Repository: dotansimha/graphql-code-generator Branch: master Commit: 2f2eb7cf1dc2 Files: 971 Total size: 5.5 MB Directory structure: gitextract_j3vhyrn3/ ├── .changeset/ │ ├── README.md │ └── config.json ├── .eslintrc.cjs ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ ├── config.yml │ │ └── feature_request.yml │ ├── PULL_REQUEST_TEMPLATE.md │ ├── labels.yml │ └── workflows/ │ ├── main.yml │ ├── pr.yml │ ├── release.yml │ ├── rust.yml │ ├── website-integrity.yml │ └── website.yml ├── .gitignore ├── .husky/ │ └── pre-commit ├── .nvmrc ├── .prettierignore ├── .vscode/ │ ├── extensions.json │ ├── launch.json │ └── settings.json ├── .yarnrc ├── LICENSE ├── README.md ├── babel.config.js ├── dev-test/ │ ├── alt-codegen.yml │ ├── apollo-android/ │ │ ├── codegen.yml │ │ └── schema.json │ ├── codegen.ts │ ├── gatsby/ │ │ ├── fragments.ts │ │ └── schema.graphql │ ├── githunt/ │ │ ├── comment-added.subscription.graphql │ │ ├── comment.query.graphql │ │ ├── comments-page-comment.fragment.graphql │ │ ├── current-user.query.graphql │ │ ├── feed-entry.fragment.graphql │ │ ├── feed.query.graphql │ │ ├── graphql-declared-modules.d.ts │ │ ├── new-entry.mutation.graphql │ │ ├── repo-info.fragment.graphql │ │ ├── schema.json │ │ ├── submit-comment.mutation.graphql │ │ ├── typed-document-nodes.ts │ │ ├── types.avoidOptionals.ts │ │ ├── types.d.ts │ │ ├── types.enumsAsTypes.ts │ │ ├── types.flatten.preResolveTypes.ts │ │ ├── types.immutableTypes.ts │ │ ├── types.onlyEnums.ts │ │ ├── types.preResolveTypes.onlyOperationTypes.ts │ │ ├── types.preResolveTypes.ts │ │ ├── types.ts │ │ ├── vote-buttons.fragment.graphql │ │ └── vote.mutation.graphql │ ├── githunt-invalid/ │ │ └── invalid.graphql │ ├── gql-tag-operations/ │ │ ├── gql/ │ │ │ ├── fragment-masking.ts │ │ │ ├── gql.ts │ │ │ ├── graphql.ts │ │ │ └── index.ts │ │ ├── graphql/ │ │ │ ├── fragment-masking.ts │ │ │ ├── gql.ts │ │ │ ├── graphql.ts │ │ │ └── index.ts │ │ ├── schema.graphql │ │ └── src/ │ │ └── index.ts │ ├── gql-tag-operations-masking/ │ │ ├── gql/ │ │ │ ├── fragment-masking.ts │ │ │ ├── gql.ts │ │ │ ├── graphql.ts │ │ │ └── index.ts │ │ ├── schema.graphql │ │ └── src/ │ │ └── index.tsx │ ├── gql-tag-operations-urql/ │ │ ├── gql/ │ │ │ ├── fragment-masking.ts │ │ │ ├── gql.d.ts │ │ │ ├── gql.ts │ │ │ ├── graphql.ts │ │ │ └── index.ts │ │ ├── schema.graphql │ │ └── src/ │ │ └── index.ts │ ├── modules/ │ │ ├── blog/ │ │ │ ├── generated.ts │ │ │ └── types/ │ │ │ └── blog.graphql │ │ ├── common/ │ │ │ ├── generated.ts │ │ │ └── types/ │ │ │ └── common.graphql │ │ ├── dotanions/ │ │ │ ├── generated.ts │ │ │ └── types/ │ │ │ └── donations.graphql │ │ ├── types.ts │ │ └── users/ │ │ ├── generated.ts │ │ └── types/ │ │ └── users.graphql │ ├── setup.js │ ├── star-wars/ │ │ ├── CreateReviewForEpisode.graphql │ │ ├── ExcludeQueryAlpha.graphql │ │ ├── ExcludeQueryBeta.graphql │ │ ├── HeroAndFriendsNames.graphql │ │ ├── HeroAppearsIn.graphql │ │ ├── HeroDetails.graphql │ │ ├── HeroDetailsFragment.graphql │ │ ├── HeroDetailsWithFragment.graphql │ │ ├── HeroName.graphql │ │ ├── HeroNameConditional.graphql │ │ ├── HeroParentTypeDependentField.graphql │ │ ├── HeroTypeDependentAliasedField.graphql │ │ ├── HumanFields.graphql │ │ ├── HumanWithNullWeight.graphql │ │ ├── TwoHeroes.graphql │ │ ├── schema.json │ │ ├── types.OnlyEnums.ts │ │ ├── types.avoidOptionals.ts │ │ ├── types.d.ts │ │ ├── types.excludeQueryAlpha.ts │ │ ├── types.excludeQueryBeta.ts │ │ ├── types.globallyAvailable.d.ts │ │ ├── types.immutableTypes.ts │ │ ├── types.preResolveTypes.onlyOperationTypes.ts │ │ ├── types.preResolveTypes.ts │ │ ├── types.skipSchema.ts │ │ └── types.ts │ ├── subpath-import/ │ │ ├── result.d.ts │ │ └── schema.graphql │ ├── test-federation/ │ │ ├── generated/ │ │ │ └── types.ts │ │ └── schema.gql │ ├── test-message/ │ │ └── schema.graphql │ ├── test-mongodb/ │ │ └── schema.graphql │ ├── test-null-value/ │ │ ├── query.ts │ │ ├── result.d.ts │ │ └── schema.graphql │ ├── test-schema/ │ │ ├── env.types.ts │ │ ├── flow-types.flow.js │ │ ├── local/ │ │ │ ├── schema-ast.js │ │ │ ├── schema-formats.js │ │ │ ├── schema-object.js │ │ │ ├── schema-text.js │ │ │ └── schema.graphql │ │ ├── resolvers-federation.ts │ │ ├── resolvers-root.ts │ │ ├── resolvers-stitching.ts │ │ ├── resolvers-types.ts │ │ ├── schema-ast.js │ │ ├── schema-federation.graphql │ │ ├── schema-formats.js │ │ ├── schema-json.js │ │ ├── schema-object.js │ │ ├── schema-text.js │ │ ├── schema-with-imports.graphql │ │ ├── schema-with-root.graphql │ │ ├── schema.graphql │ │ ├── schema.json │ │ ├── types.onlyEnums.ts │ │ ├── types.preResolveTypes.onlyOperationTypes.ts │ │ ├── types.preResolveTypes.ts │ │ ├── typings.avoidOptionals.ts │ │ ├── typings.enum.ts │ │ ├── typings.immutableTypes.ts │ │ ├── typings.ts │ │ └── typings.wrapped.ts │ └── tsconfig.json ├── dev-test-outer-dir/ │ └── githunt/ │ ├── current-user.query.graphql │ └── nothing-should-use-this-query.graphql ├── examples/ │ ├── persisted-documents/ │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── codegen.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── gql/ │ │ │ │ ├── fragment-masking.ts │ │ │ │ ├── gql.ts │ │ │ │ ├── graphql.ts │ │ │ │ ├── index.ts │ │ │ │ └── persisted-documents.json │ │ │ ├── main.ts │ │ │ ├── yoga.spec.ts │ │ │ └── yoga.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── persisted-documents-string-mode/ │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── codegen.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── gql/ │ │ │ │ ├── fragment-masking.ts │ │ │ │ ├── gql.ts │ │ │ │ ├── graphql.ts │ │ │ │ ├── index.ts │ │ │ │ └── persisted-documents.json │ │ │ ├── main.ts │ │ │ ├── yoga.spec.ts │ │ │ └── yoga.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── programmatic-typescript/ │ │ ├── package.json │ │ ├── src/ │ │ │ ├── gql.generated.ts │ │ │ ├── graphql/ │ │ │ │ └── hello.gql │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ ├── react/ │ │ ├── apollo-client/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── codegen.ts │ │ │ ├── cypress/ │ │ │ │ ├── e2e/ │ │ │ │ │ └── end2end.cy.ts │ │ │ │ └── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ ├── cypress.config.ts │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.css │ │ │ │ ├── App.tsx │ │ │ │ ├── Film.tsx │ │ │ │ ├── gql/ │ │ │ │ │ ├── fragment-masking.ts │ │ │ │ │ ├── gql.ts │ │ │ │ │ ├── graphql.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── main.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── apollo-client-defer/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── codegen.ts │ │ │ ├── cypress/ │ │ │ │ ├── e2e/ │ │ │ │ │ └── end2end.cy.ts │ │ │ │ └── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ ├── cypress.config.ts │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.tsx │ │ │ │ ├── gql/ │ │ │ │ │ ├── fragment-masking.ts │ │ │ │ │ ├── gql.ts │ │ │ │ │ ├── graphql.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── main.tsx │ │ │ │ └── yoga.mjs │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── apollo-client-swc-plugin/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── codegen.ts │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.css │ │ │ │ ├── App.tsx │ │ │ │ ├── Film.tsx │ │ │ │ ├── gql/ │ │ │ │ │ ├── fragment-masking.ts │ │ │ │ │ ├── gql.ts │ │ │ │ │ ├── graphql.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── main.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.mts │ │ ├── http-executor/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── codegen.ts │ │ │ ├── cypress/ │ │ │ │ ├── e2e/ │ │ │ │ │ └── end2end.cy.ts │ │ │ │ └── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ ├── cypress.config.ts │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.css │ │ │ │ ├── App.tsx │ │ │ │ ├── Film.tsx │ │ │ │ ├── gql/ │ │ │ │ │ ├── fragment-masking.ts │ │ │ │ │ ├── gql.ts │ │ │ │ │ ├── graphql.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── main.css │ │ │ │ └── main.tsx │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── nextjs-swr/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── codegen.ts │ │ │ ├── components/ │ │ │ │ └── Film.tsx │ │ │ ├── cypress/ │ │ │ │ ├── e2e/ │ │ │ │ │ └── end2end.cy.ts │ │ │ │ └── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ ├── cypress.config.ts │ │ │ ├── gql/ │ │ │ │ ├── fragment-masking.ts │ │ │ │ ├── gql.ts │ │ │ │ ├── graphql.ts │ │ │ │ └── index.ts │ │ │ ├── hooks/ │ │ │ │ └── use-query.ts │ │ │ ├── next.config.js │ │ │ ├── package.json │ │ │ ├── pages/ │ │ │ │ ├── _app.tsx │ │ │ │ ├── api/ │ │ │ │ │ └── hello.ts │ │ │ │ └── index.tsx │ │ │ ├── styles/ │ │ │ │ ├── Home.module.css │ │ │ │ └── globals.css │ │ │ └── tsconfig.json │ │ ├── tanstack-react-query/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── codegen.ts │ │ │ ├── cypress/ │ │ │ │ ├── e2e/ │ │ │ │ │ └── end2end.cy.ts │ │ │ │ └── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ ├── cypress.config.ts │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.css │ │ │ │ ├── App.tsx │ │ │ │ ├── Film.tsx │ │ │ │ ├── gql/ │ │ │ │ │ ├── fragment-masking.ts │ │ │ │ │ ├── gql.ts │ │ │ │ │ ├── graphql.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── main.css │ │ │ │ ├── main.tsx │ │ │ │ └── use-graphql.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ └── urql/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── codegen.ts │ │ ├── cypress/ │ │ │ ├── e2e/ │ │ │ │ └── end2end.cy.ts │ │ │ └── support/ │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ │ ├── cypress.config.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── Film.tsx │ │ │ ├── gql/ │ │ │ │ ├── fragment-masking.ts │ │ │ │ ├── gql.ts │ │ │ │ ├── graphql.ts │ │ │ │ └── index.ts │ │ │ ├── main.css │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── typescript-esm/ │ │ ├── README.md │ │ ├── codegen.cjs │ │ ├── package.json │ │ ├── src/ │ │ │ ├── executeOperation.ts │ │ │ ├── gql/ │ │ │ │ ├── fragment-masking.ts │ │ │ │ ├── gql.ts │ │ │ │ ├── graphql.ts │ │ │ │ └── index.ts │ │ │ └── main.ts │ │ └── tsconfig.json │ ├── typescript-graphql-request/ │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── codegen.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── gql/ │ │ │ │ ├── fragment-masking.ts │ │ │ │ ├── gql.ts │ │ │ │ ├── graphql.ts │ │ │ │ └── index.ts │ │ │ ├── main.spec.ts │ │ │ └── main.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── typescript-resolvers/ │ │ ├── README.md │ │ ├── codegen.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── main.ts │ │ │ └── type-defs.d.ts │ │ └── tsconfig.json │ ├── vite/ │ │ ├── vite-react-cts/ │ │ │ ├── .gitignore │ │ │ ├── codegen.cts │ │ │ ├── cypress/ │ │ │ │ ├── e2e/ │ │ │ │ │ └── end2end.cy.ts │ │ │ │ └── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ ├── cypress.config.ts │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── Film.tsx │ │ │ │ ├── gql/ │ │ │ │ │ ├── fragment-masking.ts │ │ │ │ │ ├── gql.ts │ │ │ │ │ ├── graphql.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── main.tsx │ │ │ │ └── vite-env.d.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── vite-react-mts/ │ │ │ ├── .gitignore │ │ │ ├── codegen.mts │ │ │ ├── cypress/ │ │ │ │ ├── e2e/ │ │ │ │ │ └── end2end.cy.ts │ │ │ │ └── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ ├── cypress.config.ts │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── Film.tsx │ │ │ │ ├── gql/ │ │ │ │ │ ├── fragment-masking.ts │ │ │ │ │ ├── gql.ts │ │ │ │ │ ├── graphql.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── main.tsx │ │ │ │ └── vite-env.d.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ └── vite-react-ts/ │ │ ├── .gitignore │ │ ├── codegen.ts │ │ ├── cypress/ │ │ │ ├── e2e/ │ │ │ │ └── end2end.cy.ts │ │ │ └── support/ │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ │ ├── cypress.config.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── Film.tsx │ │ │ ├── gql/ │ │ │ │ ├── fragment-masking.ts │ │ │ │ ├── gql.ts │ │ │ │ ├── graphql.ts │ │ │ │ └── index.ts │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── vue/ │ │ ├── apollo-composable/ │ │ │ ├── .gitignore │ │ │ ├── .vscode/ │ │ │ │ └── extensions.json │ │ │ ├── README.md │ │ │ ├── codegen.ts │ │ │ ├── cypress/ │ │ │ │ ├── e2e/ │ │ │ │ │ └── end2end.cy.ts │ │ │ │ └── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ ├── cypress.config.ts │ │ │ ├── env.d.ts │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.vue │ │ │ │ ├── assets/ │ │ │ │ │ ├── base.css │ │ │ │ │ └── main.css │ │ │ │ ├── components/ │ │ │ │ │ └── FilmItem.vue │ │ │ │ ├── gql/ │ │ │ │ │ ├── fragment-masking.ts │ │ │ │ │ ├── gql.ts │ │ │ │ │ ├── graphql.ts │ │ │ │ │ └── index.ts │ │ │ │ └── main.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── urql/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── codegen.ts │ │ │ ├── cypress/ │ │ │ │ ├── e2e/ │ │ │ │ │ └── end2end.cy.ts │ │ │ │ └── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ ├── cypress.config.ts │ │ │ ├── env.d.ts │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.vue │ │ │ │ ├── assets/ │ │ │ │ │ ├── base.css │ │ │ │ │ └── main.css │ │ │ │ ├── components/ │ │ │ │ │ └── FilmItem.vue │ │ │ │ ├── gql/ │ │ │ │ │ ├── fragment-masking.ts │ │ │ │ │ ├── gql.ts │ │ │ │ │ ├── graphql.ts │ │ │ │ │ └── index.ts │ │ │ │ └── main.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ └── villus/ │ │ ├── .gitignore │ │ ├── .vscode/ │ │ │ └── extensions.json │ │ ├── README.md │ │ ├── codegen.ts │ │ ├── cypress/ │ │ │ ├── e2e/ │ │ │ │ └── end2end.cy.ts │ │ │ └── support/ │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ │ ├── cypress.config.ts │ │ ├── env.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── assets/ │ │ │ │ ├── base.css │ │ │ │ └── main.css │ │ │ ├── components/ │ │ │ │ └── FilmItem.vue │ │ │ ├── gql/ │ │ │ │ ├── fragment-masking.ts │ │ │ │ ├── gql.ts │ │ │ │ ├── graphql.ts │ │ │ │ └── index.ts │ │ │ └── main.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ └── yoga-tests/ │ ├── README.md │ ├── babel.config.js │ ├── codegen.ts │ ├── package.json │ ├── src/ │ │ ├── gql/ │ │ │ ├── fragment-masking.ts │ │ │ ├── gql.ts │ │ │ ├── graphql.ts │ │ │ └── index.ts │ │ ├── main.ts │ │ ├── yoga.spec.ts │ │ └── yoga.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── package.json ├── packages/ │ ├── graphql-cli-codegen-plugin/ │ │ └── README.md │ ├── graphql-codegen-cli/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── bin.ts │ │ │ ├── cli.ts │ │ │ ├── codegen.ts │ │ │ ├── config.ts │ │ │ ├── declarations.d.ts │ │ │ ├── documentTransforms.ts │ │ │ ├── generate-and-save.ts │ │ │ ├── graphql-config.ts │ │ │ ├── hooks.ts │ │ │ ├── index.ts │ │ │ ├── init/ │ │ │ │ ├── helpers.ts │ │ │ │ ├── index.ts │ │ │ │ ├── plugins.ts │ │ │ │ ├── questions.ts │ │ │ │ ├── targets.ts │ │ │ │ └── types.ts │ │ │ ├── load.ts │ │ │ ├── plugins.ts │ │ │ ├── presets.ts │ │ │ └── utils/ │ │ │ ├── abort-controller-polyfill.ts │ │ │ ├── cli-error.ts │ │ │ ├── debugging.ts │ │ │ ├── file-system.ts │ │ │ ├── get-latest-version.ts │ │ │ ├── helpers.ts │ │ │ ├── logger.ts │ │ │ ├── patterns.ts │ │ │ └── watcher.ts │ │ ├── tests/ │ │ │ ├── __mocks__/ │ │ │ │ ├── fs.cjs │ │ │ │ └── some-fetch.cjs │ │ │ ├── __snapshots__/ │ │ │ │ └── init.spec.ts.snap │ │ │ ├── cli-error.spec.ts │ │ │ ├── cli-flags.spec.ts │ │ │ ├── codegen.spec.ts │ │ │ ├── config.spec.ts │ │ │ ├── custom-document-transforms/ │ │ │ │ ├── document-transform.js │ │ │ │ └── test-config.js │ │ │ ├── custom-loaders/ │ │ │ │ ├── custom-documents-loader.cjs │ │ │ │ ├── custom-schema-loader-with-context.cjs │ │ │ │ ├── custom-schema-loader.cjs │ │ │ │ ├── invalid-export.cjs │ │ │ │ ├── invalid-return-value-documents-loader.cjs │ │ │ │ └── invalid-return-value-schema-loader.cjs │ │ │ ├── custom-plugins/ │ │ │ │ ├── basic.js │ │ │ │ ├── checks-extended-schema.js │ │ │ │ ├── context.js │ │ │ │ ├── document-transform-context.js │ │ │ │ ├── extends-schema-fn.js │ │ │ │ ├── extends-schema.js │ │ │ │ ├── invalid.js │ │ │ │ └── validation.js │ │ │ ├── dummy-require.js │ │ │ ├── generate-and-save.spec.ts │ │ │ ├── init.spec.ts │ │ │ ├── test-documents/ │ │ │ │ ├── additional-schema.graphql │ │ │ │ ├── gatsby-and-custom-parsers.ts │ │ │ │ ├── invalid-directive.graphql │ │ │ │ ├── invalid-fields.graphql │ │ │ │ ├── invalid-schema.graphql │ │ │ │ ├── js-my-fragment.js │ │ │ │ ├── js-query-with-my-fragment.js │ │ │ │ ├── my-fragment.ts │ │ │ │ ├── query-with-commented-fragment.ts │ │ │ │ ├── query-with-my-fragment.ts │ │ │ │ ├── schema.graphql │ │ │ │ ├── test-schema.graphql │ │ │ │ ├── ts-features-with-query.ts │ │ │ │ ├── unused-variable.graphql │ │ │ │ └── valid.graphql │ │ │ ├── test-files/ │ │ │ │ ├── 1.ts │ │ │ │ ├── 10.tsx │ │ │ │ ├── 11.ts │ │ │ │ ├── 12.tsx │ │ │ │ ├── 13.tsx │ │ │ │ ├── 14.js │ │ │ │ ├── 15.js │ │ │ │ ├── 16.ts │ │ │ │ ├── 2.ts │ │ │ │ ├── 3.graphql │ │ │ │ ├── 4.ts │ │ │ │ ├── 5.tsx │ │ │ │ ├── 6.ts │ │ │ │ ├── 7.ts │ │ │ │ ├── 8.ts │ │ │ │ ├── 9.ts │ │ │ │ ├── ByteOrderMask.json │ │ │ │ ├── error-document.graphql │ │ │ │ ├── graphql.config.js │ │ │ │ ├── graphql.config.no-doc-ignored.js │ │ │ │ ├── graphql.config.no-doc.js │ │ │ │ └── schema-dir/ │ │ │ │ ├── error-schema.graphql │ │ │ │ ├── gatsby-and-custom-parsers/ │ │ │ │ │ ├── apollo-server.ts │ │ │ │ │ ├── custom.ts │ │ │ │ │ ├── gatsby.ts │ │ │ │ │ └── graphql-tag.ts │ │ │ │ ├── query.graphql │ │ │ │ ├── schema-object.cjs │ │ │ │ ├── schema.ts │ │ │ │ ├── user.graphql │ │ │ │ └── with-extend.js │ │ │ ├── utils.ts │ │ │ ├── watcher-test-helpers/ │ │ │ │ ├── assert-watcher-build-triggers.ts │ │ │ │ └── format-watcher-assertion-errors.ts │ │ │ ├── watcher.patterns.spec.ts │ │ │ └── watcher.run.spec.ts │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ ├── graphql-codegen-core/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── codegen.ts │ │ │ ├── execute-plugin.ts │ │ │ ├── index.ts │ │ │ ├── transform-document.ts │ │ │ └── utils.ts │ │ ├── tests/ │ │ │ └── prepend.spec.ts │ │ └── vitest.config.ts │ ├── plugins/ │ │ ├── other/ │ │ │ ├── add/ │ │ │ │ ├── CHANGELOG.md │ │ │ │ ├── package.json │ │ │ │ ├── src/ │ │ │ │ │ ├── config.ts │ │ │ │ │ └── index.ts │ │ │ │ └── vitest.config.ts │ │ │ ├── fragment-matcher/ │ │ │ │ ├── CHANGELOG.md │ │ │ │ ├── package.json │ │ │ │ ├── src/ │ │ │ │ │ └── index.ts │ │ │ │ ├── tests/ │ │ │ │ │ └── plugin.spec.ts │ │ │ │ └── vitest.config.ts │ │ │ ├── introspection/ │ │ │ │ ├── CHANGELOG.md │ │ │ │ ├── package.json │ │ │ │ ├── src/ │ │ │ │ │ └── index.ts │ │ │ │ ├── tests/ │ │ │ │ │ └── introspection.spec.ts │ │ │ │ └── vitest.config.ts │ │ │ ├── schema-ast/ │ │ │ │ ├── CHANGELOG.md │ │ │ │ ├── package.json │ │ │ │ ├── src/ │ │ │ │ │ └── index.ts │ │ │ │ ├── tests/ │ │ │ │ │ └── schema-ast.spec.ts │ │ │ │ └── vitest.config.ts │ │ │ ├── time/ │ │ │ │ ├── CHANGELOG.md │ │ │ │ ├── package.json │ │ │ │ ├── src/ │ │ │ │ │ ├── config.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── tests/ │ │ │ │ │ └── time.spec.ts │ │ │ │ └── vitest.config.ts │ │ │ └── visitor-plugin-common/ │ │ │ ├── CHANGELOG.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── avoid-optionals.ts │ │ │ │ ├── base-documents-visitor.ts │ │ │ │ ├── base-resolvers-visitor.ts │ │ │ │ ├── base-types-visitor.ts │ │ │ │ ├── base-visitor.ts │ │ │ │ ├── client-side-base-visitor.ts │ │ │ │ ├── declaration-kinds.ts │ │ │ │ ├── enum-values.ts │ │ │ │ ├── imports.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mappers.ts │ │ │ │ ├── naming.ts │ │ │ │ ├── optimize-operations.ts │ │ │ │ ├── scalars.ts │ │ │ │ ├── selection-set-processor/ │ │ │ │ │ ├── base.ts │ │ │ │ │ └── pre-resolve-types.ts │ │ │ │ ├── selection-set-to-object.ts │ │ │ │ ├── types.ts │ │ │ │ ├── utils.ts │ │ │ │ └── variables-to-object.ts │ │ │ ├── tests/ │ │ │ │ ├── client-side-base-visitor.spec.ts │ │ │ │ ├── create-resolvers-fields.spec.ts │ │ │ │ ├── enum-values.spec.ts │ │ │ │ ├── parse-mapper.spec.ts │ │ │ │ ├── plugins-common.spec.ts │ │ │ │ └── utils.spec.ts │ │ │ └── vitest.config.ts │ │ └── typescript/ │ │ ├── document-nodes/ │ │ │ ├── CHANGELOG.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── index.ts │ │ │ │ └── visitor.ts │ │ │ ├── tests/ │ │ │ │ └── graphql-document-nodes.spec.ts │ │ │ └── vitest.config.ts │ │ ├── gql-tag-operations/ │ │ │ ├── CHANGELOG.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ └── index.ts │ │ │ └── vitest.config.ts │ │ ├── operations/ │ │ │ ├── CHANGELOG.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── config.ts │ │ │ │ ├── index.ts │ │ │ │ ├── ts-operation-variables-to-object.ts │ │ │ │ ├── ts-selection-set-processor.ts │ │ │ │ └── visitor.ts │ │ │ ├── tests/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── ts-documents.spec.ts.snap │ │ │ │ ├── extract-all-types.spec.ts │ │ │ │ ├── shared/ │ │ │ │ │ └── schema.ts │ │ │ │ ├── ts-documents.apolloUnmask.spec.ts │ │ │ │ ├── ts-documents.nullability.spec.ts │ │ │ │ └── ts-documents.spec.ts │ │ │ └── vitest.config.ts │ │ ├── resolvers/ │ │ │ ├── CHANGELOG.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── config.ts │ │ │ │ ├── index.ts │ │ │ │ └── visitor.ts │ │ │ ├── tests/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── ts-resolvers.spec.ts.snap │ │ │ │ ├── ts-resolvers.config.avoidOptionals.spec.ts │ │ │ │ ├── ts-resolvers.config.customDirectives.spec.ts │ │ │ │ ├── ts-resolvers.config.resolversNonOptionalTypename.spec.ts │ │ │ │ ├── ts-resolvers.federation.interface.spec.ts │ │ │ │ ├── ts-resolvers.federation.mappers.spec.ts │ │ │ │ ├── ts-resolvers.federation.spec.ts │ │ │ │ ├── ts-resolvers.interface.spec.ts │ │ │ │ ├── ts-resolvers.mapping.spec.ts │ │ │ │ ├── ts-resolvers.meta.spec.ts │ │ │ │ ├── ts-resolvers.spec.ts │ │ │ │ ├── ts-resolvers.union.spec.ts │ │ │ │ └── utils.ts │ │ │ └── vitest.config.ts │ │ ├── typed-document-node/ │ │ │ ├── CHANGELOG.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── config.ts │ │ │ │ ├── index.ts │ │ │ │ └── visitor.ts │ │ │ ├── tests/ │ │ │ │ └── typed-document-node.spec.ts │ │ │ └── vitest.config.ts │ │ └── typescript/ │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── config.ts │ │ │ ├── index.ts │ │ │ ├── introspection-visitor.ts │ │ │ ├── typescript-variables-to-object.ts │ │ │ └── visitor.ts │ │ ├── tests/ │ │ │ ├── __snapshots__/ │ │ │ │ └── typescript.spec.ts.snap │ │ │ └── typescript.spec.ts │ │ └── vitest.config.ts │ ├── presets/ │ │ ├── client/ │ │ │ ├── CHANGELOG.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── add-typename-selection-document-transform.ts │ │ │ │ ├── babel.ts │ │ │ │ ├── fragment-masking-plugin.ts │ │ │ │ ├── index.ts │ │ │ │ ├── persisted-documents.spec.ts │ │ │ │ ├── persisted-documents.ts │ │ │ │ └── process-sources.ts │ │ │ ├── tests/ │ │ │ │ ├── babel.spec.ts │ │ │ │ ├── client-preset.nullability.spec.ts │ │ │ │ ├── client-preset.spec.ts │ │ │ │ └── fixtures/ │ │ │ │ ├── crlf-operation.ts │ │ │ │ ├── duplicate-operation.ts │ │ │ │ ├── enum.ts │ │ │ │ ├── reused-fragment.ts │ │ │ │ ├── simple-lowercase-operation-name.ts │ │ │ │ ├── simple-uppercase-operation-name.ts │ │ │ │ ├── subscription-root-node.ts │ │ │ │ ├── union-fragment.ts │ │ │ │ ├── with-deferred-fragment.ts │ │ │ │ ├── with-enum-values.ts │ │ │ │ ├── with-fragment.ts │ │ │ │ └── with-nested-fragment.ts │ │ │ └── vitest.config.ts │ │ ├── graphql-modules/ │ │ │ ├── CHANGELOG.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── builder.ts │ │ │ │ ├── config.ts │ │ │ │ ├── index.ts │ │ │ │ └── utils.ts │ │ │ ├── tests/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ ├── builder.spec.ts.snap │ │ │ │ │ └── integration.spec.ts.snap │ │ │ │ ├── builder.spec.ts │ │ │ │ ├── integration.spec.ts │ │ │ │ └── test-files/ │ │ │ │ └── modules/ │ │ │ │ ├── blog/ │ │ │ │ │ └── types/ │ │ │ │ │ └── blog.graphql │ │ │ │ ├── common/ │ │ │ │ │ └── types/ │ │ │ │ │ └── common.graphql │ │ │ │ ├── dotanions/ │ │ │ │ │ └── types/ │ │ │ │ │ └── donations.graphql │ │ │ │ └── users/ │ │ │ │ └── types/ │ │ │ │ ├── ext_user.graphql │ │ │ │ └── users.graphql │ │ │ ├── vitest.config.ts │ │ │ └── vitest.setup.ts │ │ └── swc-plugin/ │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── lib.rs │ │ │ └── tests.rs │ │ └── tests/ │ │ └── fixtures/ │ │ ├── simple-uppercase-operation-name.js │ │ ├── simple-uppercase-operation-name.other-dir.js │ │ └── simple-uppercase-operation-name.ts │ └── utils/ │ ├── graphql-codegen-testing/ │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ ├── mock-graphql-server.ts │ │ │ ├── resolvers-common.ts │ │ │ └── typescript.ts │ │ └── vitest.config.ts │ └── plugins-helpers/ │ ├── CHANGELOG.md │ ├── package.json │ ├── src/ │ │ ├── federation.ts │ │ ├── getCachedDocumentNodeFromSchema.ts │ │ ├── helpers.ts │ │ ├── index.ts │ │ ├── oldVisit.ts │ │ ├── profiler.ts │ │ ├── resolve-external-module-and-fn.ts │ │ ├── types.ts │ │ ├── typings.d.ts │ │ └── utils.ts │ ├── tests/ │ │ ├── fixtures/ │ │ │ └── externalModuleFn.js │ │ ├── is-using-types.spec.ts │ │ └── resolve-external-module-and-fn.spec.ts │ └── vitest.config.ts ├── patches/ │ └── typescript-json-schema+0.56.0.patch ├── prettier.config.cjs ├── renovate.json ├── scripts/ │ ├── fix-bin.js │ ├── match-graphql.js │ └── print-example-ci-command.js ├── tsconfig.json ├── tsconfig.spec.json ├── vitest.config.ts └── website/ ├── .gitignore ├── README.md ├── next-env.d.ts ├── next-sitemap.config.js ├── next.config.js ├── package.json ├── postcss.config.mjs ├── public/ │ └── config.schema.json ├── route-lockfile.txt ├── scripts/ │ ├── generate-config-json-schema.ts │ ├── generate-packages-info.ts │ └── sitemap-ci.mjs ├── src/ │ ├── category-to-packages.mjs │ ├── components/ │ │ ├── dev-ex-cards.tsx │ │ ├── hero/ │ │ │ └── index.tsx │ │ ├── index-page.tsx │ │ ├── java-installation.mdx │ │ ├── live-demo/ │ │ │ ├── Editor.tsx │ │ │ ├── LiveDemo.tsx │ │ │ ├── LiveDemoEditors.tsx │ │ │ ├── examples.ts │ │ │ ├── formatter.ts │ │ │ ├── generate.ts │ │ │ ├── plugins.ts │ │ │ └── utils.ts │ │ ├── page.tsx │ │ ├── plugin.tsx │ │ └── plugins-marketplace-search.tsx │ ├── lib/ │ │ ├── docs-generator.ts │ │ ├── plugin-get-static-props.ts │ │ ├── plugins/ │ │ │ ├── index.ts │ │ │ └── packages.ts │ │ ├── plugins-docs.ts │ │ └── transform.ts │ ├── pages/ │ │ ├── _app.tsx │ │ ├── _meta.ts │ │ ├── docs/ │ │ │ ├── _meta.ts │ │ │ ├── advanced/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── document-transform.mdx │ │ │ │ ├── generated-files-colocation.mdx │ │ │ │ ├── how-does-it-work.mdx │ │ │ │ ├── profiler.mdx │ │ │ │ └── programmatic-usage.mdx │ │ │ ├── config-reference/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── codegen-config.mdx │ │ │ │ ├── config-field.mdx │ │ │ │ ├── documents-field.mdx │ │ │ │ ├── lifecycle-hooks.mdx │ │ │ │ ├── multiproject-config.mdx │ │ │ │ ├── naming-convention.mdx │ │ │ │ ├── require-field.mdx │ │ │ │ └── schema-field.mdx │ │ │ ├── custom-codegen/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── contributing.mdx │ │ │ │ ├── extend-schema.mdx │ │ │ │ ├── index.mdx │ │ │ │ ├── plugin-structure.mdx │ │ │ │ ├── using-visitor.mdx │ │ │ │ └── validate-configuration.mdx │ │ │ ├── getting-started/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── development-workflow.mdx │ │ │ │ ├── esm-typescript-usage.mdx │ │ │ │ ├── index.mdx │ │ │ │ └── installation.mdx │ │ │ ├── guides/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── angular.mdx │ │ │ │ ├── api-testing.mdx │ │ │ │ ├── flutter-freezed.mdx │ │ │ │ ├── further-reading.mdx │ │ │ │ ├── graphql-modules.mdx │ │ │ │ ├── graphql-server-apollo-yoga-with-server-preset.mdx │ │ │ │ ├── graphql-server-apollo-yoga.mdx │ │ │ │ ├── react-query.mdx │ │ │ │ ├── react-vue.mdx │ │ │ │ ├── svelte.mdx │ │ │ │ └── vanilla-typescript.mdx │ │ │ ├── integrations/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── apollo-local-state.mdx │ │ │ │ ├── create-react-app.mdx │ │ │ │ ├── federation.mdx │ │ │ │ ├── gatsby.mdx │ │ │ │ ├── prettier.mdx │ │ │ │ └── vscode.mdx │ │ │ └── migration/ │ │ │ ├── _meta.ts │ │ │ ├── apollo-tooling.mdx │ │ │ ├── from-0-13.mdx │ │ │ ├── from-0-18.mdx │ │ │ ├── from-4-0.mdx │ │ │ ├── graphql-cli.mdx │ │ │ └── operations-and-client-preset-from-5-0.mdx │ │ ├── index.mdx │ │ ├── plugins/ │ │ │ ├── _meta.ts │ │ │ ├── c-sharp/ │ │ │ │ ├── _meta.ts │ │ │ │ └── c-sharp-operations.mdx │ │ │ ├── dart/ │ │ │ │ └── flutter-freezed.mdx │ │ │ ├── flow/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── flow-operations.mdx │ │ │ │ └── flow-resolvers.mdx │ │ │ ├── java/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── java-apollo-android.mdx │ │ │ │ ├── java-resolvers.mdx │ │ │ │ ├── java.mdx │ │ │ │ └── kotlin.mdx │ │ │ ├── other/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── add.mdx │ │ │ │ ├── fragment-matcher.mdx │ │ │ │ ├── hasura-allow-list.mdx │ │ │ │ ├── introspection.mdx │ │ │ │ ├── jsdoc.mdx │ │ │ │ ├── reason-client.mdx │ │ │ │ ├── schema-ast.mdx │ │ │ │ ├── time.mdx │ │ │ │ └── urql-introspection.mdx │ │ │ ├── presets/ │ │ │ │ ├── _meta.ts │ │ │ │ ├── graphql-modules-preset.mdx │ │ │ │ ├── import-types-preset.mdx │ │ │ │ ├── near-operation-file-preset.mdx │ │ │ │ └── preset-client.mdx │ │ │ └── typescript/ │ │ │ ├── _meta.ts │ │ │ ├── named-operations-object.mdx │ │ │ ├── relay-operation-optimizer.mdx │ │ │ ├── typed-document-node.mdx │ │ │ ├── typescript-apollo-angular.mdx │ │ │ ├── typescript-apollo-client-helpers.mdx │ │ │ ├── typescript-apollo-next.mdx │ │ │ ├── typescript-document-nodes.mdx │ │ │ ├── typescript-fabbrica.mdx │ │ │ ├── typescript-generic-sdk.mdx │ │ │ ├── typescript-graphql-files-modules.mdx │ │ │ ├── typescript-graphql-request.mdx │ │ │ ├── typescript-mock-data.mdx │ │ │ ├── typescript-mongodb.mdx │ │ │ ├── typescript-msw.mdx │ │ │ ├── typescript-nhost.mdx │ │ │ ├── typescript-oclif.mdx │ │ │ ├── typescript-operations.mdx │ │ │ ├── typescript-react-apollo.mdx │ │ │ ├── typescript-react-query.mdx │ │ │ ├── typescript-resolvers.mdx │ │ │ ├── typescript-rtk-query.mdx │ │ │ ├── typescript-stencil-apollo.mdx │ │ │ ├── typescript-svelte-apollo.mdx │ │ │ ├── typescript-type-graphql.mdx │ │ │ ├── typescript-urql.mdx │ │ │ ├── typescript-validation-schema.mdx │ │ │ ├── typescript-vue-apollo-smart-ops.mdx │ │ │ ├── typescript-vue-apollo.mdx │ │ │ ├── typescript-vue-urql.mdx │ │ │ └── typescript.mdx │ │ └── plugins.mdx │ └── selection-styles.css ├── tailwind.config.ts ├── theme.config.tsx └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .changeset/README.md ================================================ # Changesets Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets) We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md) ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config@2.1.0/schema.json", "commit": false, "linked": [], "access": "restricted", "baseBranch": "master", "updateInternalDependencies": "patch", "ignore": [ "website", "example-*", "@graphql-codegen/client-preset-swc-plugin", "example-apollo-client-swc-plugin", "example-react-nextjs-swr" ], "changelog": [ "@changesets/changelog-github", { "repo": "dotansimha/graphql-code-generator" } ], "snapshot": { "useCalculatedVersion": true, "prereleaseTemplate": "{tag}-{datetime}-{commit}" } } ================================================ FILE: .eslintrc.cjs ================================================ module.exports = { root: true, extends: ['@theguild', 'plugin:tailwindcss/recommended'], rules: { 'no-empty': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-use-before-define': 'off', '@typescript-eslint/no-namespace': 'off', '@typescript-eslint/no-empty-interface': 'off', '@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/ban-ts-ignore': 'off', '@typescript-eslint/ban-types': 'off', 'import/no-extraneous-dependencies': 'error', // todo: enable 'unicorn/filename-case': 'off', 'import/extensions': 'off', 'import/no-default-export': 'off', // todo: enable in v3 'unicorn/prefer-node-protocol': 'off', 'prefer-object-has-own': 'off', }, env: { node: true, }, overrides: [ { files: ['website/**'], extends: '@theguild/eslint-config/react', }, { files: [ '*.spec.ts', '**/tests/**/*.{js,ts,tsx,cjs}', '**/graphql-codegen-testing/**/*.ts', '**/vitest.config.ts', '**/vitest.setup.ts', '**/__mocks__/*', ], rules: { 'import/no-extraneous-dependencies': 'off', '@typescript-eslint/no-require-imports': 'off', }, }, { files: '**/tests/fixtures/*.{ts,js}', rules: { '@typescript-eslint/no-unused-vars': 'off', }, }, { files: ['packages/**/*.{,c,m}ts{,x}'], parserOptions: { project: ['./tsconfig.json'], }, }, { files: ['scripts/*.{ts,js}', 'prettier.config.cjs'], rules: { '@typescript-eslint/no-require-imports': 'off', }, }, ], ignorePatterns: [ 'dev-test', 'website', 'examples/**', '**/tests/test-files/**', '**/tests/test-documents/**', '**/react-app-env.d.ts', 'packages/presets/swc-plugin/tests/fixtures/simple-uppercase-operation-name.js', 'packages/presets/swc-plugin/tests/fixtures/simple-uppercase-operation-name.other-dir.js', '**/build/**/*', '**/dist/**/*', ], }; ================================================ FILE: .gitattributes ================================================ # This fixture must contain CRLF as line breaks. See https://github.com/dotansimha/graphql-code-generator/issues/7362 packages/presets/gql-tag-operations/tests/fixtures/crlf-operation.ts eol=crlf ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.yml ================================================ name: '🐛 Bug report' description: Create a report to help us improve body: - type: markdown attributes: value: | Thank you for reporting an issue :pray:. ## Is it related to a community plugin? All request linked to a "Community plugin" (as defined below) should [be addressed on the `dotansimha/graphql-code-generator-community` repository](https://github.com/dotansimha/graphql-code-generator-community/issues/new?assignees=&labels=&template=bug_report.yml).
Community plugins: - `@graphql-codegen/typescript-react-apollo` - `@graphql-codegen/typescript-graphql-request` - `@graphql-codegen/typescript-apollo-angular` - `@graphql-codegen/typescript-apollo-client-helpers` - `@graphql-codegen/typescript-react-query` - `@graphql-codegen/typescript-urql` - `@graphql-codegen/named-operations-object` - `@graphql-codegen/urql-introspection` - `@graphql-codegen/flow-resolvers` - `@graphql-codegen/typescript-vue-apollo` - `@graphql-codegen/typescript-rtk-query` - `@graphql-codegen/flow-operations` - `@graphql-codegen/typescript-msw` - `@graphql-codegen/typescript-mongodb` - `@graphql-codegen/typescript-type-graphql` - `@graphql-codegen/jsdoc` - `@graphql-codegen/typescript-vue-urql` - `@graphql-codegen/kotlin` - `@graphql-codegen/typescript-vue-apollo-smart-ops` - `@graphql-codegen/java` - `@graphql-codegen/c-sharp-operations` - `@graphql-codegen/hasura-allow-list` - `@graphql-codegen/typescript-stencil-apollo` - `@graphql-codegen/relay-operation-optimizer` - `@graphql-codegen/typescript-oclif` - `@graphql-codegen/java-resolvers` - `@graphql-codegen/java-apollo-android`
--- - type: dropdown id: packages attributes: label: Which packages are impacted by your issue? multiple: true options: - '@graphql-codegen/cli' - '@graphql-codegen/core' - '@graphql-codegen/add' - '@graphql-codegen/fragment-matcher' - '@graphql-codegen/introspection' - '@graphql-codegen/schema-ast' - '@graphql-codegen/time' - '@graphql-codegen/visitor-plugin-common' - '@graphql-codegen/typescript-document-nodes' - '@graphql-codegen/gql-tag-operations' - '@graphql-codegen/typescript-operations' - '@graphql-codegen/typescript-resolvers' - '@graphql-codegen/typescript-rtk-query' - '@graphql-codegen/typed-document-node' - '@graphql-codegen/typescript' - '@graphql-codegen/client-preset' - '@graphql-codegen/graphql-modules-preset' - '@graphql-codegen/testing' - '@graphql-codegen/plugin-helpers' validations: required: false - type: markdown attributes: value: | The issues on this repo are being tracked and monitored according to our [Contributor Workflow](https://github.com/the-guild-org/Stack/blob/master/CONTRIBUTING.md#a-typical-contributor-workflow), Before submitting a new bug/issue, please check the [Contributor Workflow](https://github.com/the-guild-org/Stack/blob/master/CONTRIBUTING.md#a-typical-contributor-workflow) After reading the [Contributor Workflow](https://github.com/the-guild-org/Stack/blob/master/CONTRIBUTING.md#a-typical-contributor-workflow), Check out and update the current state of this issue: - [ ] 1. The issue provides a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) available on [GitHub](https://github.com/dotansimha/graphql-code-generator-issue-sandbox-template), [Stackblitz](https://stackblitz.com/github/dotansimha/graphql-code-generator-issue-sandbox-template) or [CodeSandbox](https://codesandbox.io/s/github/dotansimha/graphql-code-generator-issue-sandbox-template). - _Make sure to fork this template and run `yarn generate` in the terminal._ - _Please make sure the Codegen and plugins version under `package.json` matches yours._ - [ ] 2. A failing test has been provided - [ ] 3. A local solution has been provided - [ ] 4. A pull request is pending review The more information you fill in, the better the community can help you. - type: textarea id: description attributes: label: Describe the bug description: Provide a clear and concise description of the challenge you are running into. validations: required: true - type: input id: link attributes: label: Your Example Website or App description: | Which website or app were you using when the bug happened? Note: - Your bug will may get fixed much faster if we can run your code and it doesn't have dependencies other than the `@graphql-codegen/*` npm related packages / dependencies. - To create a shareable code example you can use [GitHub](https://github.com/dotansimha/graphql-code-generator-issue-sandbox-template), [Stackblitz](https://stackblitz.com/github/dotansimha/graphql-code-generator-issue-sandbox-template) or [CodeSandbox](https://codesandbox.io/s/github/dotansimha/graphql-code-generator-issue-sandbox-template). Please no localhost URLs. - Please read these tips for providing a minimal example: https://stackoverflow.com/help/minimal-reproducible-example. placeholder: | e.g. https://codesandbox.io/...... OR Github Repo validations: required: true - type: textarea id: steps attributes: label: Steps to Reproduce the Bug or Issue description: Describe the steps we have to take to reproduce the behavior. placeholder: | 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error validations: required: true - type: textarea id: expected attributes: label: Expected behavior description: Provide a clear and concise description of what you expected to happen. placeholder: | As a user, I expected ___ behavior but i am seeing ___ validations: required: true - type: textarea id: screenshots_or_videos attributes: label: Screenshots or Videos description: | If applicable, add screenshots or a video to help explain your problem. For more information on the supported file image/file types and the file size limits, please refer to the following link: https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/attaching-files placeholder: | You can drag your video or image files inside of this editor ↓ - type: textarea id: platform attributes: label: Platform value: | - OS: [e.g. macOS, Windows, Linux] - NodeJS: [e.g. 18.5.0] - `graphql` version: [e.g. 16.3.0] - `@graphql-codegen/*` version(s): [e.g. 2.6.2] validations: required: true - type: textarea id: config attributes: label: Codegen Config File description: Your local Codegen config file (YAML/JSON...) placeholder: | schema: schema.graphql documents: document.graphql generates: types.ts: plugins: - typescript - typescript-operations - type: textarea id: additional attributes: label: Additional context description: Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Have a question? url: https://github.com/dotansimha/graphql-code-generator/discussions/new about: Not sure about something? need help from the community? have a question to our team? please ask and answer questions here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.yml ================================================ name: '✨ Feature request' description: Suggest an idea for the core of this project body: - type: markdown attributes: value: | ## Is it related to a community plugin? All request linked to a "Community plugin" (as defined below) should [be addressed on the `dotansimha/graphql-code-generator-community` repository](https://github.com/dotansimha/graphql-code-generator-community/issues/new?assignees=&labels=&template=feature-request.md).
Community plugins: - `@graphql-codegen/typescript-react-apollo` - `@graphql-codegen/typescript-graphql-request` - `@graphql-codegen/typescript-apollo-angular` - `@graphql-codegen/typescript-apollo-client-helpers` - `@graphql-codegen/typescript-react-query` - `@graphql-codegen/typescript-urql` - `@graphql-codegen/named-operations-object` - `@graphql-codegen/urql-introspection` - `@graphql-codegen/flow-resolvers` - `@graphql-codegen/typescript-vue-apollo` - `@graphql-codegen/typescript-rtk-query` - `@graphql-codegen/flow-operations` - `@graphql-codegen/typescript-msw` - `@graphql-codegen/typescript-mongodb` - `@graphql-codegen/typescript-type-graphql` - `@graphql-codegen/jsdoc` - `@graphql-codegen/typescript-vue-urql` - `@graphql-codegen/kotlin` - `@graphql-codegen/typescript-vue-apollo-smart-ops` - `@graphql-codegen/java` - `@graphql-codegen/c-sharp-operations` - `@graphql-codegen/hasura-allow-list` - `@graphql-codegen/typescript-stencil-apollo` - `@graphql-codegen/relay-operation-optimizer` - `@graphql-codegen/typescript-oclif` - `@graphql-codegen/java-resolvers` - `@graphql-codegen/java-apollo-android`
--- - type: textarea id: description attributes: label: Is your feature request related to a problem? Please describe. description: "A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]" validations: required: true - type: textarea id: solution attributes: label: Describe the solution you'd like description: 'A clear and concise description of what you want to happen.' validations: required: true - type: textarea id: alternatives attributes: label: Describe alternatives you've considered description: "A clear and concise description of any alternative solutions or features you've considered." validations: required: false - type: textarea id: context attributes: label: Any additional important details? description: 'Add context or screenshots about the feature request here.' validations: required: false ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ 🚨 **IMPORTANT: Please do not create a Pull Request without creating an issue first.** _Any change needs to be discussed before proceeding. Failure to do so may result in the rejection of the pull request._ ## Description Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. Related # (issue) ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ## Screenshots/Sandbox (if appropriate/relevant): Adding links to sandbox or providing screenshots can help us understand more about this PR and take action on it as appropriate ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [ ] Test A - [ ] Test B **Test Environment**: - OS: - `@graphql-codegen/...`: - NodeJS: ## Checklist: - [ ] I have followed the [CONTRIBUTING](https://github.com/the-guild-org/Stack/blob/master/CONTRIBUTING.md) doc and the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules ## Further comments If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... ================================================ FILE: .github/labels.yml ================================================ # Please add the repo specific custom labels here - name: 'core' color: '0366d6' description: 'Related to codegen core/cli' - name: 'dependencies' color: 'd4c5f9' - name: 'new-preset' color: '006b75' description: 'Suggestion for a new preset' - name: 'plugins' color: 'c2e0c6' - name: 'presets' color: '0e8a16' description: 'Related to Codegen presets' ================================================ FILE: .github/workflows/main.yml ================================================ name: Testing on: push: branches: - master pull_request: branches: - master env: NODE_OPTIONS: '--max_old_space_size=4096' CARGO_TERM_COLOR: always jobs: lint: name: Linting Check uses: the-guild-org/shared-config/.github/workflows/lint.yml@main with: script: yarn ci:lint secrets: githubToken: ${{ secrets.GITHUB_TOKEN }} prettier-check: name: 🧹 Prettier Check runs-on: ubuntu-latest steps: - name: Checkout Master uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup env uses: the-guild-org/shared-config/setup@main - name: Prettier Check run: yarn prettier:check dev-tests-old: name: Validating dev-tests runs-on: ubuntu-latest strategy: matrix: method: - 'cjs' - 'esm' steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup env uses: the-guild-org/shared-config/setup@main - name: Build run: yarn build env: CI: true - name: Test dev-tests ${{matrix.method}} run: | yarn run generate:examples:${{matrix.method}} git diff --exit-code -- dev-test/ dev-tests: name: Examples - Normal runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup env uses: the-guild-org/shared-config/setup@main - name: Build run: yarn build env: CI: true - name: Generate and Diff Codegen Artifacts run: | EXAMPLE_TYPE=normal yarn examples:codegen git diff --exit-code -- examples/ - name: Build Examples run: | EXAMPLE_TYPE=normal yarn examples:build - name: End2End Test Examples run: | EXAMPLE_TYPE=normal yarn examples:test:end2end # TODO: Remove all SWC test setup and references as that has been moved to https://github.com/swc-project/plugins/tree/main/contrib/graphql-codegen-client-preset # dev-tests-swc: # name: Examples - SWC # runs-on: ubuntu-latest # steps: # - name: Checkout # uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 # - name: Setup env # uses: the-guild-org/shared-config/setup@main # - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1 # with: # toolchain: 1.65.0 # target: wasm32-wasi # override: true # - name: Build SWC plugin # working-directory: ./packages/presets/swc-plugin # run: | # npm run build-wasm # - name: Build # run: yarn build # env: # CI: true # - name: Generate and Diff Codegen Artifacts # run: | # EXAMPLE_TYPE=swc yarn examples:codegen # git diff --exit-code -- examples/ # - name: Build Examples # run: | # EXAMPLE_TYPE=swc yarn examples:build # - name: End2End Test Examples # run: | # EXAMPLE_TYPE=swc yarn examples:test:end2end esm: name: Testing exports integrity runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup env uses: the-guild-org/shared-config/setup@main - name: Build run: yarn build env: CI: true - name: Test ESM & CJS integrity run: yarn bob check test: name: Unit Test on Node ${{matrix.node_version}} (${{matrix.os}}) and GraphQL v${{matrix.graphql_version}} runs-on: ubuntu-latest needs: - lint - prettier-check - esm strategy: matrix: os: [ubuntu-latest] # remove windows to speed up the tests node_version: [20, 22, 24] graphql_version: [15, 16] include: - node-version: 20 os: windows-latest graphql_version: 16 steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup env uses: the-guild-org/shared-config/setup@main with: nodeVersion: ${{matrix.node_version}} - name: Use GraphQL v${{matrix.graphql_version}} run: node ./scripts/match-graphql.js ${{matrix.graphql_version}} - name: Install Dependencies run: yarn - name: Build run: yarn build - name: Test # FIXME: Do not test `watcher.run.spec.ts` here because it is currently not working for Node22+ in Ubuntu run: yarn test --exclude="**/tests/watcher.run.spec.ts" env: CI: true test-watcher: name: Watcher Unit Test on Node ${{matrix.node_version}} (${{matrix.os}}) and GraphQL v${{matrix.graphql_version}} runs-on: ubuntu-latest needs: - lint - prettier-check - esm strategy: matrix: os: [ubuntu-latest] # remove windows to speed up the tests node_version: [20] graphql_version: [15, 16] include: - node-version: 20 os: windows-latest graphql_version: 16 steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup env uses: the-guild-org/shared-config/setup@main with: nodeVersion: ${{matrix.node_version}} - name: Use GraphQL v${{matrix.graphql_version}} run: node ./scripts/match-graphql.js ${{matrix.graphql_version}} - name: Install Dependencies run: yarn - name: Build run: yarn build - name: Test # FIXME: Merge `watcher.run.spec.ts` test to the above when it works for Node22+ in Ubuntu run: yarn test packages/graphql-codegen-cli/tests/watcher.run.spec.ts env: CI: true # TODO: Remove all SWC test setup and references as that has been moved to https://github.com/swc-project/plugins/tree/main/contrib/graphql-codegen-client-preset # test-rust-swc-plugin: # name: Build and Unit Test SWC Plugin # runs-on: ubuntu-latest # steps: # - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 # - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1 # with: # toolchain: 1.65.0 # target: wasm32-wasi # override: true # - uses: marcopolo/cargo@a527bf4d534717ff4424a84446c5d710f8833139 # with: # working-directory: ./packages/presets/swc-plugin # command: build # args: --target wasm32-wasi # - uses: marcopolo/cargo@a527bf4d534717ff4424a84446c5d710f8833139 # with: # working-directory: ./packages/presets/swc-plugin # command: test ================================================ FILE: .github/workflows/pr.yml ================================================ name: pr on: pull_request: branches: - master permissions: contents: write id-token: write pull-requests: write jobs: dependencies: uses: the-guild-org/shared-config/.github/workflows/changesets-dependencies.yaml@main if: ${{ github.event.pull_request.title != 'Upcoming Release Changes' }} secrets: githubToken: ${{ secrets.GITHUB_TOKEN }} alpha: uses: the-guild-org/shared-config/.github/workflows/release-snapshot.yml@main if: ${{ github.event.pull_request.title != 'Upcoming Release Changes' }} with: npmTag: alpha buildScript: build secrets: githubToken: ${{ secrets.GITHUB_TOKEN }} npmToken: ${{ secrets.NPM_TOKEN }} release-candidate: uses: the-guild-org/shared-config/.github/workflows/release-snapshot.yml@main if: ${{ github.event.pull_request.title == 'Upcoming Release Changes' }} with: npmTag: rc restoreDeletedChangesets: true buildScript: build secrets: githubToken: ${{ secrets.GITHUB_TOKEN }} npmToken: ${{ secrets.NPM_TOKEN }} ================================================ FILE: .github/workflows/release.yml ================================================ name: release on: push: branches: - master jobs: stable: uses: the-guild-org/shared-config/.github/workflows/release-stable.yml@main with: releaseScript: release secrets: # githubToken: ${{ secrets.GUILD_BOT_TOKEN }} githubToken: ${{ secrets.GITHUB_TOKEN }} npmToken: ${{ secrets.NPM_TOKEN }} ================================================ FILE: .github/workflows/rust.yml ================================================ name: Rust plugin on: workflow_dispatch: jobs: publish-rust-swc-plugin: runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 # Setup .npmrc file to publish to npm - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: '18.x' registry-url: 'https://registry.npmjs.org' - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1 with: toolchain: 1.65.0 target: wasm32-wasi override: true - name: Build SWC plugin working-directory: ./packages/presets/swc-plugin run: | npm run build-wasm - name: Publish SWC plugin working-directory: ./packages/presets/swc-plugin run: | npm publish --access=public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} ================================================ FILE: .github/workflows/website-integrity.yml ================================================ name: Website Integrity on: pull_request: paths: - 'website/**' jobs: website-check: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Fetch run: git fetch origin master - name: Setup env uses: the-guild-org/shared-config/setup@main - name: Build Packages run: yarn build - name: Build Website run: yarn workspace website run build - name: Compare run: git diff origin/${{ github.base_ref }}.. -- website/route-lockfile.txt - name: Diff to file if: always() id: diff_result run: | OUTPUT=$(git diff origin/${{ github.base_ref }}.. -- website/route-lockfile.txt) OUTPUT="${OUTPUT//'%'/'%25'}" OUTPUT="${OUTPUT//$'\n'/'%0A'}" OUTPUT="${OUTPUT//$'\r'/'%0D'}" echo "::set-output name=result::$OUTPUT" - name: Publish a message if: always() && contains(steps.diff_result.outputs.result, 'diff') uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2 with: message: | ```diff ${{ steps.diff_result.outputs.result }} ``` ================================================ FILE: .github/workflows/website.yml ================================================ name: website on: push: branches: - master pull_request: branches: - master jobs: deployment: runs-on: ubuntu-latest if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'push' steps: - name: checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - uses: the-guild-org/shared-config/setup@main name: setup env - uses: the-guild-org/shared-config/website-cf@main name: build and deploy website env: NEXT_BASE_PATH: ${{ github.ref == 'refs/heads/master' && '/graphql/codegen' || '' }} SITE_URL: ${{ github.ref == 'refs/heads/master' && 'https://the-guild.dev/graphql/codegen' || '' }} with: cloudflareApiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} cloudflareAccountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} githubToken: ${{ secrets.GITHUB_TOKEN }} projectName: graphql-code-generator prId: ${{ github.event.pull_request.number }} websiteDirectory: ./ buildScript: yarn build && cd website && yarn build artifactDir: website/out ================================================ FILE: .gitignore ================================================ .idea/ .npmrc .yarnclean .DS_Store coverage *.log node_modules/ temp/ junit.xml dist/ .bob/ out.txt .cache tsconfig.tsbuildinfo .yarn/ recompile.sh .next/ out/ website/public/sitemap.xml website/public/_redirects .eslintcache **/cypress/screenshots **/cypress/videos ================================================ FILE: .husky/pre-commit ================================================ yarn lint-staged ================================================ FILE: .nvmrc ================================================ 22 ================================================ FILE: .prettierignore ================================================ dev-test/githunt-invalid/invalid.graphql packages/graphql-codegen-cli/tests/test-documents/invalid-schema.graphql packages/presets/gql-tag-operations/tests/fixtures/crlf-operation.ts dist/ build/ .next/ .bob CHANGELOG.md .husky/_/ .changeset/*.md # temporarily ignore follow files because prettier-ignore comments don't work in mdx2 # see https://github.com/prettier/prettier/pull/12208 website/src/pages/docs/advanced/generated-files-colocation.mdx website/src/pages/docs/advanced/how-does-it-work.mdx website/src/pages/docs/config-reference/schema-field.mdx website/src/pages/docs/getting-started/index.mdx website/src/pages/docs/guides/graphql-server-apollo-yoga.mdx website/src/pages/docs/guides/react.mdx website/src/pages/plugins/index.mdx website/src/pages/plugins/presets/near-operation-file-preset.mdx temp/ website/out website/.next # added because it blocks CI and when I try to format it locally nothing happens :) website/src/components/live-demo/LiveDemo.tsx # This should be added bc our rust test setup for the SWC plugin does a string diff, and it fails # bc it compares imports with double quotes against the formatted perttier single quotes packages/presets/swc-plugin/tests/fixtures # Ignore intentional error files packages/graphql-codegen-cli/tests/test-files/schema-dir/error-schema.graphql packages/graphql-codegen-cli/tests/test-files/error-document.graphql ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": ["rust-lang.rust-analyzer", "tamasfe.even-better-toml"] } ================================================ FILE: .vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { "name": "Run open test file", "type": "node", "request": "launch", "runtimeArgs": ["--inspect-brk", "${workspaceRoot}/node_modules/.bin/vitest", "--runInBand", "${relativeFile}"], "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" } ] } ================================================ FILE: .vscode/settings.json ================================================ { "yaml.schemas": { "./website/static/config.schema.json": "*codegen.*" }, "eslint.useFlatConfig": false, "editor.tabSize": 2, "editor.insertSpaces": true, "editor.rulers": [80], "editor.wordWrapColumn": 110, "prettier.semi": true, "files.trimTrailingWhitespace": true, "files.insertFinalNewline": true, "prettier.singleQuote": true, "prettier.printWidth": 110, "files.exclude": { "**/.git": true, "**/.DS_Store": true, "node_modules": false, "test-lib": true, "lib": true, "coverage": true, "npm": true }, "typescript.tsdk": "node_modules/typescript/lib", "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer", "editor.formatOnSave": true } } ================================================ FILE: .yarnrc ================================================ --ignore-engines true --network-timeout 1000000000 ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016 Dotan Simha Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================
GraphQL Code Generator logo Created by The Guild
[![npm version](https://badge.fury.io/js/%40graphql-codegen%2Fcli.svg)](https://badge.fury.io/js/%40graphql-codegen%2Fcli) [https://the-guild.dev/graphql/codegen](https://the-guild.dev/graphql/codegen) GraphQL Code Generator is a tool that generates code out of your GraphQL schema. Whether you are developing a frontend or backend, you can utilize GraphQL Code Generator to generate output from your GraphQL Schema and GraphQL Documents (query/mutation/subscription/fragment). By analyzing the schema and documents and parsing it, GraphQL Code Generator can output code at a wide variety of formats, based on pre-defined templates or based on custom user-defined ones. Regardless of the language that you're using, GraphQL Code Generator has you covered. GraphQL Code Generator lets you choose the output that you need, based on _plugins_, which are very flexible and customizable. You can also write your _plugins_ to generate custom outputs that match your needs. You can try this tool live on your browser and see some useful examples. Check out [GraphQL Code Generator Live Examples](https://the-guild.dev/graphql/codegen/#live-demo). We currently support and maintain [these plugins](https://the-guild.dev/graphql/codegen/plugins) (TypeScript, Flow, React, Angular, MongoDB, Stencil, Reason, and some more), and there is an active community that writes and maintains custom plugins. ## Quick Start > You can find the complete instructions in [GraphQL Code Generator website](https://the-guild.dev/graphql/codegen/docs/getting-started/installation). Start by installing the basic deps of GraphQL Codegen: ```bash yarn add graphql yarn add -D @graphql-codegen/cli ``` GraphQL Code Generator lets you setup everything by simply running the following command: ```bash yarn graphql-codegen init ``` Question by question, it will guide you through the whole process of setting up a schema, selecting plugins, picking a destination of a generated file, and a lot more. If you wish to [manually setup codegen, follow these instructions](https://the-guild.dev/graphql/codegen/docs/getting-started/installation). ## Links Besides our [docs page](https://the-guild.dev/graphql/codegen/docs/getting-started), feel free to go through our published Medium articles to get a better grasp of what GraphQL Code Generator is all about: - [All available plugins & presets](https://the-guild.dev/graphql/codegen/plugins) ## Contributing If this is your first time contributing to this project, please do read our [Contributor Workflow Guide](https://github.com/the-guild-org/Stack/blob/master/CONTRIBUTING.md) before you get started off. Feel free to open issues and pull requests. We're always welcome support from the community. For a contribution guide specific to this project, please refer to: http://the-guild.dev/graphql/codegen/docs/custom-codegen/contributing. ## Code of Conduct Help us keep GraphQL Code Generator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/the-guild-org/Stack/blob/master/CODE_OF_CONDUCT.md) as adopted from [Contributor Covenant](https://contributor-covenant.org) ## License [![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg?maxAge=2592000)](https://raw.githubusercontent.com/apollostack/apollo-ios/master/LICENSE) MIT ================================================ FILE: babel.config.js ================================================ module.exports = { presets: [ ['@babel/preset-env', { targets: { node: process.versions.node.split('.')[0] } }], ['@babel/preset-typescript', { allowDeclareFields: true }], ], }; ================================================ FILE: dev-test/alt-codegen.yml ================================================ overwrite: true schema: 'test-schema/schema.graphql' documents: - 'src/**/*.graphql' generates: test-schema/schema.ts: - typescript: declarationKind: interface - typescript-operations: declarationKind: interface defaultScalarType: unknown ================================================ FILE: dev-test/apollo-android/codegen.yml ================================================ schema: - https://jpmbfqfpxvcujfn4d4e3lu2pga.appsync-api.us-east-1.amazonaws.com/graphql: headers: 'x-api-key': da2-t2u7vtm33fattisq6vrrde56ui documents: - /Users/dotansimha/Dev/test-app/app/src/main/graphql/com/amazonaws/amplify/generated/graphql/*.graphql generates: generatedJava/: preset: java-apollo-android config: package: com.app.generated.graphql scalars: AWSDate: Long plugins: - java-apollo-android ================================================ FILE: dev-test/apollo-android/schema.json ================================================ { "data": { "__schema": { "queryType": { "name": "Query" }, "mutationType": { "name": "Mutation" }, "subscriptionType": { "name": "Subscription" }, "types": [ { "kind": "OBJECT", "name": "Query", "description": null, "fields": [ { "name": "getTodo", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Todo", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "listTodos", "description": null, "args": [ { "name": "filter", "description": null, "type": { "kind": "INPUT_OBJECT", "name": "ModelTodoFilterInput", "ofType": null }, "defaultValue": null }, { "name": "limit", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "nextToken", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ModelTodoConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Todo", "description": null, "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "ID", "description": "Built-in ID", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "String", "description": "Built-in String", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ModelTodoConnection", "description": null, "fields": [ { "name": "items", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Todo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nextToken", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ModelTodoFilterInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "INPUT_OBJECT", "name": "ModelIDFilterInput", "ofType": null }, "defaultValue": null }, { "name": "name", "description": null, "type": { "kind": "INPUT_OBJECT", "name": "ModelStringFilterInput", "ofType": null }, "defaultValue": null }, { "name": "description", "description": null, "type": { "kind": "INPUT_OBJECT", "name": "ModelStringFilterInput", "ofType": null }, "defaultValue": null }, { "name": "and", "description": null, "type": { "kind": "LIST", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ModelTodoFilterInput", "ofType": null } }, "defaultValue": null }, { "name": "or", "description": null, "type": { "kind": "LIST", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ModelTodoFilterInput", "ofType": null } }, "defaultValue": null }, { "name": "not", "description": null, "type": { "kind": "INPUT_OBJECT", "name": "ModelTodoFilterInput", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ModelIDFilterInput", "description": null, "fields": null, "inputFields": [ { "name": "ne", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "eq", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "le", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "lt", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "ge", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "gt", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "contains", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "notContains", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "between", "description": null, "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "beginsWith", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ModelStringFilterInput", "description": null, "fields": null, "inputFields": [ { "name": "ne", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "eq", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "le", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "lt", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "ge", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "gt", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "contains", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "notContains", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "between", "description": null, "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "beginsWith", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "Int", "description": "Built-in Int", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Mutation", "description": null, "fields": [ { "name": "createTodo", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CreateTodoInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Todo", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateTodo", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateTodoInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Todo", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteTodo", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteTodoInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Todo", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CreateTodoInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "name", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "description", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateTodoInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "description", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteTodoInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Subscription", "description": null, "fields": [ { "name": "onCreateTodo", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "Todo", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onUpdateTodo", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "Todo", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onDeleteTodo", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "Todo", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ModelFloatFilterInput", "description": null, "fields": null, "inputFields": [ { "name": "ne", "description": null, "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "defaultValue": null }, { "name": "eq", "description": null, "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "defaultValue": null }, { "name": "le", "description": null, "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "defaultValue": null }, { "name": "lt", "description": null, "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "defaultValue": null }, { "name": "ge", "description": null, "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "defaultValue": null }, { "name": "gt", "description": null, "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "defaultValue": null }, { "name": "contains", "description": null, "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "defaultValue": null }, { "name": "notContains", "description": null, "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "defaultValue": null }, { "name": "between", "description": null, "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "Float", "description": "Built-in Float", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ModelBooleanFilterInput", "description": null, "fields": null, "inputFields": [ { "name": "ne", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "eq", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "Boolean", "description": "Built-in Boolean", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ModelIntFilterInput", "description": null, "fields": null, "inputFields": [ { "name": "ne", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "eq", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "le", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "lt", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "ge", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "gt", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "contains", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "notContains", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "between", "description": null, "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ModelSortDirection", "description": null, "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ASC", "description": null, "isDeprecated": false, "deprecationReason": null }, { "name": "DESC", "description": null, "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "__Schema", "description": "A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.", "fields": [ { "name": "types", "description": "A list of all types supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "queryType", "description": "The type that query operations will be rooted at.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mutationType", "description": "If this server supports mutation, the type that mutation operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "directives", "description": "'A list of all directives supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subscriptionType", "description": "'If this server support subscription, the type that subscription operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Type", "description": null, "fields": [ { "name": "kind", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "fields", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "interfaces", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "possibleTypes", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "enumValues", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "inputFields", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ofType", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__TypeKind", "description": "An enum describing what kind of type a given __Type is", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "SCALAR", "description": "Indicates this type is a scalar.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Indicates this type is a union. `possibleTypes` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Indicates this type is an enum. `enumValues` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Indicates this type is an input object. `inputFields` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "LIST", "description": "Indicates this type is a list. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "NON_NULL", "description": "Indicates this type is a non-null. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "__Field", "description": null, "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__InputValue", "description": null, "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "defaultValue", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__EnumValue", "description": null, "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Directive", "description": null, "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "locations", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "onOperation", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onFragment", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onField", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "isDeprecated": true, "deprecationReason": "Use `locations`." } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__DirectiveLocation", "description": "An enum describing valid locations where a directive can be placed", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "QUERY", "description": "Indicates the directive is valid on queries.", "isDeprecated": false, "deprecationReason": null }, { "name": "MUTATION", "description": "Indicates the directive is valid on mutations.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD", "description": "Indicates the directive is valid on fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_DEFINITION", "description": "Indicates the directive is valid on fragment definitions.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_SPREAD", "description": "Indicates the directive is valid on fragment spreads.", "isDeprecated": false, "deprecationReason": null }, { "name": "INLINE_FRAGMENT", "description": "Indicates the directive is valid on inline fragments.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCHEMA", "description": "Indicates the directive is valid on a schema SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCALAR", "description": "Indicates the directive is valid on a scalar SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Indicates the directive is valid on an object SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD_DEFINITION", "description": "Indicates the directive is valid on a field SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ARGUMENT_DEFINITION", "description": "Indicates the directive is valid on a field argument SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Indicates the directive is valid on an interface SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Indicates the directive is valid on an union SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Indicates the directive is valid on an enum SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM_VALUE", "description": "Indicates the directive is valid on an enum value SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Indicates the directive is valid on an input object SDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_FIELD_DEFINITION", "description": "Indicates the directive is valid on an input object field SDL definition.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null } ], "directives": [ { "name": "include", "description": "Directs the executor to include this field or fragment only when the `if` argument is true", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Included when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": true, "onField": true }, { "name": "skip", "description": "Directs the executor to skip this field or fragment when the `if`'argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Skipped when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": true, "onField": true }, { "name": "defer", "description": "This directive allows results to be deferred during execution", "locations": ["FIELD"], "args": [], "onOperation": false, "onFragment": false, "onField": true }, { "name": "aws_auth", "description": "Directs the schema to enforce authorization on a field", "locations": ["FIELD_DEFINITION"], "args": [ { "name": "cognito_groups", "description": "List of cognito user pool groups which have access on this field", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": false, "onField": false }, { "name": "aws_publish", "description": "Tells the service which subscriptions will be published to when this mutation is called. This directive is deprecated use @aws_susbscribe directive instead.", "locations": ["FIELD_DEFINITION"], "args": [ { "name": "subscriptions", "description": "List of subscriptions which will be published to when this mutation is called.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": false, "onField": false }, { "name": "aws_cognito_user_pools", "description": "Tells the service this field/object has access authorized by a Cognito User Pools token.", "locations": ["OBJECT", "FIELD_DEFINITION"], "args": [ { "name": "cognito_groups", "description": "List of cognito user pool groups which have access on this field", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": false, "onField": false }, { "name": "aws_subscribe", "description": "Tells the service which mutation triggers this subscription.", "locations": ["FIELD_DEFINITION"], "args": [ { "name": "mutations", "description": "List of mutations which will trigger this subscription when they are called.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": false, "onField": false }, { "name": "aws_oidc", "description": "Tells the service this field/object has access authorized by an OIDC token.", "locations": ["OBJECT", "FIELD_DEFINITION"], "args": [], "onOperation": false, "onFragment": false, "onField": false }, { "name": "deprecated", "description": null, "locations": ["FIELD_DEFINITION", "ENUM_VALUE"], "args": [ { "name": "reason", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": "\"No longer supported\"" } ], "onOperation": false, "onFragment": false, "onField": false }, { "name": "aws_api_key", "description": "Tells the service this field/object has access authorized by an API key.", "locations": ["OBJECT", "FIELD_DEFINITION"], "args": [], "onOperation": false, "onFragment": false, "onField": false }, { "name": "aws_iam", "description": "Tells the service this field/object has access authorized by sigv4 signing.", "locations": ["OBJECT", "FIELD_DEFINITION"], "args": [], "onOperation": false, "onFragment": false, "onField": false } ] } } } ================================================ FILE: dev-test/codegen.ts ================================================ import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { hooks: { afterAllFileWrite: ['prettier --write'] }, emitLegacyCommonJSImports: false, generates: { './dev-test/test-schema/resolvers-types.ts': { schema: './dev-test/test-schema/schema-text.js', plugins: ['typescript', 'typescript-resolvers'], }, './dev-test/test-schema/flow-types.flow.js': { schema: './dev-test/test-schema/schema.json', plugins: ['flow', 'flow-resolvers'], }, './dev-test/test-schema/resolvers-root.ts': { schema: './dev-test/test-schema/schema-with-root.graphql', plugins: ['typescript', 'typescript-resolvers'], }, './dev-test/test-schema/resolvers-federation.ts': { schema: './dev-test/test-schema/schema-federation.graphql', config: { federation: true }, plugins: ['typescript', 'typescript-resolvers'], }, './dev-test/test-schema/resolvers-stitching.ts': { schema: './dev-test/test-schema/schema-text.js', plugins: ['typescript', { 'typescript-resolvers': { noSchemaStitching: false } }], }, './dev-test/test-schema/typings.ts': { schema: './dev-test/test-schema/schema.json', plugins: ['typescript', 'typescript-resolvers'], }, './dev-test/test-schema/typings.avoidOptionals.ts': { schema: './dev-test/test-schema/schema.json', config: { avoidOptionals: true }, plugins: ['typescript'], }, './dev-test/test-schema/typings.wrapped.ts': { schema: './dev-test/test-schema/schema.json', plugins: [ { add: { content: 'declare namespace GraphQL {' } }, { add: { placement: 'append', content: '}' } }, 'typescript', 'typescript-operations', ], }, './dev-test/test-schema/env.types.ts': { schema: process.env.SCHEMA_PATH, plugins: ['typescript'] }, './dev-test/test-schema/typings.immutableTypes.ts': { schema: './dev-test/test-schema/schema.json', config: { imutableTypes: true }, plugins: ['typescript'], }, './dev-test/test-schema/typings.enum.ts': { schema: './dev-test/test-schema/schema-object.js', plugins: ['typescript'], }, './dev-test/githunt/graphql-declared-modules.d.ts': { schema: './dev-test/githunt/schema.json', documents: [ './dev-test/githunt/**/*.graphql', './dev-test-outer-dir/githunt/**/*.graphql', '!**/nothing-should-use-this-query.graphql', ], plugins: ['typescript-graphql-files-modules'], }, './dev-test/githunt/typed-document-nodes.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', plugins: ['typescript', 'typescript-operations', 'typed-document-node'], }, './dev-test/githunt/types.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', plugins: ['typescript', 'typescript-operations'], }, './dev-test/githunt/types.preResolveTypes.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', config: { preResolveTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/githunt/types.onlyEnums.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', config: { onlyEnums: true }, plugins: ['typescript'], }, './dev-test/githunt/types.preResolveTypes.onlyOperationTypes.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', config: { preResolveTypes: true, onlyOperationTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/githunt/types.flatten.preResolveTypes.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', config: { preResolveTypes: true, flattenGeneratedTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/githunt/types.enumsAsTypes.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', config: { enumsAsTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/githunt/types.d.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', config: { enumsAsTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/githunt/types.avoidOptionals.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', config: { avoidOptionals: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/githunt/types.immutableTypes.ts': { schema: './dev-test/githunt/schema.json', documents: './dev-test/githunt/**/*.graphql', config: { immutableTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/star-wars/types.ts': { schema: './dev-test/star-wars/schema.json', documents: './dev-test/star-wars/**/*.graphql', plugins: ['typescript', 'typescript-operations'], }, './dev-test/star-wars/types.excludeQueryAlpha.ts': { schema: './dev-test/star-wars/schema.json', documents: ['./dev-test/star-wars/**/*.graphql', '!./dev-test/star-wars/**/ExcludeQueryAlpha.graphql'], plugins: ['typescript', 'typescript-operations'], }, './dev-test/star-wars/types.excludeQueryBeta.ts': { schema: './dev-test/star-wars/schema.json', documents: ['./dev-test/star-wars/**/*.graphql', '!./dev-test/star-wars/**/ExcludeQueryBeta.graphql'], plugins: ['typescript', 'typescript-operations'], }, './dev-test/star-wars/types.preResolveTypes.ts': { schema: './dev-test/star-wars/schema.json', documents: './dev-test/star-wars/**/*.graphql', config: { preResolveTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/star-wars/types.OnlyEnums.ts': { schema: './dev-test/star-wars/schema.json', documents: './dev-test/star-wars/**/*.graphql', config: { onlyEnums: true }, plugins: ['typescript'], }, './dev-test/star-wars/types.preResolveTypes.onlyOperationTypes.ts': { schema: './dev-test/star-wars/schema.json', documents: './dev-test/star-wars/**/*.graphql', config: { preResolveTypes: true, onlyOperationTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/test-schema/types.preResolveTypes.ts': { schema: './dev-test/test-schema/schema.graphql', documents: ['query test { testArr1 testArr2 testArr3 }'], config: { preResolveTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/test-schema/types.preResolveTypes.onlyOperationTypes.ts': { schema: './dev-test/test-schema/schema.graphql', documents: ['query test { testArr1 testArr2 testArr3 }'], config: { preResolveTypes: true, onlyOperationTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/star-wars/types.d.ts': { schema: './dev-test/star-wars/schema.json', config: { enumsAsTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/modules/': { schema: './dev-test/modules/*/types/*.graphql', preset: 'graphql-modules', presetConfig: { baseTypesPath: 'types.ts', filename: 'generated.ts' }, plugins: ['typescript', 'typescript-resolvers'], }, './dev-test/star-wars/types.globallyAvailable.d.ts': { schema: './dev-test/star-wars/schema.json', documents: './dev-test/star-wars/**/*.graphql', config: { enumsAsTypes: true, noExport: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/star-wars/types.avoidOptionals.ts': { schema: './dev-test/star-wars/schema.json', documents: './dev-test/star-wars/**/*.graphql', config: { avoidOptionals: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/star-wars/types.immutableTypes.ts': { schema: './dev-test/star-wars/schema.json', documents: './dev-test/star-wars/**/*.graphql', config: { immutableTypes: true }, plugins: ['typescript', 'typescript-operations'], }, './dev-test/star-wars/types.skipSchema.ts': { schema: './dev-test/star-wars/schema.json', documents: './dev-test/star-wars/**/*.graphql', plugins: ['typescript', 'typescript-operations'], }, './dev-test/gql-tag-operations/gql/': { schema: './dev-test/gql-tag-operations/schema.graphql', documents: './dev-test/gql-tag-operations/src/**/*.ts', preset: 'client', }, './dev-test/gql-tag-operations/graphql/': { schema: './dev-test/gql-tag-operations/schema.graphql', documents: './dev-test/gql-tag-operations/src/**/*.ts', preset: 'client', }, './dev-test/gql-tag-operations-urql/gql/': { schema: './dev-test/gql-tag-operations-urql/schema.graphql', documents: './dev-test/gql-tag-operations-urql/src/**/*.ts', preset: 'client', presetConfig: { augmentedModuleName: '@urql/core' }, }, './dev-test/gql-tag-operations-masking/gql/': { schema: './dev-test/gql-tag-operations-masking/schema.graphql', documents: './dev-test/gql-tag-operations-masking/src/**/*.tsx', preset: 'client', presetConfig: { fragmentMasking: true }, }, './dev-test/test-null-value/result.d.ts': { schema: './dev-test/test-null-value/schema.graphql', documents: ['./dev-test/test-null-value/query.ts'], plugins: ['typescript', 'typescript-operations'], config: { // The combination of these two flags caused the following issue: // https://github.com/dotansimha/graphql-code-generator/pull/9709 skipTypename: true, mergeFragmentTypes: true, }, }, './dev-test/subpath-import/result.d.ts': { schema: './dev-test/subpath-import/schema.graphql', plugins: ['typescript', 'typescript-resolvers'], config: { contextType: '\\#test-null-value/context#TestContext', fieldContextTypes: ['mutation.createUser#\\#test/root#FiedContextType'], enumValues: { RoleStatus: '\\#changeName/server/drizzle/schema#RoleStatus', }, }, }, './dev-test/test-federation/generated/types.ts': { schema: './dev-test/test-federation/schema.gql', plugins: ['typescript', 'typescript-resolvers'], config: { mapperTypeSuffix: 'Mapper', enumsAsTypes: true, useIndexSignature: true, maybeValue: 'T | null | undefined', scalars: { CarKey: 'string', }, }, }, }, }; export default config; ================================================ FILE: dev-test/gatsby/fragments.ts ================================================ import gql from 'graphql-tag'; export const WPColumns = gql` fragment WPColumns on WpCoreColumnsBlock { __typename attributes { ... on WpCoreColumnsBlockAttributes { align verticalAlignment } } innerBlocks { ...WpColumnFields ...WpCoreImageBlockFragment ...WpCoreGalleryBlockFragment innerBlocks { __typename ...WpCoreImageBlockForGalleryFragment ...WpCoreGalleryBlockFragment saveContent dynamicContent isDynamic # ... on WpCoreGalleryBlock { __typename ...WpCoreGalleryBlockFragment innerBlocks { __typename ...WpCoreImageBlockForGalleryFragment } } ... on WpCoreColumnsBlock { innerBlocks { ...WpColumnFields innerBlocks { ...WpCoreImageBlockFragment ...WpCoreGalleryBlockFragment ... on WpCoreColumnsBlock { innerBlocks { ...WpColumnFields innerBlocks { ...WpCoreImageBlockForGalleryFragment ...WpCoreGalleryBlockFragment } } } } } } } } } `; export const wpColumnFields = gql` fragment WpColumnFields on WpCoreColumnBlock { __typename saveContent dynamicContent isDynamic attributes { __typename } } `; export const WpCoreImageBlockFragment = gql` fragment WpCoreImageBlockFragment on WpCoreImageBlock { __typename saveContent originalContent attributes { __typename ... on WpCoreImageBlockAttributes { id alt caption width title height linkTarget url imageFluid { childImageSharp { gatsbyImageData(quality: 100, layout: FULL_WIDTH) } } } } } `; export const WpCoreImageBlockForGalleryFragment = gql` fragment WpCoreImageBlockForGalleryFragment on WpCoreImageBlock { __typename saveContent attributes { __typename ... on WpCoreImageBlockAttributes { id alt caption width title height linkTarget url imageFluid { childImageSharp { full: gatsbyImageData(quality: 100, layout: FULL_WIDTH) thumbnail: gatsbyImageData(layout: CONSTRAINED) } } } } } `; export const WpCoreParagraphBlockFragment = gql` fragment WpCoreParagraphBlockFragment on WpCoreParagraphBlock { __typename saveContent isDynamic dynamicContent } `; export const WpCoreGalleryBlockFragment = gql` fragment WpCoreGalleryBlockFragment on WpCoreGalleryBlock { dynamicContent attributes { ... on WpCoreGalleryBlockAttributes { align anchor ids caption images { id url link alt caption } className } } } `; ================================================ FILE: dev-test/gatsby/schema.graphql ================================================ """ Define parent-child relations between types. This is used to add `child*` and `children*` convenience fields like `childImageSharp`. """ directive @childOf( """ A list of mime-types this type is a child of. Usually these are the mime-types handled by a transformer plugin. """ mimeTypes: [String!]! = [] """ A list of types this type is a child of. Usually these are the types handled by a transformer plugin. """ types: [String!]! = [] ) on OBJECT """ Add date formatting options. """ directive @dateformat(difference: String, formatString: String, fromNow: Boolean, locale: String) on FIELD_DEFINITION """ Do not infer field types from field values. """ directive @dontInfer on OBJECT """ Link to File node by relative path. """ directive @fileByRelativePath(from: String) on FIELD_DEFINITION """ Infer field types from field values. """ directive @infer on OBJECT """ Link to node by foreign-key relation. """ directive @link(by: String! = "id", from: String, on: String) on FIELD_DEFINITION """ Define the mime-types handled by this type. """ directive @mimeTypes( """ The mime-types handled by this type. """ types: [String!]! = [] ) on OBJECT """ DEPRECATED: Use interface inheritance instead, i.e. "interface Foo implements Node". Adds root query fields for an interface. All implementing types must also implement the Node interface. """ directive @nodeInterface on INTERFACE """ Proxy resolver from another field. """ directive @proxy(from: String!, fromNode: Boolean! = false) on FIELD_DEFINITION input AVIFOptions { lossless: Boolean quality: Int speed: Int } input BlurredOptions { """ Force the output format for the low-res preview. Default is to use the same format as the input. You should rarely need to change this """ toFormat: ImageFormat """ Width of the generated low-res preview. Default is 20px """ width: Int } input BooleanQueryOperatorInput { eq: Boolean in: [Boolean] ne: Boolean nin: [Boolean] } """ A date string, such as 2007-12-03, compliant with the ISO 8601 standard for representation of dates and times using the Gregorian calendar. """ scalar Date input DateQueryOperatorInput { eq: Date gt: Date gte: Date in: [Date] lt: Date lte: Date ne: Date nin: [Date] } type Directory implements Node { absolutePath: String! accessTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! atime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! atimeMs: Float! base: String! birthTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! birthtime: Date @deprecated(reason: "Use `birthTime` instead") birthtimeMs: Float @deprecated(reason: "Use `birthTime` instead") changeTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! children: [Node!]! ctime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! ctimeMs: Float! dev: Int! dir: String! ext: String! extension: String! gid: Int! id: ID! ino: Float! internal: Internal! mode: Int! modifiedTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! mtime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! mtimeMs: Float! name: String! nlink: Int! parent: Node prettySize: String! rdev: Int! relativeDirectory: String! relativePath: String! root: String! size: Int! sourceInstanceName: String! uid: Int! } type DirectoryConnection { distinct(field: DirectoryFieldsEnum!): [String!]! edges: [DirectoryEdge!]! group(field: DirectoryFieldsEnum!, limit: Int, skip: Int): [DirectoryGroupConnection!]! max(field: DirectoryFieldsEnum!): Float min(field: DirectoryFieldsEnum!): Float nodes: [Directory!]! pageInfo: PageInfo! sum(field: DirectoryFieldsEnum!): Float totalCount: Int! } type DirectoryEdge { next: Directory node: Directory! previous: Directory } enum DirectoryFieldsEnum { absolutePath accessTime atime atimeMs base birthTime birthtime birthtimeMs changeTime children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id ctime ctimeMs dev dir ext extension gid id ino internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type mode modifiedTime mtime mtimeMs name nlink parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id prettySize rdev relativeDirectory relativePath root size sourceInstanceName uid } input DirectoryFilterInput { absolutePath: StringQueryOperatorInput accessTime: DateQueryOperatorInput atime: DateQueryOperatorInput atimeMs: FloatQueryOperatorInput base: StringQueryOperatorInput birthTime: DateQueryOperatorInput birthtime: DateQueryOperatorInput birthtimeMs: FloatQueryOperatorInput changeTime: DateQueryOperatorInput children: NodeFilterListInput ctime: DateQueryOperatorInput ctimeMs: FloatQueryOperatorInput dev: IntQueryOperatorInput dir: StringQueryOperatorInput ext: StringQueryOperatorInput extension: StringQueryOperatorInput gid: IntQueryOperatorInput id: StringQueryOperatorInput ino: FloatQueryOperatorInput internal: InternalFilterInput mode: IntQueryOperatorInput modifiedTime: DateQueryOperatorInput mtime: DateQueryOperatorInput mtimeMs: FloatQueryOperatorInput name: StringQueryOperatorInput nlink: IntQueryOperatorInput parent: NodeFilterInput prettySize: StringQueryOperatorInput rdev: IntQueryOperatorInput relativeDirectory: StringQueryOperatorInput relativePath: StringQueryOperatorInput root: StringQueryOperatorInput size: IntQueryOperatorInput sourceInstanceName: StringQueryOperatorInput uid: IntQueryOperatorInput } type DirectoryGroupConnection { distinct(field: DirectoryFieldsEnum!): [String!]! edges: [DirectoryEdge!]! field: String! fieldValue: String group(field: DirectoryFieldsEnum!, limit: Int, skip: Int): [DirectoryGroupConnection!]! max(field: DirectoryFieldsEnum!): Float min(field: DirectoryFieldsEnum!): Float nodes: [Directory!]! pageInfo: PageInfo! sum(field: DirectoryFieldsEnum!): Float totalCount: Int! } input DirectorySortInput { fields: [DirectoryFieldsEnum] order: [SortOrderEnum] = [ASC] } input DuotoneGradient { highlight: String! opacity: Int shadow: String! } type File implements Node { absolutePath: String! accessTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! atime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! atimeMs: Float! base: String! birthTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! birthtime: Date @deprecated(reason: "Use `birthTime` instead") birthtimeMs: Float @deprecated(reason: "Use `birthTime` instead") blksize: Int blocks: Int changeTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! """ Returns the first child node of type ImageSharp or null if there are no children of given type on this node """ childImageSharp: ImageSharp children: [Node!]! """ Returns all children nodes filtered by type ImageSharp """ childrenImageSharp: [ImageSharp] ctime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! ctimeMs: Float! dev: Int! dir: String! ext: String! extension: String! gid: Int! hash: String id: ID! ino: Float! internal: Internal! mode: Int! modifiedTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! mtime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date! mtimeMs: Float! name: String! nlink: Int! parent: Node prettySize: String! """ Copy file to static directory and return public url to it """ publicURL: String rdev: Int! relativeDirectory: String! relativePath: String! root: String! size: Int! sourceInstanceName: String! uid: Int! } type FileConnection { distinct(field: FileFieldsEnum!): [String!]! edges: [FileEdge!]! group(field: FileFieldsEnum!, limit: Int, skip: Int): [FileGroupConnection!]! max(field: FileFieldsEnum!): Float min(field: FileFieldsEnum!): Float nodes: [File!]! pageInfo: PageInfo! sum(field: FileFieldsEnum!): Float totalCount: Int! } type FileEdge { next: File node: File! previous: File } enum FileFieldsEnum { absolutePath accessTime atime atimeMs base birthTime birthtime birthtimeMs blksize blocks changeTime childImageSharp___children childImageSharp___children___children childImageSharp___children___children___children childImageSharp___children___children___id childImageSharp___children___id childImageSharp___children___internal___content childImageSharp___children___internal___contentDigest childImageSharp___children___internal___description childImageSharp___children___internal___fieldOwners childImageSharp___children___internal___ignoreType childImageSharp___children___internal___mediaType childImageSharp___children___internal___owner childImageSharp___children___internal___type childImageSharp___children___parent___children childImageSharp___children___parent___id childImageSharp___fixed___aspectRatio childImageSharp___fixed___base64 childImageSharp___fixed___height childImageSharp___fixed___originalName childImageSharp___fixed___src childImageSharp___fixed___srcSet childImageSharp___fixed___srcSetWebp childImageSharp___fixed___srcWebp childImageSharp___fixed___tracedSVG childImageSharp___fixed___width childImageSharp___fluid___aspectRatio childImageSharp___fluid___base64 childImageSharp___fluid___originalImg childImageSharp___fluid___originalName childImageSharp___fluid___presentationHeight childImageSharp___fluid___presentationWidth childImageSharp___fluid___sizes childImageSharp___fluid___src childImageSharp___fluid___srcSet childImageSharp___fluid___srcSetWebp childImageSharp___fluid___srcWebp childImageSharp___fluid___tracedSVG childImageSharp___gatsbyImageData childImageSharp___id childImageSharp___internal___content childImageSharp___internal___contentDigest childImageSharp___internal___description childImageSharp___internal___fieldOwners childImageSharp___internal___ignoreType childImageSharp___internal___mediaType childImageSharp___internal___owner childImageSharp___internal___type childImageSharp___original___height childImageSharp___original___src childImageSharp___original___width childImageSharp___parent___children childImageSharp___parent___children___children childImageSharp___parent___children___id childImageSharp___parent___id childImageSharp___parent___internal___content childImageSharp___parent___internal___contentDigest childImageSharp___parent___internal___description childImageSharp___parent___internal___fieldOwners childImageSharp___parent___internal___ignoreType childImageSharp___parent___internal___mediaType childImageSharp___parent___internal___owner childImageSharp___parent___internal___type childImageSharp___parent___parent___children childImageSharp___parent___parent___id childImageSharp___resize___aspectRatio childImageSharp___resize___height childImageSharp___resize___originalName childImageSharp___resize___src childImageSharp___resize___tracedSVG childImageSharp___resize___width children childrenImageSharp childrenImageSharp___children childrenImageSharp___children___children childrenImageSharp___children___children___children childrenImageSharp___children___children___id childrenImageSharp___children___id childrenImageSharp___children___internal___content childrenImageSharp___children___internal___contentDigest childrenImageSharp___children___internal___description childrenImageSharp___children___internal___fieldOwners childrenImageSharp___children___internal___ignoreType childrenImageSharp___children___internal___mediaType childrenImageSharp___children___internal___owner childrenImageSharp___children___internal___type childrenImageSharp___children___parent___children childrenImageSharp___children___parent___id childrenImageSharp___fixed___aspectRatio childrenImageSharp___fixed___base64 childrenImageSharp___fixed___height childrenImageSharp___fixed___originalName childrenImageSharp___fixed___src childrenImageSharp___fixed___srcSet childrenImageSharp___fixed___srcSetWebp childrenImageSharp___fixed___srcWebp childrenImageSharp___fixed___tracedSVG childrenImageSharp___fixed___width childrenImageSharp___fluid___aspectRatio childrenImageSharp___fluid___base64 childrenImageSharp___fluid___originalImg childrenImageSharp___fluid___originalName childrenImageSharp___fluid___presentationHeight childrenImageSharp___fluid___presentationWidth childrenImageSharp___fluid___sizes childrenImageSharp___fluid___src childrenImageSharp___fluid___srcSet childrenImageSharp___fluid___srcSetWebp childrenImageSharp___fluid___srcWebp childrenImageSharp___fluid___tracedSVG childrenImageSharp___gatsbyImageData childrenImageSharp___id childrenImageSharp___internal___content childrenImageSharp___internal___contentDigest childrenImageSharp___internal___description childrenImageSharp___internal___fieldOwners childrenImageSharp___internal___ignoreType childrenImageSharp___internal___mediaType childrenImageSharp___internal___owner childrenImageSharp___internal___type childrenImageSharp___original___height childrenImageSharp___original___src childrenImageSharp___original___width childrenImageSharp___parent___children childrenImageSharp___parent___children___children childrenImageSharp___parent___children___id childrenImageSharp___parent___id childrenImageSharp___parent___internal___content childrenImageSharp___parent___internal___contentDigest childrenImageSharp___parent___internal___description childrenImageSharp___parent___internal___fieldOwners childrenImageSharp___parent___internal___ignoreType childrenImageSharp___parent___internal___mediaType childrenImageSharp___parent___internal___owner childrenImageSharp___parent___internal___type childrenImageSharp___parent___parent___children childrenImageSharp___parent___parent___id childrenImageSharp___resize___aspectRatio childrenImageSharp___resize___height childrenImageSharp___resize___originalName childrenImageSharp___resize___src childrenImageSharp___resize___tracedSVG childrenImageSharp___resize___width children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id ctime ctimeMs dev dir ext extension gid hash id ino internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type mode modifiedTime mtime mtimeMs name nlink parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id prettySize publicURL rdev relativeDirectory relativePath root size sourceInstanceName uid } input FileFilterInput { absolutePath: StringQueryOperatorInput accessTime: DateQueryOperatorInput atime: DateQueryOperatorInput atimeMs: FloatQueryOperatorInput base: StringQueryOperatorInput birthTime: DateQueryOperatorInput birthtime: DateQueryOperatorInput birthtimeMs: FloatQueryOperatorInput blksize: IntQueryOperatorInput blocks: IntQueryOperatorInput changeTime: DateQueryOperatorInput childImageSharp: ImageSharpFilterInput children: NodeFilterListInput childrenImageSharp: ImageSharpFilterListInput ctime: DateQueryOperatorInput ctimeMs: FloatQueryOperatorInput dev: IntQueryOperatorInput dir: StringQueryOperatorInput ext: StringQueryOperatorInput extension: StringQueryOperatorInput gid: IntQueryOperatorInput hash: StringQueryOperatorInput id: StringQueryOperatorInput ino: FloatQueryOperatorInput internal: InternalFilterInput mode: IntQueryOperatorInput modifiedTime: DateQueryOperatorInput mtime: DateQueryOperatorInput mtimeMs: FloatQueryOperatorInput name: StringQueryOperatorInput nlink: IntQueryOperatorInput parent: NodeFilterInput prettySize: StringQueryOperatorInput publicURL: StringQueryOperatorInput rdev: IntQueryOperatorInput relativeDirectory: StringQueryOperatorInput relativePath: StringQueryOperatorInput root: StringQueryOperatorInput size: IntQueryOperatorInput sourceInstanceName: StringQueryOperatorInput uid: IntQueryOperatorInput } type FileGroupConnection { distinct(field: FileFieldsEnum!): [String!]! edges: [FileEdge!]! field: String! fieldValue: String group(field: FileFieldsEnum!, limit: Int, skip: Int): [FileGroupConnection!]! max(field: FileFieldsEnum!): Float min(field: FileFieldsEnum!): Float nodes: [File!]! pageInfo: PageInfo! sum(field: FileFieldsEnum!): Float totalCount: Int! } input FileSortInput { fields: [FileFieldsEnum] order: [SortOrderEnum] = [ASC] } input FloatQueryOperatorInput { eq: Float gt: Float gte: Float in: [Float] lt: Float lte: Float ne: Float nin: [Float] } enum GatsbyImageFormat { AUTO AVIF JPG NO_CHANGE PNG WEBP } enum GatsbyImageLayout { CONSTRAINED FIXED FULL_WIDTH } enum GatsbyImagePlaceholder { BLURRED DOMINANT_COLOR NONE TRACED_SVG } input IDQueryOperatorInput { eq: ID in: [ID] ne: ID nin: [ID] } enum ImageCropFocus { ATTENTION CENTER EAST ENTROPY NORTH NORTHEAST NORTHWEST SOUTH SOUTHEAST SOUTHWEST WEST } enum ImageFit { CONTAIN COVER FILL INSIDE OUTSIDE } enum ImageFormat { AUTO AVIF JPG NO_CHANGE PNG WEBP } enum ImageLayout { CONSTRAINED FIXED FULL_WIDTH } enum ImagePlaceholder { BLURRED DOMINANT_COLOR NONE TRACED_SVG } type ImageSharp implements Node { children: [Node!]! fixed( background: String = "rgba(0,0,0,1)" base64Width: Int cropFocus: ImageCropFocus = ATTENTION duotone: DuotoneGradient fit: ImageFit = COVER grayscale: Boolean = false height: Int jpegProgressive: Boolean = true jpegQuality: Int pngCompressionSpeed: Int = 4 pngQuality: Int quality: Int rotate: Int = 0 toFormat: ImageFormat = AUTO toFormatBase64: ImageFormat = AUTO traceSVG: Potrace trim: Float = 0 webpQuality: Int width: Int ): ImageSharpFixed fluid( background: String = "rgba(0,0,0,1)" base64Width: Int cropFocus: ImageCropFocus = ATTENTION duotone: DuotoneGradient fit: ImageFit = COVER grayscale: Boolean = false jpegProgressive: Boolean = true jpegQuality: Int maxHeight: Int maxWidth: Int pngCompressionSpeed: Int = 4 pngQuality: Int quality: Int rotate: Int = 0 sizes: String = "" """ A list of image widths to be generated. Example: [ 200, 340, 520, 890 ] """ srcSetBreakpoints: [Int] = [] toFormat: ImageFormat = AUTO toFormatBase64: ImageFormat = AUTO traceSVG: Potrace trim: Float = 0 webpQuality: Int ): ImageSharpFluid gatsbyImageData( """ If set along with width or height, this will set the value of the other dimension to match the provided aspect ratio, cropping the image if needed. If neither width or height is provided, height will be set based on the intrinsic width of the source image. """ aspectRatio: Float """ Options to pass to sharp when generating AVIF images. """ avifOptions: AVIFOptions """ Background color applied to the wrapper. Also passed to sharp to use as a background when "letterboxing" an image to another aspect ratio. """ backgroundColor: String """ Options for the low-resolution placeholder image. Set placeholder to "BLURRED" to use this """ blurredOptions: BlurredOptions """ Specifies the image widths to generate. For FIXED and CONSTRAINED images it is better to allow these to be determined automatically, based on the image size. For FULL_WIDTH images this can be used to override the default, which is [750, 1080, 1366, 1920]. It will never generate any images larger than the source. """ breakpoints: [Int] """ The image formats to generate. Valid values are "AUTO" (meaning the same format as the source image), "JPG", "PNG", "WEBP" and "AVIF". The default value is [AUTO, WEBP], and you should rarely need to change this. Take care if you specify JPG or PNG when you do not know the formats of the source images, as this could lead to unwanted results such as converting JPEGs to PNGs. Specifying both PNG and JPG is not supported and will be ignored. """ formats: [ImageFormat] """ The display height of the generated image for layout = FIXED, and the maximum display height of the largest image for layout = CONSTRAINED. The image will be cropped if the aspect ratio does not match the source image. If omitted, it is calculated from the supplied width, matching the aspect ratio of the source image. """ height: Int """ Options to pass to sharp when generating JPG images. """ jpgOptions: JPGOptions """ The layout for the image. FIXED: A static image sized, that does not resize according to the screen width FULL_WIDTH: The image resizes to fit its container. Pass a "sizes" option if it isn't going to be the full width of the screen. CONSTRAINED: Resizes to fit its container, up to a maximum width, at which point it will remain fixed in size. """ layout: ImageLayout = CONSTRAINED """ A list of image pixel densities to generate. It will never generate images larger than the source, and will always include a 1x image. Default is [ 1, 2 ] for FIXED images, meaning 1x and 2x and [0.25, 0.5, 1, 2] for CONSTRAINED. In this case, an image with a constrained layout and width = 400 would generate images at 100, 200, 400 and 800px wide. Ignored for FULL_WIDTH images, which use breakpoints instead """ outputPixelDensities: [Float] """ Format of generated placeholder image, displayed while the main image loads. BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. TRACED_SVG: a low-resolution traced SVG of the image. NONE: no placeholder. Set "background" to use a fixed background color. """ placeholder: ImagePlaceholder """ Options to pass to sharp when generating PNG images. """ pngOptions: PNGOptions """ The default quality. This is overridden by any format-specific options """ quality: Int """ The "sizes" property, passed to the img tag. This describes the display size of the image. This does not affect the generated images, but is used by the browser to decide which images to download. You should usually leave this blank, and a suitable value will be calculated. The exception is if a FULL_WIDTH image does not actually span the full width of the screen, in which case you should pass the correct size here. """ sizes: String """ Options for traced placeholder SVGs. You also should set placeholder to "TRACED_SVG". """ tracedSVGOptions: Potrace """ Options to pass to sharp to control cropping and other image manipulations. """ transformOptions: TransformOptions """ Options to pass to sharp when generating WebP images. """ webpOptions: WebPOptions """ The display width of the generated image for layout = FIXED, and the maximum display width of the largest image for layout = CONSTRAINED. Ignored if layout = FLUID. """ width: Int ): JSON! id: ID! internal: Internal! original: ImageSharpOriginal parent: Node resize( background: String = "rgba(0,0,0,1)" base64: Boolean = false cropFocus: ImageCropFocus = ATTENTION duotone: DuotoneGradient fit: ImageFit = COVER grayscale: Boolean = false height: Int jpegProgressive: Boolean = true jpegQuality: Int pngCompressionLevel: Int = 9 pngCompressionSpeed: Int = 4 pngQuality: Int quality: Int rotate: Int = 0 toFormat: ImageFormat = AUTO traceSVG: Potrace trim: Float = 0 webpQuality: Int width: Int ): ImageSharpResize } type ImageSharpConnection { distinct(field: ImageSharpFieldsEnum!): [String!]! edges: [ImageSharpEdge!]! group(field: ImageSharpFieldsEnum!, limit: Int, skip: Int): [ImageSharpGroupConnection!]! max(field: ImageSharpFieldsEnum!): Float min(field: ImageSharpFieldsEnum!): Float nodes: [ImageSharp!]! pageInfo: PageInfo! sum(field: ImageSharpFieldsEnum!): Float totalCount: Int! } type ImageSharpEdge { next: ImageSharp node: ImageSharp! previous: ImageSharp } enum ImageSharpFieldsEnum { children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id fixed___aspectRatio fixed___base64 fixed___height fixed___originalName fixed___src fixed___srcSet fixed___srcSetWebp fixed___srcWebp fixed___tracedSVG fixed___width fluid___aspectRatio fluid___base64 fluid___originalImg fluid___originalName fluid___presentationHeight fluid___presentationWidth fluid___sizes fluid___src fluid___srcSet fluid___srcSetWebp fluid___srcWebp fluid___tracedSVG gatsbyImageData id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type original___height original___src original___width parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id resize___aspectRatio resize___height resize___originalName resize___src resize___tracedSVG resize___width } input ImageSharpFilterInput { children: NodeFilterListInput fixed: ImageSharpFixedFilterInput fluid: ImageSharpFluidFilterInput gatsbyImageData: JSONQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput original: ImageSharpOriginalFilterInput parent: NodeFilterInput resize: ImageSharpResizeFilterInput } input ImageSharpFilterListInput { elemMatch: ImageSharpFilterInput } type ImageSharpFixed { aspectRatio: Float base64: String height: Float! originalName: String src: String! srcSet: String! srcSetWebp: String srcWebp: String tracedSVG: String width: Float! } input ImageSharpFixedFilterInput { aspectRatio: FloatQueryOperatorInput base64: StringQueryOperatorInput height: FloatQueryOperatorInput originalName: StringQueryOperatorInput src: StringQueryOperatorInput srcSet: StringQueryOperatorInput srcSetWebp: StringQueryOperatorInput srcWebp: StringQueryOperatorInput tracedSVG: StringQueryOperatorInput width: FloatQueryOperatorInput } type ImageSharpFluid { aspectRatio: Float! base64: String originalImg: String originalName: String presentationHeight: Int! presentationWidth: Int! sizes: String! src: String! srcSet: String! srcSetWebp: String srcWebp: String tracedSVG: String } input ImageSharpFluidFilterInput { aspectRatio: FloatQueryOperatorInput base64: StringQueryOperatorInput originalImg: StringQueryOperatorInput originalName: StringQueryOperatorInput presentationHeight: IntQueryOperatorInput presentationWidth: IntQueryOperatorInput sizes: StringQueryOperatorInput src: StringQueryOperatorInput srcSet: StringQueryOperatorInput srcSetWebp: StringQueryOperatorInput srcWebp: StringQueryOperatorInput tracedSVG: StringQueryOperatorInput } type ImageSharpGroupConnection { distinct(field: ImageSharpFieldsEnum!): [String!]! edges: [ImageSharpEdge!]! field: String! fieldValue: String group(field: ImageSharpFieldsEnum!, limit: Int, skip: Int): [ImageSharpGroupConnection!]! max(field: ImageSharpFieldsEnum!): Float min(field: ImageSharpFieldsEnum!): Float nodes: [ImageSharp!]! pageInfo: PageInfo! sum(field: ImageSharpFieldsEnum!): Float totalCount: Int! } type ImageSharpOriginal { height: Float src: String width: Float } input ImageSharpOriginalFilterInput { height: FloatQueryOperatorInput src: StringQueryOperatorInput width: FloatQueryOperatorInput } type ImageSharpResize { aspectRatio: Float height: Int originalName: String src: String tracedSVG: String width: Int } input ImageSharpResizeFilterInput { aspectRatio: FloatQueryOperatorInput height: IntQueryOperatorInput originalName: StringQueryOperatorInput src: StringQueryOperatorInput tracedSVG: StringQueryOperatorInput width: IntQueryOperatorInput } input ImageSharpSortInput { fields: [ImageSharpFieldsEnum] order: [SortOrderEnum] = [ASC] } input IntQueryOperatorInput { eq: Int gt: Int gte: Int in: [Int] lt: Int lte: Int ne: Int nin: [Int] } type Internal { content: String contentDigest: String! description: String fieldOwners: [String] ignoreType: Boolean mediaType: String owner: String! type: String! } input InternalFilterInput { content: StringQueryOperatorInput contentDigest: StringQueryOperatorInput description: StringQueryOperatorInput fieldOwners: StringQueryOperatorInput ignoreType: BooleanQueryOperatorInput mediaType: StringQueryOperatorInput owner: StringQueryOperatorInput type: StringQueryOperatorInput } input JPGOptions { progressive: Boolean = true quality: Int } """ The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). """ scalar JSON input JSONQueryOperatorInput { eq: JSON glob: JSON in: [JSON] ne: JSON nin: [JSON] regex: JSON } """ Node Interface """ interface Node { children: [Node!]! id: ID! internal: Internal! parent: Node } input NodeFilterInput { children: NodeFilterListInput id: StringQueryOperatorInput internal: InternalFilterInput parent: NodeFilterInput } input NodeFilterListInput { elemMatch: NodeFilterInput } input PNGOptions { compressionSpeed: Int = 4 quality: Int } type PageInfo { currentPage: Int! hasNextPage: Boolean! hasPreviousPage: Boolean! itemCount: Int! pageCount: Int! perPage: Int totalCount: Int! } input Potrace { alphaMax: Float background: String blackOnWhite: Boolean color: String optCurve: Boolean optTolerance: Float threshold: Int turdSize: Float turnPolicy: PotraceTurnPolicy } enum PotraceTurnPolicy { TURNPOLICY_BLACK TURNPOLICY_LEFT TURNPOLICY_MAJORITY TURNPOLICY_MINORITY TURNPOLICY_RIGHT TURNPOLICY_WHITE } type Query { allDirectory(filter: DirectoryFilterInput, limit: Int, skip: Int, sort: DirectorySortInput): DirectoryConnection! allFile(filter: FileFilterInput, limit: Int, skip: Int, sort: FileSortInput): FileConnection! allImageSharp(filter: ImageSharpFilterInput, limit: Int, skip: Int, sort: ImageSharpSortInput): ImageSharpConnection! allInternalEvents( filter: internal__eventsFilterInput limit: Int skip: Int sort: internal__eventsSortInput ): internal__eventsConnection! allSite(filter: SiteFilterInput, limit: Int, skip: Int, sort: SiteSortInput): SiteConnection! allSiteBuildMetadata( filter: SiteBuildMetadataFilterInput limit: Int skip: Int sort: SiteBuildMetadataSortInput ): SiteBuildMetadataConnection! allSiteFunction( filter: SiteFunctionFilterInput limit: Int skip: Int sort: SiteFunctionSortInput ): SiteFunctionConnection! allSitePage(filter: SitePageFilterInput, limit: Int, skip: Int, sort: SitePageSortInput): SitePageConnection! allSitePlugin(filter: SitePluginFilterInput, limit: Int, skip: Int, sort: SitePluginSortInput): SitePluginConnection! allWp(filter: WpFilterInput, limit: Int, skip: Int, sort: WpSortInput): WpConnection! allWpBlockEditorContentNode( filter: WpBlockEditorContentNodeFilterInput limit: Int skip: Int sort: WpBlockEditorContentNodeSortInput ): WpBlockEditorContentNodeConnection! allWpBlockEditorPreview( filter: WpBlockEditorPreviewFilterInput limit: Int skip: Int sort: WpBlockEditorPreviewSortInput ): WpBlockEditorPreviewConnection! allWpCategory(filter: WpCategoryFilterInput, limit: Int, skip: Int, sort: WpCategorySortInput): WpCategoryConnection! allWpComment(filter: WpCommentFilterInput, limit: Int, skip: Int, sort: WpCommentSortInput): WpCommentConnection! allWpCommentAuthor( filter: WpCommentAuthorFilterInput limit: Int skip: Int sort: WpCommentAuthorSortInput ): WpCommentAuthorConnection! allWpContentNode( filter: WpContentNodeFilterInput limit: Int skip: Int sort: WpContentNodeSortInput ): WpContentNodeConnection! allWpContentType( filter: WpContentTypeFilterInput limit: Int skip: Int sort: WpContentTypeSortInput ): WpContentTypeConnection! allWpMediaItem( filter: WpMediaItemFilterInput limit: Int skip: Int sort: WpMediaItemSortInput ): WpMediaItemConnection! allWpMenu(filter: WpMenuFilterInput, limit: Int, skip: Int, sort: WpMenuSortInput): WpMenuConnection! allWpMenuItem(filter: WpMenuItemFilterInput, limit: Int, skip: Int, sort: WpMenuItemSortInput): WpMenuItemConnection! allWpPage(filter: WpPageFilterInput, limit: Int, skip: Int, sort: WpPageSortInput): WpPageConnection! allWpPost(filter: WpPostFilterInput, limit: Int, skip: Int, sort: WpPostSortInput): WpPostConnection! allWpPostFormat( filter: WpPostFormatFilterInput limit: Int skip: Int sort: WpPostFormatSortInput ): WpPostFormatConnection! allWpReusableBlock( filter: WpReusableBlockFilterInput limit: Int skip: Int sort: WpReusableBlockSortInput ): WpReusableBlockConnection! allWpTag(filter: WpTagFilterInput, limit: Int, skip: Int, sort: WpTagSortInput): WpTagConnection! allWpTaxonomy(filter: WpTaxonomyFilterInput, limit: Int, skip: Int, sort: WpTaxonomySortInput): WpTaxonomyConnection! allWpTermNode(filter: WpTermNodeFilterInput, limit: Int, skip: Int, sort: WpTermNodeSortInput): WpTermNodeConnection! allWpUser(filter: WpUserFilterInput, limit: Int, skip: Int, sort: WpUserSortInput): WpUserConnection! allWpUserRole(filter: WpUserRoleFilterInput, limit: Int, skip: Int, sort: WpUserRoleSortInput): WpUserRoleConnection! directory( absolutePath: StringQueryOperatorInput accessTime: DateQueryOperatorInput atime: DateQueryOperatorInput atimeMs: FloatQueryOperatorInput base: StringQueryOperatorInput birthTime: DateQueryOperatorInput birthtime: DateQueryOperatorInput birthtimeMs: FloatQueryOperatorInput changeTime: DateQueryOperatorInput children: NodeFilterListInput ctime: DateQueryOperatorInput ctimeMs: FloatQueryOperatorInput dev: IntQueryOperatorInput dir: StringQueryOperatorInput ext: StringQueryOperatorInput extension: StringQueryOperatorInput gid: IntQueryOperatorInput id: StringQueryOperatorInput ino: FloatQueryOperatorInput internal: InternalFilterInput mode: IntQueryOperatorInput modifiedTime: DateQueryOperatorInput mtime: DateQueryOperatorInput mtimeMs: FloatQueryOperatorInput name: StringQueryOperatorInput nlink: IntQueryOperatorInput parent: NodeFilterInput prettySize: StringQueryOperatorInput rdev: IntQueryOperatorInput relativeDirectory: StringQueryOperatorInput relativePath: StringQueryOperatorInput root: StringQueryOperatorInput size: IntQueryOperatorInput sourceInstanceName: StringQueryOperatorInput uid: IntQueryOperatorInput ): Directory file( absolutePath: StringQueryOperatorInput accessTime: DateQueryOperatorInput atime: DateQueryOperatorInput atimeMs: FloatQueryOperatorInput base: StringQueryOperatorInput birthTime: DateQueryOperatorInput birthtime: DateQueryOperatorInput birthtimeMs: FloatQueryOperatorInput blksize: IntQueryOperatorInput blocks: IntQueryOperatorInput changeTime: DateQueryOperatorInput childImageSharp: ImageSharpFilterInput children: NodeFilterListInput childrenImageSharp: ImageSharpFilterListInput ctime: DateQueryOperatorInput ctimeMs: FloatQueryOperatorInput dev: IntQueryOperatorInput dir: StringQueryOperatorInput ext: StringQueryOperatorInput extension: StringQueryOperatorInput gid: IntQueryOperatorInput hash: StringQueryOperatorInput id: StringQueryOperatorInput ino: FloatQueryOperatorInput internal: InternalFilterInput mode: IntQueryOperatorInput modifiedTime: DateQueryOperatorInput mtime: DateQueryOperatorInput mtimeMs: FloatQueryOperatorInput name: StringQueryOperatorInput nlink: IntQueryOperatorInput parent: NodeFilterInput prettySize: StringQueryOperatorInput publicURL: StringQueryOperatorInput rdev: IntQueryOperatorInput relativeDirectory: StringQueryOperatorInput relativePath: StringQueryOperatorInput root: StringQueryOperatorInput size: IntQueryOperatorInput sourceInstanceName: StringQueryOperatorInput uid: IntQueryOperatorInput ): File imageSharp( children: NodeFilterListInput fixed: ImageSharpFixedFilterInput fluid: ImageSharpFluidFilterInput gatsbyImageData: JSONQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput original: ImageSharpOriginalFilterInput parent: NodeFilterInput resize: ImageSharpResizeFilterInput ): ImageSharp internalEvents( children: NodeFilterListInput events: internal__eventsEventsFilterListInput id: StringQueryOperatorInput internal: InternalFilterInput next_rest_url: StringQueryOperatorInput parent: NodeFilterInput previous_rest_url: StringQueryOperatorInput rest_url: StringQueryOperatorInput total: IntQueryOperatorInput total_pages: IntQueryOperatorInput ): internal__events site( buildTime: DateQueryOperatorInput children: NodeFilterListInput host: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput jsxRuntime: StringQueryOperatorInput parent: NodeFilterInput pathPrefix: StringQueryOperatorInput polyfill: BooleanQueryOperatorInput port: IntQueryOperatorInput siteMetadata: SiteSiteMetadataFilterInput trailingSlash: StringQueryOperatorInput ): Site siteBuildMetadata( buildTime: DateQueryOperatorInput children: NodeFilterListInput id: StringQueryOperatorInput internal: InternalFilterInput parent: NodeFilterInput ): SiteBuildMetadata siteFunction( absoluteCompiledFilePath: StringQueryOperatorInput children: NodeFilterListInput functionRoute: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput matchPath: StringQueryOperatorInput originalAbsoluteFilePath: StringQueryOperatorInput originalRelativeFilePath: StringQueryOperatorInput parent: NodeFilterInput pluginName: StringQueryOperatorInput relativeCompiledFilePath: StringQueryOperatorInput ): SiteFunction sitePage( children: NodeFilterListInput component: StringQueryOperatorInput componentChunkName: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput internalComponentName: StringQueryOperatorInput matchPath: StringQueryOperatorInput pageContext: JSONQueryOperatorInput parent: NodeFilterInput path: StringQueryOperatorInput pluginCreator: SitePluginFilterInput ): SitePage sitePlugin( browserAPIs: StringQueryOperatorInput children: NodeFilterListInput id: StringQueryOperatorInput internal: InternalFilterInput name: StringQueryOperatorInput nodeAPIs: StringQueryOperatorInput packageJson: JSONQueryOperatorInput parent: NodeFilterInput pluginFilepath: StringQueryOperatorInput pluginOptions: JSONQueryOperatorInput resolve: StringQueryOperatorInput ssrAPIs: StringQueryOperatorInput version: StringQueryOperatorInput ): SitePlugin wp( allSettings: WpSettingsFilterInput children: NodeFilterListInput discussionSettings: WpDiscussionSettingsFilterInput generalSettings: WpGeneralSettingsFilterInput id: StringQueryOperatorInput internal: InternalFilterInput nodeType: StringQueryOperatorInput parent: NodeFilterInput readingSettings: WpReadingSettingsFilterInput wpGatsby: WpWPGatsbyFilterInput writingSettings: WpWritingSettingsFilterInput ): Wp wpBlockEditorContentNode( blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput children: NodeFilterListInput id: StringQueryOperatorInput internal: InternalFilterInput nodeType: StringQueryOperatorInput parent: NodeFilterInput previewBlocks: WpBlockFilterListInput previewBlocksJSON: StringQueryOperatorInput ): WpBlockEditorContentNode wpBlockEditorPreview( author: WpNodeWithAuthorToUserConnectionEdgeFilterInput authorDatabaseId: IntQueryOperatorInput authorId: IDQueryOperatorInput blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput children: NodeFilterListInput content: StringQueryOperatorInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput lastUpdateTime: StringQueryOperatorInput link: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput previewed: WpBlockEditorContentNodeFilterInput previewedDatabaseId: IntQueryOperatorInput previewedParentDatabaseId: IntQueryOperatorInput slug: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput title: StringQueryOperatorInput uri: StringQueryOperatorInput ): WpBlockEditorPreview wpCategory( ancestors: WpCategoryToAncestorsCategoryConnectionFilterInput children: NodeFilterListInput contentNodes: WpCategoryToContentNodeConnectionFilterInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput link: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput posts: WpCategoryToPostConnectionFilterInput slug: StringQueryOperatorInput taxonomy: WpCategoryToTaxonomyConnectionEdgeFilterInput taxonomyName: StringQueryOperatorInput termGroupId: IntQueryOperatorInput termTaxonomyId: IntQueryOperatorInput uri: StringQueryOperatorInput wpChildren: WpCategoryToCategoryConnectionFilterInput wpParent: WpCategoryToParentCategoryConnectionEdgeFilterInput ): WpCategory wpComment( agent: StringQueryOperatorInput approved: BooleanQueryOperatorInput author: WpCommentToCommenterConnectionEdgeFilterInput authorIp: StringQueryOperatorInput children: NodeFilterListInput commentedOn: WpCommentToContentNodeConnectionEdgeFilterInput content: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput karma: IntQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput replies: WpCommentToCommentConnectionFilterInput type: StringQueryOperatorInput wpParent: WpCommentToParentCommentConnectionEdgeFilterInput ): WpComment wpCommentAuthor( avatar: WpAvatarFilterInput children: NodeFilterListInput databaseId: IntQueryOperatorInput email: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput url: StringQueryOperatorInput ): WpCommentAuthor wpContentNode( children: NodeFilterListInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput slug: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput uri: StringQueryOperatorInput ): WpContentNode wpContentType( archivePath: StringQueryOperatorInput canExport: BooleanQueryOperatorInput children: NodeFilterListInput connectedTaxonomies: WpContentTypeToTaxonomyConnectionFilterInput contentNodes: WpContentTypeToContentNodeConnectionFilterInput deleteWithUser: BooleanQueryOperatorInput description: StringQueryOperatorInput excludeFromSearch: BooleanQueryOperatorInput graphqlPluralName: StringQueryOperatorInput graphqlSingleName: StringQueryOperatorInput hasArchive: BooleanQueryOperatorInput hierarchical: BooleanQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isFrontPage: BooleanQueryOperatorInput isPostsPage: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput label: StringQueryOperatorInput labels: WpPostTypeLabelDetailsFilterInput menuIcon: StringQueryOperatorInput menuPosition: IntQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput public: BooleanQueryOperatorInput publiclyQueryable: BooleanQueryOperatorInput restBase: StringQueryOperatorInput restControllerClass: StringQueryOperatorInput showInAdminBar: BooleanQueryOperatorInput showInGraphql: BooleanQueryOperatorInput showInMenu: BooleanQueryOperatorInput showInNavMenus: BooleanQueryOperatorInput showInRest: BooleanQueryOperatorInput showUi: BooleanQueryOperatorInput uri: StringQueryOperatorInput ): WpContentType wpMediaItem( altText: StringQueryOperatorInput ancestors: WpHierarchicalContentNodeToContentNodeAncestorsConnectionFilterInput author: WpNodeWithAuthorToUserConnectionEdgeFilterInput authorDatabaseId: IntQueryOperatorInput authorId: IDQueryOperatorInput caption: StringQueryOperatorInput children: NodeFilterListInput commentCount: IntQueryOperatorInput commentStatus: StringQueryOperatorInput comments: WpMediaItemToCommentConnectionFilterInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput description: StringQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput fileSize: IntQueryOperatorInput filename: StringQueryOperatorInput filesize: IntQueryOperatorInput gatsbyImage: JSONQueryOperatorInput guid: StringQueryOperatorInput height: IntQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput localFile: FileFilterInput mediaDetails: WpMediaDetailsFilterInput mediaItemUrl: StringQueryOperatorInput mediaType: StringQueryOperatorInput mimeType: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput publicUrl: StringQueryOperatorInput remoteFile: FileFilterInput resize: RemoteFileResizeFilterInput sizes: StringQueryOperatorInput slug: StringQueryOperatorInput sourceUrl: StringQueryOperatorInput srcSet: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput title: StringQueryOperatorInput uri: StringQueryOperatorInput width: IntQueryOperatorInput wpChildren: WpHierarchicalContentNodeToContentNodeChildrenConnectionFilterInput wpParent: WpHierarchicalContentNodeToParentContentNodeConnectionEdgeFilterInput ): WpMediaItem wpMenu( children: NodeFilterListInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput locations: WpMenuLocationEnumQueryOperatorInput menuItems: WpMenuToMenuItemConnectionFilterInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput slug: StringQueryOperatorInput ): WpMenu wpMenuItem( childItems: WpMenuItemToMenuItemConnectionFilterInput children: NodeFilterListInput connectedNode: WpMenuItemToMenuItemLinkableConnectionEdgeFilterInput cssClasses: StringQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput label: StringQueryOperatorInput linkRelationship: StringQueryOperatorInput locations: WpMenuLocationEnumQueryOperatorInput menu: WpMenuItemToMenuConnectionEdgeFilterInput nodeType: StringQueryOperatorInput order: IntQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput path: StringQueryOperatorInput target: StringQueryOperatorInput title: StringQueryOperatorInput url: StringQueryOperatorInput ): WpMenuItem wpPage( ancestors: WpHierarchicalContentNodeToContentNodeAncestorsConnectionFilterInput author: WpNodeWithAuthorToUserConnectionEdgeFilterInput authorDatabaseId: IntQueryOperatorInput authorId: IDQueryOperatorInput blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput children: NodeFilterListInput commentCount: IntQueryOperatorInput commentStatus: StringQueryOperatorInput comments: WpPageToCommentConnectionFilterInput content: StringQueryOperatorInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput featuredImage: WpNodeWithFeaturedImageToMediaItemConnectionEdgeFilterInput featuredImageDatabaseId: IntQueryOperatorInput featuredImageId: IDQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isFrontPage: BooleanQueryOperatorInput isPostsPage: BooleanQueryOperatorInput isPrivacyPage: BooleanQueryOperatorInput isRevision: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput menuOrder: IntQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput previewBlocks: WpBlockFilterListInput previewBlocksJSON: StringQueryOperatorInput slug: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput title: StringQueryOperatorInput uri: StringQueryOperatorInput wpChildren: WpHierarchicalContentNodeToContentNodeChildrenConnectionFilterInput wpParent: WpHierarchicalContentNodeToParentContentNodeConnectionEdgeFilterInput ): WpPage wpPost( author: WpNodeWithAuthorToUserConnectionEdgeFilterInput authorDatabaseId: IntQueryOperatorInput authorId: IDQueryOperatorInput blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput categories: WpPostToCategoryConnectionFilterInput children: NodeFilterListInput commentCount: IntQueryOperatorInput commentStatus: StringQueryOperatorInput comments: WpPostToCommentConnectionFilterInput content: StringQueryOperatorInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput excerpt: StringQueryOperatorInput featuredImage: WpNodeWithFeaturedImageToMediaItemConnectionEdgeFilterInput featuredImageDatabaseId: IntQueryOperatorInput featuredImageId: IDQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isRevision: BooleanQueryOperatorInput isSticky: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput pingStatus: StringQueryOperatorInput pinged: StringQueryOperatorInput postFormats: WpPostToPostFormatConnectionFilterInput previewBlocks: WpBlockFilterListInput previewBlocksJSON: StringQueryOperatorInput slug: StringQueryOperatorInput status: StringQueryOperatorInput tags: WpPostToTagConnectionFilterInput template: WpContentTemplateFilterInput terms: WpPostToTermNodeConnectionFilterInput title: StringQueryOperatorInput toPing: StringQueryOperatorInput uri: StringQueryOperatorInput ): WpPost wpPostFormat( children: NodeFilterListInput contentNodes: WpPostFormatToContentNodeConnectionFilterInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput link: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput posts: WpPostFormatToPostConnectionFilterInput slug: StringQueryOperatorInput taxonomy: WpPostFormatToTaxonomyConnectionEdgeFilterInput taxonomyName: StringQueryOperatorInput termGroupId: IntQueryOperatorInput termTaxonomyId: IntQueryOperatorInput uri: StringQueryOperatorInput ): WpPostFormat wpReusableBlock( blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput children: NodeFilterListInput content: StringQueryOperatorInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isRevision: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput previewBlocks: WpBlockFilterListInput previewBlocksJSON: StringQueryOperatorInput slug: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput title: StringQueryOperatorInput uri: StringQueryOperatorInput ): WpReusableBlock wpTag( children: NodeFilterListInput contentNodes: WpTagToContentNodeConnectionFilterInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput link: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput posts: WpTagToPostConnectionFilterInput slug: StringQueryOperatorInput taxonomy: WpTagToTaxonomyConnectionEdgeFilterInput taxonomyName: StringQueryOperatorInput termGroupId: IntQueryOperatorInput termTaxonomyId: IntQueryOperatorInput uri: StringQueryOperatorInput ): WpTag wpTaxonomy( archivePath: StringQueryOperatorInput children: NodeFilterListInput connectedContentTypes: WpTaxonomyToContentTypeConnectionFilterInput description: StringQueryOperatorInput graphqlPluralName: StringQueryOperatorInput graphqlSingleName: StringQueryOperatorInput hierarchical: BooleanQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput label: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput public: BooleanQueryOperatorInput restBase: StringQueryOperatorInput restControllerClass: StringQueryOperatorInput showCloud: BooleanQueryOperatorInput showInAdminColumn: BooleanQueryOperatorInput showInGraphql: BooleanQueryOperatorInput showInMenu: BooleanQueryOperatorInput showInNavMenus: BooleanQueryOperatorInput showInQuickEdit: BooleanQueryOperatorInput showInRest: BooleanQueryOperatorInput showUi: BooleanQueryOperatorInput ): WpTaxonomy wpTermNode( children: NodeFilterListInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput link: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput slug: StringQueryOperatorInput taxonomyName: StringQueryOperatorInput termGroupId: IntQueryOperatorInput termTaxonomyId: IntQueryOperatorInput uri: StringQueryOperatorInput ): WpTermNode wpUser( avatar: WpAvatarFilterInput blockEditorPreviews: WpUserToBlockEditorPreviewConnectionFilterInput capKey: StringQueryOperatorInput capabilities: StringQueryOperatorInput children: NodeFilterListInput comments: WpUserToCommentConnectionFilterInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput email: StringQueryOperatorInput extraCapabilities: StringQueryOperatorInput firstName: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastName: StringQueryOperatorInput locale: StringQueryOperatorInput name: StringQueryOperatorInput nicename: StringQueryOperatorInput nickname: StringQueryOperatorInput nodeType: StringQueryOperatorInput pages: WpUserToPageConnectionFilterInput parent: NodeFilterInput posts: WpUserToPostConnectionFilterInput registeredDate: StringQueryOperatorInput roles: WpUserToUserRoleConnectionFilterInput slug: StringQueryOperatorInput uri: StringQueryOperatorInput url: StringQueryOperatorInput username: StringQueryOperatorInput ): WpUser wpUserRole( capabilities: StringQueryOperatorInput children: NodeFilterListInput displayName: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput ): WpUserRole } """ Remote Interface """ interface RemoteFile { filename: String! filesize: Int """ Data used in the component. See https://gatsby.dev/img for more info. """ gatsbyImage( """ If set along with width or height, this will set the value of the other dimension to match the provided aspect ratio, cropping the image if needed. If neither width or height is provided, height will be set based on the intrinsic width of the source image. """ aspectRatio: Float """ Background color applied to the wrapper, or when "letterboxing" an image to another aspect ratio. """ backgroundColor: String """ Specifies the image widths to generate. You should rarely need to change this. For FIXED and CONSTRAINED images it is better to allow these to be determined automatically, based on the image size. For FULL_WIDTH images this can be used to override the default, which is [750, 1080, 1366, 1920]. It will never generate any images larger than the source. """ breakpoints: [Int] = [750, 1080, 1366, 1920] cropFocus: [RemoteFileCropFocus] fit: RemoteFileFit = COVER """ The image formats to generate. Valid values are AUTO (meaning the same format as the source image), JPG, PNG, WEBP and AVIF. The default value is [AUTO, WEBP, AVIF], and you should rarely need to change this. Take care if you specify JPG or PNG when you do not know the formats of the source images, as this could lead to unwanted results such as converting JPEGs to PNGs. Specifying both PNG and JPG is not supported and will be ignored. """ formats: [RemoteFileFormat!] = [AUTO, WEBP, AVIF] """ If set, the height of the generated image. If omitted, it is calculated from the supplied width, matching the aspect ratio of the source image. """ height: Int """ The layout for the image. FIXED: A static image sized, that does not resize according to the screen width FULL_WIDTH: The image resizes to fit its container. Pass a "sizes" option if it isn't going to be the full width of the screen. CONSTRAINED: Resizes to fit its container, up to a maximum width, at which point it will remain fixed in size. """ layout: RemoteFileLayout = CONSTRAINED """ A list of image pixel densities to generate for FIXED and CONSTRAINED images. You should rarely need to change this. It will never generate images larger than the source, and will always include a 1x image. Default is [ 1, 2 ] for fixed images, meaning 1x, 2x, and [0.25, 0.5, 1, 2] for fluid. In this case, an image with a fluid layout and width = 400 would generate images at 100, 200, 400 and 800px wide. """ outputPixelDensities: [Float] = [0.25, 0.5, 1, 2] """ Format of generated placeholder image, displayed while the main image loads. BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. TRACED_SVG: a low-resolution traced SVG of the image. NONE: no placeholder. Set the argument "backgroundColor" to use a fixed background color. """ placeholder: RemoteFilePlaceholder = DOMINANT_COLOR quality: Int = 75 """ The "sizes" property, passed to the img tag. This describes the display size of the image. This does not affect the generated images, but is used by the browser to decide which images to download. You can leave this blank for fixed images, or if the responsive image container will be the full width of the screen. In these cases we will generate an appropriate value. """ sizes: String """ The display width of the generated image for layout = FIXED, and the display width of the largest image for layout = CONSTRAINED. The actual largest image resolution will be this value multiplied by the largest value in outputPixelDensities Ignored if layout = FLUID. """ width: Int ): JSON height: Int id: ID! mimeType: String! publicUrl: String! resize( cropFocus: [RemoteFileCropFocus] fit: RemoteFileFit = COVER """ The image formats to generate. Valid values are AUTO (meaning the same format as the source image), JPG, PNG, WEBP and AVIF. The default value is [AUTO, WEBP, AVIF], and you should rarely need to change this. Take care if you specify JPG or PNG when you do not know the formats of the source images, as this could lead to unwanted results such as converting JPEGs to PNGs. Specifying both PNG and JPG is not supported and will be ignored. """ format: RemoteFileFormat = AUTO height: Int quality: Int = 75 width: Int ): RemoteFileResize width: Int } enum RemoteFileCropFocus { BOTTOM CENTER EDGES ENTROPY FACES LEFT RIGHT TOP } enum RemoteFileFit { CONTAIN COVER FILL OUTSIDE } enum RemoteFileFormat { AUTO AVIF JPG PNG WEBP } enum RemoteFileLayout { CONSTRAINED FIXED FULL_WIDTH } enum RemoteFilePlaceholder { BLURRED DOMINANT_COLOR NONE } type RemoteFileResize { height: Int src: String width: Int } input RemoteFileResizeFilterInput { height: IntQueryOperatorInput src: StringQueryOperatorInput width: IntQueryOperatorInput } type Site implements Node { buildTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date children: [Node!]! host: String id: ID! internal: Internal! jsxRuntime: String parent: Node pathPrefix: String polyfill: Boolean port: Int siteMetadata: SiteSiteMetadata trailingSlash: String } type SiteBuildMetadata implements Node { buildTime( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date children: [Node!]! id: ID! internal: Internal! parent: Node } type SiteBuildMetadataConnection { distinct(field: SiteBuildMetadataFieldsEnum!): [String!]! edges: [SiteBuildMetadataEdge!]! group(field: SiteBuildMetadataFieldsEnum!, limit: Int, skip: Int): [SiteBuildMetadataGroupConnection!]! max(field: SiteBuildMetadataFieldsEnum!): Float min(field: SiteBuildMetadataFieldsEnum!): Float nodes: [SiteBuildMetadata!]! pageInfo: PageInfo! sum(field: SiteBuildMetadataFieldsEnum!): Float totalCount: Int! } type SiteBuildMetadataEdge { next: SiteBuildMetadata node: SiteBuildMetadata! previous: SiteBuildMetadata } enum SiteBuildMetadataFieldsEnum { buildTime children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id } input SiteBuildMetadataFilterInput { buildTime: DateQueryOperatorInput children: NodeFilterListInput id: StringQueryOperatorInput internal: InternalFilterInput parent: NodeFilterInput } type SiteBuildMetadataGroupConnection { distinct(field: SiteBuildMetadataFieldsEnum!): [String!]! edges: [SiteBuildMetadataEdge!]! field: String! fieldValue: String group(field: SiteBuildMetadataFieldsEnum!, limit: Int, skip: Int): [SiteBuildMetadataGroupConnection!]! max(field: SiteBuildMetadataFieldsEnum!): Float min(field: SiteBuildMetadataFieldsEnum!): Float nodes: [SiteBuildMetadata!]! pageInfo: PageInfo! sum(field: SiteBuildMetadataFieldsEnum!): Float totalCount: Int! } input SiteBuildMetadataSortInput { fields: [SiteBuildMetadataFieldsEnum] order: [SortOrderEnum] = [ASC] } type SiteConnection { distinct(field: SiteFieldsEnum!): [String!]! edges: [SiteEdge!]! group(field: SiteFieldsEnum!, limit: Int, skip: Int): [SiteGroupConnection!]! max(field: SiteFieldsEnum!): Float min(field: SiteFieldsEnum!): Float nodes: [Site!]! pageInfo: PageInfo! sum(field: SiteFieldsEnum!): Float totalCount: Int! } type SiteEdge { next: Site node: Site! previous: Site } enum SiteFieldsEnum { buildTime children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id host id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type jsxRuntime parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id pathPrefix polyfill port siteMetadata___description siteMetadata___title trailingSlash } input SiteFilterInput { buildTime: DateQueryOperatorInput children: NodeFilterListInput host: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput jsxRuntime: StringQueryOperatorInput parent: NodeFilterInput pathPrefix: StringQueryOperatorInput polyfill: BooleanQueryOperatorInput port: IntQueryOperatorInput siteMetadata: SiteSiteMetadataFilterInput trailingSlash: StringQueryOperatorInput } type SiteFunction implements Node { absoluteCompiledFilePath: String! children: [Node!]! functionRoute: String! id: ID! internal: Internal! matchPath: String originalAbsoluteFilePath: String! originalRelativeFilePath: String! parent: Node pluginName: String! relativeCompiledFilePath: String! } type SiteFunctionConnection { distinct(field: SiteFunctionFieldsEnum!): [String!]! edges: [SiteFunctionEdge!]! group(field: SiteFunctionFieldsEnum!, limit: Int, skip: Int): [SiteFunctionGroupConnection!]! max(field: SiteFunctionFieldsEnum!): Float min(field: SiteFunctionFieldsEnum!): Float nodes: [SiteFunction!]! pageInfo: PageInfo! sum(field: SiteFunctionFieldsEnum!): Float totalCount: Int! } type SiteFunctionEdge { next: SiteFunction node: SiteFunction! previous: SiteFunction } enum SiteFunctionFieldsEnum { absoluteCompiledFilePath children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id functionRoute id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type matchPath originalAbsoluteFilePath originalRelativeFilePath parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id pluginName relativeCompiledFilePath } input SiteFunctionFilterInput { absoluteCompiledFilePath: StringQueryOperatorInput children: NodeFilterListInput functionRoute: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput matchPath: StringQueryOperatorInput originalAbsoluteFilePath: StringQueryOperatorInput originalRelativeFilePath: StringQueryOperatorInput parent: NodeFilterInput pluginName: StringQueryOperatorInput relativeCompiledFilePath: StringQueryOperatorInput } type SiteFunctionGroupConnection { distinct(field: SiteFunctionFieldsEnum!): [String!]! edges: [SiteFunctionEdge!]! field: String! fieldValue: String group(field: SiteFunctionFieldsEnum!, limit: Int, skip: Int): [SiteFunctionGroupConnection!]! max(field: SiteFunctionFieldsEnum!): Float min(field: SiteFunctionFieldsEnum!): Float nodes: [SiteFunction!]! pageInfo: PageInfo! sum(field: SiteFunctionFieldsEnum!): Float totalCount: Int! } input SiteFunctionSortInput { fields: [SiteFunctionFieldsEnum] order: [SortOrderEnum] = [ASC] } type SiteGroupConnection { distinct(field: SiteFieldsEnum!): [String!]! edges: [SiteEdge!]! field: String! fieldValue: String group(field: SiteFieldsEnum!, limit: Int, skip: Int): [SiteGroupConnection!]! max(field: SiteFieldsEnum!): Float min(field: SiteFieldsEnum!): Float nodes: [Site!]! pageInfo: PageInfo! sum(field: SiteFieldsEnum!): Float totalCount: Int! } type SitePage implements Node { children: [Node!]! component: String! componentChunkName: String! id: ID! internal: Internal! internalComponentName: String! matchPath: String pageContext: JSON parent: Node path: String! pluginCreator: SitePlugin } type SitePageConnection { distinct(field: SitePageFieldsEnum!): [String!]! edges: [SitePageEdge!]! group(field: SitePageFieldsEnum!, limit: Int, skip: Int): [SitePageGroupConnection!]! max(field: SitePageFieldsEnum!): Float min(field: SitePageFieldsEnum!): Float nodes: [SitePage!]! pageInfo: PageInfo! sum(field: SitePageFieldsEnum!): Float totalCount: Int! } type SitePageEdge { next: SitePage node: SitePage! previous: SitePage } enum SitePageFieldsEnum { children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id component componentChunkName id internalComponentName internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type matchPath pageContext parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id path pluginCreator___browserAPIs pluginCreator___children pluginCreator___children___children pluginCreator___children___children___children pluginCreator___children___children___id pluginCreator___children___id pluginCreator___children___internal___content pluginCreator___children___internal___contentDigest pluginCreator___children___internal___description pluginCreator___children___internal___fieldOwners pluginCreator___children___internal___ignoreType pluginCreator___children___internal___mediaType pluginCreator___children___internal___owner pluginCreator___children___internal___type pluginCreator___children___parent___children pluginCreator___children___parent___id pluginCreator___id pluginCreator___internal___content pluginCreator___internal___contentDigest pluginCreator___internal___description pluginCreator___internal___fieldOwners pluginCreator___internal___ignoreType pluginCreator___internal___mediaType pluginCreator___internal___owner pluginCreator___internal___type pluginCreator___name pluginCreator___nodeAPIs pluginCreator___packageJson pluginCreator___parent___children pluginCreator___parent___children___children pluginCreator___parent___children___id pluginCreator___parent___id pluginCreator___parent___internal___content pluginCreator___parent___internal___contentDigest pluginCreator___parent___internal___description pluginCreator___parent___internal___fieldOwners pluginCreator___parent___internal___ignoreType pluginCreator___parent___internal___mediaType pluginCreator___parent___internal___owner pluginCreator___parent___internal___type pluginCreator___parent___parent___children pluginCreator___parent___parent___id pluginCreator___pluginFilepath pluginCreator___pluginOptions pluginCreator___resolve pluginCreator___ssrAPIs pluginCreator___version } input SitePageFilterInput { children: NodeFilterListInput component: StringQueryOperatorInput componentChunkName: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput internalComponentName: StringQueryOperatorInput matchPath: StringQueryOperatorInput pageContext: JSONQueryOperatorInput parent: NodeFilterInput path: StringQueryOperatorInput pluginCreator: SitePluginFilterInput } type SitePageGroupConnection { distinct(field: SitePageFieldsEnum!): [String!]! edges: [SitePageEdge!]! field: String! fieldValue: String group(field: SitePageFieldsEnum!, limit: Int, skip: Int): [SitePageGroupConnection!]! max(field: SitePageFieldsEnum!): Float min(field: SitePageFieldsEnum!): Float nodes: [SitePage!]! pageInfo: PageInfo! sum(field: SitePageFieldsEnum!): Float totalCount: Int! } input SitePageSortInput { fields: [SitePageFieldsEnum] order: [SortOrderEnum] = [ASC] } type SitePlugin implements Node { browserAPIs: [String] children: [Node!]! id: ID! internal: Internal! name: String nodeAPIs: [String] packageJson: JSON parent: Node pluginFilepath: String pluginOptions: JSON resolve: String ssrAPIs: [String] version: String } type SitePluginConnection { distinct(field: SitePluginFieldsEnum!): [String!]! edges: [SitePluginEdge!]! group(field: SitePluginFieldsEnum!, limit: Int, skip: Int): [SitePluginGroupConnection!]! max(field: SitePluginFieldsEnum!): Float min(field: SitePluginFieldsEnum!): Float nodes: [SitePlugin!]! pageInfo: PageInfo! sum(field: SitePluginFieldsEnum!): Float totalCount: Int! } type SitePluginEdge { next: SitePlugin node: SitePlugin! previous: SitePlugin } enum SitePluginFieldsEnum { browserAPIs children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type name nodeAPIs packageJson parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id pluginFilepath pluginOptions resolve ssrAPIs version } input SitePluginFilterInput { browserAPIs: StringQueryOperatorInput children: NodeFilterListInput id: StringQueryOperatorInput internal: InternalFilterInput name: StringQueryOperatorInput nodeAPIs: StringQueryOperatorInput packageJson: JSONQueryOperatorInput parent: NodeFilterInput pluginFilepath: StringQueryOperatorInput pluginOptions: JSONQueryOperatorInput resolve: StringQueryOperatorInput ssrAPIs: StringQueryOperatorInput version: StringQueryOperatorInput } type SitePluginGroupConnection { distinct(field: SitePluginFieldsEnum!): [String!]! edges: [SitePluginEdge!]! field: String! fieldValue: String group(field: SitePluginFieldsEnum!, limit: Int, skip: Int): [SitePluginGroupConnection!]! max(field: SitePluginFieldsEnum!): Float min(field: SitePluginFieldsEnum!): Float nodes: [SitePlugin!]! pageInfo: PageInfo! sum(field: SitePluginFieldsEnum!): Float totalCount: Int! } input SitePluginSortInput { fields: [SitePluginFieldsEnum] order: [SortOrderEnum] = [ASC] } type SiteSiteMetadata { description: String title: String } input SiteSiteMetadataFilterInput { description: StringQueryOperatorInput title: StringQueryOperatorInput } input SiteSortInput { fields: [SiteFieldsEnum] order: [SortOrderEnum] = [ASC] } enum SortOrderEnum { ASC DESC } input StringQueryOperatorInput { eq: String glob: String in: [String] ne: String nin: [String] regex: String } input TransformOptions { cropFocus: ImageCropFocus = ATTENTION duotone: DuotoneGradient fit: ImageFit = COVER grayscale: Boolean = false rotate: Int = 0 trim: Float = 0 } input WebPOptions { quality: Int } """ Non-node WPGraphQL root fields. """ type Wp implements Node { """ Entry point to get all settings for the site """ allSettings: WpSettings children: [Node!]! """ Fields of the 'DiscussionSettings' settings group """ discussionSettings: WpDiscussionSettings """ Fields of the 'GeneralSettings' settings group """ generalSettings: WpGeneralSettings id: ID! internal: Internal! nodeType: String parent: Node """ Fields of the 'ReadingSettings' settings group """ readingSettings: WpReadingSettings """ Information needed by gatsby-source-wordpress. """ wpGatsby: WpWPGatsby """ Fields of the 'WritingSettings' settings group """ writingSettings: WpWritingSettings } """ Avatars are profile images for users. WordPress by default uses the Gravatar service to host and fetch avatars from. """ type WpAvatar { """ URL for the default image or a default type. Accepts '404' (return a 404 instead of a default image), 'retro' (8bit), 'monsterid' (monster), 'wavatar' (cartoon face), 'indenticon' (the 'quilt'), 'mystery', 'mm', or 'mysteryman' (The Oyster Man), 'blank' (transparent GIF), or 'gravatar_default' (the Gravatar logo). """ default: String """ HTML attributes to insert in the IMG element. Is not sanitized. """ extraAttr: String """ Whether to always show the default image, never the Gravatar. """ forceDefault: Boolean """ Whether the avatar was successfully found. """ foundAvatar: Boolean """ Height of the avatar image. """ height: Int """ What rating to display avatars up to. Accepts 'G', 'PG', 'R', 'X', and are judged in that order. """ rating: String """ Type of url scheme to use. Typically HTTP vs. HTTPS. """ scheme: String """ The size of the avatar in pixels. A value of 96 will match a 96px x 96px gravatar image. """ size: Int """ URL for the gravatar image source. """ url: String """ Width of the avatar image. """ width: Int } input WpAvatarFilterInput { default: StringQueryOperatorInput extraAttr: StringQueryOperatorInput forceDefault: BooleanQueryOperatorInput foundAvatar: BooleanQueryOperatorInput height: IntQueryOperatorInput rating: StringQueryOperatorInput scheme: StringQueryOperatorInput size: IntQueryOperatorInput url: StringQueryOperatorInput width: IntQueryOperatorInput } interface WpBlock { """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpBlockAttributesObject { foobar: String } interface WpBlockEditorContentNode implements Node { """ Gutenberg blocks """ blocks: [WpBlock!] """ Gutenberg blocks as json string """ blocksJSON: String children: [Node!]! id: ID! internal: Internal! nodeType: String parent: Node """ Previewed gutenberg blocks """ previewBlocks: [WpBlock!] """ Previewed Gutenberg blocks as json string """ previewBlocksJSON: String } type WpBlockEditorContentNodeConnection { distinct(field: WpBlockEditorContentNodeFieldsEnum!): [String!]! edges: [WpBlockEditorContentNodeEdge!]! group(field: WpBlockEditorContentNodeFieldsEnum!, limit: Int, skip: Int): [WpBlockEditorContentNodeGroupConnection!]! max(field: WpBlockEditorContentNodeFieldsEnum!): Float min(field: WpBlockEditorContentNodeFieldsEnum!): Float nodes: [WpBlockEditorContentNode!]! pageInfo: PageInfo! sum(field: WpBlockEditorContentNodeFieldsEnum!): Float totalCount: Int! } type WpBlockEditorContentNodeEdge { next: WpBlockEditorContentNode node: WpBlockEditorContentNode! previous: WpBlockEditorContentNode } enum WpBlockEditorContentNodeFieldsEnum { blocks blocksJSON blocks___attributesJSON blocks___dynamicContent blocks___innerBlocks blocks___innerBlocks___attributesJSON blocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___attributesJSON blocks___innerBlocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___isDynamic blocks___innerBlocks___innerBlocks___name blocks___innerBlocks___innerBlocks___order blocks___innerBlocks___innerBlocks___originalContent blocks___innerBlocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___innerBlocks___saveContent blocks___innerBlocks___isDynamic blocks___innerBlocks___name blocks___innerBlocks___order blocks___innerBlocks___originalContent blocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___parentNode___id blocks___innerBlocks___saveContent blocks___isDynamic blocks___name blocks___order blocks___originalContent blocks___parentNodeDatabaseId blocks___parentNode___id blocks___saveContent children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id previewBlocks previewBlocksJSON previewBlocks___attributesJSON previewBlocks___dynamicContent previewBlocks___innerBlocks previewBlocks___innerBlocks___attributesJSON previewBlocks___innerBlocks___dynamicContent previewBlocks___innerBlocks___innerBlocks previewBlocks___innerBlocks___innerBlocks___attributesJSON previewBlocks___innerBlocks___innerBlocks___dynamicContent previewBlocks___innerBlocks___innerBlocks___innerBlocks previewBlocks___innerBlocks___innerBlocks___isDynamic previewBlocks___innerBlocks___innerBlocks___name previewBlocks___innerBlocks___innerBlocks___order previewBlocks___innerBlocks___innerBlocks___originalContent previewBlocks___innerBlocks___innerBlocks___parentNodeDatabaseId previewBlocks___innerBlocks___innerBlocks___saveContent previewBlocks___innerBlocks___isDynamic previewBlocks___innerBlocks___name previewBlocks___innerBlocks___order previewBlocks___innerBlocks___originalContent previewBlocks___innerBlocks___parentNodeDatabaseId previewBlocks___innerBlocks___parentNode___id previewBlocks___innerBlocks___saveContent previewBlocks___isDynamic previewBlocks___name previewBlocks___order previewBlocks___originalContent previewBlocks___parentNodeDatabaseId previewBlocks___parentNode___id previewBlocks___saveContent } input WpBlockEditorContentNodeFilterInput { blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput children: NodeFilterListInput id: StringQueryOperatorInput internal: InternalFilterInput nodeType: StringQueryOperatorInput parent: NodeFilterInput previewBlocks: WpBlockFilterListInput previewBlocksJSON: StringQueryOperatorInput } type WpBlockEditorContentNodeGroupConnection { distinct(field: WpBlockEditorContentNodeFieldsEnum!): [String!]! edges: [WpBlockEditorContentNodeEdge!]! field: String! fieldValue: String group(field: WpBlockEditorContentNodeFieldsEnum!, limit: Int, skip: Int): [WpBlockEditorContentNodeGroupConnection!]! max(field: WpBlockEditorContentNodeFieldsEnum!): Float min(field: WpBlockEditorContentNodeFieldsEnum!): Float nodes: [WpBlockEditorContentNode!]! pageInfo: PageInfo! sum(field: WpBlockEditorContentNodeFieldsEnum!): Float totalCount: Int! } input WpBlockEditorContentNodeSortInput { fields: [WpBlockEditorContentNodeFieldsEnum] order: [SortOrderEnum] = [ASC] } """ The BlockEditorPreview type """ type WpBlockEditorPreview implements Node & WpContentNode & WpDatabaseIdentifier & WpNode & WpNodeWithAuthor & WpNodeWithContentEditor & WpNodeWithTemplate & WpNodeWithTitle & WpUniformResourceIdentifiable { """ Connection between the NodeWithAuthor type and the User type """ author: WpNodeWithAuthorToUserConnectionEdge """ The database identifier of the author of the node """ authorDatabaseId: Int """ The globally unique identifier of the author of the node """ authorId: ID blocks: [WpBlock!] blocksJSON: String children: [Node!]! """ The content of the post. """ content: String """ Connection between the ContentNode type and the ContentType type """ contentType: WpContentNodeToContentTypeConnectionEdge """ The name of the Content Type the node belongs to """ contentTypeName: String! """ The unique identifier stored in the database """ databaseId: Int! """ Post publishing date. """ date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The publishing date set in GMT. """ dateGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The desired slug of the post """ desiredSlug: String """ The RSS enclosure for the object """ enclosure: String """ The global unique identifier for this post. This currently matches the value stored in WP_Post->guid and the guid column in the "post_objects" database table. """ guid: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The user that most recently edited the node """ lastEditedBy: WpContentNodeToEditLastConnectionEdge lastUpdateTime: String """ The permalink of the post """ link: String """ The local modified time for a post. If a post was recently updated the modified field will change to match the corresponding time. """ modified( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The GMT modified time for a post. If a post was recently updated the modified field will change to match the corresponding time in GMT. """ modifiedGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date nodeType: String parent: Node previewed: WpBlockEditorContentNode previewedDatabaseId: Int previewedParentDatabaseId: Int """ The uri slug for the post. This is equivalent to the WP_Post->post_name field and the post_name column in the database for the "post_objects" table. """ slug: String """ The current status of the object """ status: String """ The template assigned to the node """ template: WpContentTemplate """ The title of the post. This is currently just the raw title. An amendment to support rendered title needs to be made. """ title: String """ The unique resource identifier path """ uri: String } type WpBlockEditorPreviewConnection { distinct(field: WpBlockEditorPreviewFieldsEnum!): [String!]! edges: [WpBlockEditorPreviewEdge!]! group(field: WpBlockEditorPreviewFieldsEnum!, limit: Int, skip: Int): [WpBlockEditorPreviewGroupConnection!]! max(field: WpBlockEditorPreviewFieldsEnum!): Float min(field: WpBlockEditorPreviewFieldsEnum!): Float nodes: [WpBlockEditorPreview!]! pageInfo: PageInfo! sum(field: WpBlockEditorPreviewFieldsEnum!): Float totalCount: Int! } type WpBlockEditorPreviewEdge { next: WpBlockEditorPreview node: WpBlockEditorPreview! previous: WpBlockEditorPreview } enum WpBlockEditorPreviewFieldsEnum { authorDatabaseId authorId author___node___avatar___default author___node___avatar___extraAttr author___node___avatar___forceDefault author___node___avatar___foundAvatar author___node___avatar___height author___node___avatar___rating author___node___avatar___scheme author___node___avatar___size author___node___avatar___url author___node___avatar___width author___node___blockEditorPreviews___nodes author___node___capKey author___node___capabilities author___node___children author___node___children___children author___node___children___id author___node___comments___nodes author___node___databaseId author___node___description author___node___email author___node___extraCapabilities author___node___firstName author___node___id author___node___internal___content author___node___internal___contentDigest author___node___internal___description author___node___internal___fieldOwners author___node___internal___ignoreType author___node___internal___mediaType author___node___internal___owner author___node___internal___type author___node___isContentNode author___node___isTermNode author___node___lastName author___node___locale author___node___name author___node___nicename author___node___nickname author___node___nodeType author___node___pages___nodes author___node___parent___children author___node___parent___id author___node___posts___nodes author___node___registeredDate author___node___roles___nodes author___node___slug author___node___uri author___node___url author___node___username blocks blocksJSON blocks___attributesJSON blocks___dynamicContent blocks___innerBlocks blocks___innerBlocks___attributesJSON blocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___attributesJSON blocks___innerBlocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___isDynamic blocks___innerBlocks___innerBlocks___name blocks___innerBlocks___innerBlocks___order blocks___innerBlocks___innerBlocks___originalContent blocks___innerBlocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___innerBlocks___saveContent blocks___innerBlocks___isDynamic blocks___innerBlocks___name blocks___innerBlocks___order blocks___innerBlocks___originalContent blocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___parentNode___id blocks___innerBlocks___saveContent blocks___isDynamic blocks___name blocks___order blocks___originalContent blocks___parentNodeDatabaseId blocks___parentNode___id blocks___saveContent children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id content contentTypeName contentType___node___archivePath contentType___node___canExport contentType___node___children contentType___node___children___children contentType___node___children___id contentType___node___connectedTaxonomies___nodes contentType___node___contentNodes___nodes contentType___node___deleteWithUser contentType___node___description contentType___node___excludeFromSearch contentType___node___graphqlPluralName contentType___node___graphqlSingleName contentType___node___hasArchive contentType___node___hierarchical contentType___node___id contentType___node___internal___content contentType___node___internal___contentDigest contentType___node___internal___description contentType___node___internal___fieldOwners contentType___node___internal___ignoreType contentType___node___internal___mediaType contentType___node___internal___owner contentType___node___internal___type contentType___node___isContentNode contentType___node___isFrontPage contentType___node___isPostsPage contentType___node___isTermNode contentType___node___label contentType___node___labels___addNew contentType___node___labels___addNewItem contentType___node___labels___allItems contentType___node___labels___archives contentType___node___labels___attributes contentType___node___labels___editItem contentType___node___labels___featuredImage contentType___node___labels___filterItemsList contentType___node___labels___insertIntoItem contentType___node___labels___itemsList contentType___node___labels___itemsListNavigation contentType___node___labels___menuName contentType___node___labels___name contentType___node___labels___newItem contentType___node___labels___notFound contentType___node___labels___notFoundInTrash contentType___node___labels___parentItemColon contentType___node___labels___removeFeaturedImage contentType___node___labels___searchItems contentType___node___labels___setFeaturedImage contentType___node___labels___singularName contentType___node___labels___uploadedToThisItem contentType___node___labels___useFeaturedImage contentType___node___labels___viewItem contentType___node___labels___viewItems contentType___node___menuIcon contentType___node___menuPosition contentType___node___name contentType___node___nodeType contentType___node___parent___children contentType___node___parent___id contentType___node___public contentType___node___publiclyQueryable contentType___node___restBase contentType___node___restControllerClass contentType___node___showInAdminBar contentType___node___showInGraphql contentType___node___showInMenu contentType___node___showInNavMenus contentType___node___showInRest contentType___node___showUi contentType___node___uri databaseId date dateGmt desiredSlug enclosure guid id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isTermNode lastEditedBy___node___avatar___default lastEditedBy___node___avatar___extraAttr lastEditedBy___node___avatar___forceDefault lastEditedBy___node___avatar___foundAvatar lastEditedBy___node___avatar___height lastEditedBy___node___avatar___rating lastEditedBy___node___avatar___scheme lastEditedBy___node___avatar___size lastEditedBy___node___avatar___url lastEditedBy___node___avatar___width lastEditedBy___node___blockEditorPreviews___nodes lastEditedBy___node___capKey lastEditedBy___node___capabilities lastEditedBy___node___children lastEditedBy___node___children___children lastEditedBy___node___children___id lastEditedBy___node___comments___nodes lastEditedBy___node___databaseId lastEditedBy___node___description lastEditedBy___node___email lastEditedBy___node___extraCapabilities lastEditedBy___node___firstName lastEditedBy___node___id lastEditedBy___node___internal___content lastEditedBy___node___internal___contentDigest lastEditedBy___node___internal___description lastEditedBy___node___internal___fieldOwners lastEditedBy___node___internal___ignoreType lastEditedBy___node___internal___mediaType lastEditedBy___node___internal___owner lastEditedBy___node___internal___type lastEditedBy___node___isContentNode lastEditedBy___node___isTermNode lastEditedBy___node___lastName lastEditedBy___node___locale lastEditedBy___node___name lastEditedBy___node___nicename lastEditedBy___node___nickname lastEditedBy___node___nodeType lastEditedBy___node___pages___nodes lastEditedBy___node___parent___children lastEditedBy___node___parent___id lastEditedBy___node___posts___nodes lastEditedBy___node___registeredDate lastEditedBy___node___roles___nodes lastEditedBy___node___slug lastEditedBy___node___uri lastEditedBy___node___url lastEditedBy___node___username lastUpdateTime link modified modifiedGmt nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id previewedDatabaseId previewedParentDatabaseId previewed___blocks previewed___blocksJSON previewed___blocks___attributesJSON previewed___blocks___dynamicContent previewed___blocks___innerBlocks previewed___blocks___innerBlocks___attributesJSON previewed___blocks___innerBlocks___dynamicContent previewed___blocks___innerBlocks___innerBlocks previewed___blocks___innerBlocks___isDynamic previewed___blocks___innerBlocks___name previewed___blocks___innerBlocks___order previewed___blocks___innerBlocks___originalContent previewed___blocks___innerBlocks___parentNodeDatabaseId previewed___blocks___innerBlocks___saveContent previewed___blocks___isDynamic previewed___blocks___name previewed___blocks___order previewed___blocks___originalContent previewed___blocks___parentNodeDatabaseId previewed___blocks___parentNode___id previewed___blocks___saveContent previewed___children previewed___children___children previewed___children___children___children previewed___children___children___id previewed___children___id previewed___children___internal___content previewed___children___internal___contentDigest previewed___children___internal___description previewed___children___internal___fieldOwners previewed___children___internal___ignoreType previewed___children___internal___mediaType previewed___children___internal___owner previewed___children___internal___type previewed___children___parent___children previewed___children___parent___id previewed___id previewed___internal___content previewed___internal___contentDigest previewed___internal___description previewed___internal___fieldOwners previewed___internal___ignoreType previewed___internal___mediaType previewed___internal___owner previewed___internal___type previewed___nodeType previewed___parent___children previewed___parent___children___children previewed___parent___children___id previewed___parent___id previewed___parent___internal___content previewed___parent___internal___contentDigest previewed___parent___internal___description previewed___parent___internal___fieldOwners previewed___parent___internal___ignoreType previewed___parent___internal___mediaType previewed___parent___internal___owner previewed___parent___internal___type previewed___parent___parent___children previewed___parent___parent___id previewed___previewBlocks previewed___previewBlocksJSON previewed___previewBlocks___attributesJSON previewed___previewBlocks___dynamicContent previewed___previewBlocks___innerBlocks previewed___previewBlocks___innerBlocks___attributesJSON previewed___previewBlocks___innerBlocks___dynamicContent previewed___previewBlocks___innerBlocks___innerBlocks previewed___previewBlocks___innerBlocks___isDynamic previewed___previewBlocks___innerBlocks___name previewed___previewBlocks___innerBlocks___order previewed___previewBlocks___innerBlocks___originalContent previewed___previewBlocks___innerBlocks___parentNodeDatabaseId previewed___previewBlocks___innerBlocks___saveContent previewed___previewBlocks___isDynamic previewed___previewBlocks___name previewed___previewBlocks___order previewed___previewBlocks___originalContent previewed___previewBlocks___parentNodeDatabaseId previewed___previewBlocks___parentNode___id previewed___previewBlocks___saveContent slug status template___templateName title uri } input WpBlockEditorPreviewFilterInput { author: WpNodeWithAuthorToUserConnectionEdgeFilterInput authorDatabaseId: IntQueryOperatorInput authorId: IDQueryOperatorInput blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput children: NodeFilterListInput content: StringQueryOperatorInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput lastUpdateTime: StringQueryOperatorInput link: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput previewed: WpBlockEditorContentNodeFilterInput previewedDatabaseId: IntQueryOperatorInput previewedParentDatabaseId: IntQueryOperatorInput slug: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput title: StringQueryOperatorInput uri: StringQueryOperatorInput } input WpBlockEditorPreviewFilterListInput { elemMatch: WpBlockEditorPreviewFilterInput } type WpBlockEditorPreviewGroupConnection { distinct(field: WpBlockEditorPreviewFieldsEnum!): [String!]! edges: [WpBlockEditorPreviewEdge!]! field: String! fieldValue: String group(field: WpBlockEditorPreviewFieldsEnum!, limit: Int, skip: Int): [WpBlockEditorPreviewGroupConnection!]! max(field: WpBlockEditorPreviewFieldsEnum!): Float min(field: WpBlockEditorPreviewFieldsEnum!): Float nodes: [WpBlockEditorPreview!]! pageInfo: PageInfo! sum(field: WpBlockEditorPreviewFieldsEnum!): Float totalCount: Int! } input WpBlockEditorPreviewSortInput { fields: [WpBlockEditorPreviewFieldsEnum] order: [SortOrderEnum] = [ASC] } input WpBlockFilterInput { attributesJSON: StringQueryOperatorInput dynamicContent: StringQueryOperatorInput innerBlocks: WpBlockFilterListInput isDynamic: BooleanQueryOperatorInput name: StringQueryOperatorInput order: IntQueryOperatorInput originalContent: StringQueryOperatorInput parentNode: WpNodeFilterInput parentNodeDatabaseId: IntQueryOperatorInput saveContent: StringQueryOperatorInput } input WpBlockFilterListInput { elemMatch: WpBlockFilterInput } """ The category type """ type WpCategory implements Node & WpDatabaseIdentifier & WpHierarchicalTermNode & WpMenuItemLinkable & WpNode & WpTermNode & WpUniformResourceIdentifiable { """ The ancestors of the node. Default ordered as lowest (closest to the child) to highest (closest to the root). """ ancestors: WpCategoryToAncestorsCategoryConnection children: [Node!]! """ Connection between the category type and the ContentNode type """ contentNodes: WpCategoryToContentNodeConnection """ The number of objects connected to the object """ count: Int """ The unique resource identifier path """ databaseId: Int! """ The description of the object """ description: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The link to the term """ link: String """ The human friendly name of the object. """ name: String nodeType: String parent: Node """ Database id of the parent node """ parentDatabaseId: Int """ The globally unique identifier of the parent node. """ parentId: ID """ Connection between the category type and the post type """ posts: WpCategoryToPostConnection """ An alphanumeric identifier for the object unique to its type. """ slug: String """ Connection between the category type and the Taxonomy type """ taxonomy: WpCategoryToTaxonomyConnectionEdge """ The name of the taxonomy that the object is associated with """ taxonomyName: String """ The ID of the term group that this term object belongs to """ termGroupId: Int """ The taxonomy ID that the object is associated with """ termTaxonomyId: Int """ The unique resource identifier path """ uri: String """ Connection between the category type and the category type """ wpChildren: WpCategoryToCategoryConnection """ Connection between the category type and the category type """ wpParent: WpCategoryToParentCategoryConnectionEdge } type WpCategoryConnection { distinct(field: WpCategoryFieldsEnum!): [String!]! edges: [WpCategoryEdge!]! group(field: WpCategoryFieldsEnum!, limit: Int, skip: Int): [WpCategoryGroupConnection!]! max(field: WpCategoryFieldsEnum!): Float min(field: WpCategoryFieldsEnum!): Float nodes: [WpCategory!]! pageInfo: PageInfo! sum(field: WpCategoryFieldsEnum!): Float totalCount: Int! } type WpCategoryEdge { next: WpCategory node: WpCategory! previous: WpCategory } enum WpCategoryFieldsEnum { ancestors___nodes ancestors___nodes___ancestors___nodes ancestors___nodes___children ancestors___nodes___children___children ancestors___nodes___children___id ancestors___nodes___contentNodes___nodes ancestors___nodes___count ancestors___nodes___databaseId ancestors___nodes___description ancestors___nodes___id ancestors___nodes___internal___content ancestors___nodes___internal___contentDigest ancestors___nodes___internal___description ancestors___nodes___internal___fieldOwners ancestors___nodes___internal___ignoreType ancestors___nodes___internal___mediaType ancestors___nodes___internal___owner ancestors___nodes___internal___type ancestors___nodes___isContentNode ancestors___nodes___isTermNode ancestors___nodes___link ancestors___nodes___name ancestors___nodes___nodeType ancestors___nodes___parentDatabaseId ancestors___nodes___parentId ancestors___nodes___parent___children ancestors___nodes___parent___id ancestors___nodes___posts___nodes ancestors___nodes___slug ancestors___nodes___taxonomyName ancestors___nodes___termGroupId ancestors___nodes___termTaxonomyId ancestors___nodes___uri ancestors___nodes___wpChildren___nodes children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id contentNodes___nodes contentNodes___nodes___children contentNodes___nodes___children___children contentNodes___nodes___children___id contentNodes___nodes___contentTypeName contentNodes___nodes___databaseId contentNodes___nodes___date contentNodes___nodes___dateGmt contentNodes___nodes___desiredSlug contentNodes___nodes___enclosure contentNodes___nodes___guid contentNodes___nodes___id contentNodes___nodes___internal___content contentNodes___nodes___internal___contentDigest contentNodes___nodes___internal___description contentNodes___nodes___internal___fieldOwners contentNodes___nodes___internal___ignoreType contentNodes___nodes___internal___mediaType contentNodes___nodes___internal___owner contentNodes___nodes___internal___type contentNodes___nodes___isContentNode contentNodes___nodes___isTermNode contentNodes___nodes___link contentNodes___nodes___modified contentNodes___nodes___modifiedGmt contentNodes___nodes___nodeType contentNodes___nodes___parent___children contentNodes___nodes___parent___id contentNodes___nodes___slug contentNodes___nodes___status contentNodes___nodes___template___templateName contentNodes___nodes___uri count databaseId description id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isTermNode link name nodeType parentDatabaseId parentId parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id posts___nodes posts___nodes___authorDatabaseId posts___nodes___authorId posts___nodes___blocks posts___nodes___blocksJSON posts___nodes___blocks___attributesJSON posts___nodes___blocks___dynamicContent posts___nodes___blocks___innerBlocks posts___nodes___blocks___isDynamic posts___nodes___blocks___name posts___nodes___blocks___order posts___nodes___blocks___originalContent posts___nodes___blocks___parentNodeDatabaseId posts___nodes___blocks___saveContent posts___nodes___categories___nodes posts___nodes___children posts___nodes___children___children posts___nodes___children___id posts___nodes___commentCount posts___nodes___commentStatus posts___nodes___comments___nodes posts___nodes___content posts___nodes___contentTypeName posts___nodes___databaseId posts___nodes___date posts___nodes___dateGmt posts___nodes___desiredSlug posts___nodes___enclosure posts___nodes___excerpt posts___nodes___featuredImageDatabaseId posts___nodes___featuredImageId posts___nodes___guid posts___nodes___id posts___nodes___internal___content posts___nodes___internal___contentDigest posts___nodes___internal___description posts___nodes___internal___fieldOwners posts___nodes___internal___ignoreType posts___nodes___internal___mediaType posts___nodes___internal___owner posts___nodes___internal___type posts___nodes___isContentNode posts___nodes___isRevision posts___nodes___isSticky posts___nodes___isTermNode posts___nodes___link posts___nodes___modified posts___nodes___modifiedGmt posts___nodes___nodeType posts___nodes___parent___children posts___nodes___parent___id posts___nodes___pingStatus posts___nodes___pinged posts___nodes___postFormats___nodes posts___nodes___previewBlocks posts___nodes___previewBlocksJSON posts___nodes___previewBlocks___attributesJSON posts___nodes___previewBlocks___dynamicContent posts___nodes___previewBlocks___innerBlocks posts___nodes___previewBlocks___isDynamic posts___nodes___previewBlocks___name posts___nodes___previewBlocks___order posts___nodes___previewBlocks___originalContent posts___nodes___previewBlocks___parentNodeDatabaseId posts___nodes___previewBlocks___saveContent posts___nodes___slug posts___nodes___status posts___nodes___tags___nodes posts___nodes___template___templateName posts___nodes___terms___nodes posts___nodes___title posts___nodes___toPing posts___nodes___uri slug taxonomyName taxonomy___node___archivePath taxonomy___node___children taxonomy___node___children___children taxonomy___node___children___id taxonomy___node___connectedContentTypes___nodes taxonomy___node___description taxonomy___node___graphqlPluralName taxonomy___node___graphqlSingleName taxonomy___node___hierarchical taxonomy___node___id taxonomy___node___internal___content taxonomy___node___internal___contentDigest taxonomy___node___internal___description taxonomy___node___internal___fieldOwners taxonomy___node___internal___ignoreType taxonomy___node___internal___mediaType taxonomy___node___internal___owner taxonomy___node___internal___type taxonomy___node___label taxonomy___node___name taxonomy___node___nodeType taxonomy___node___parent___children taxonomy___node___parent___id taxonomy___node___public taxonomy___node___restBase taxonomy___node___restControllerClass taxonomy___node___showCloud taxonomy___node___showInAdminColumn taxonomy___node___showInGraphql taxonomy___node___showInMenu taxonomy___node___showInNavMenus taxonomy___node___showInQuickEdit taxonomy___node___showInRest taxonomy___node___showUi termGroupId termTaxonomyId uri wpChildren___nodes wpChildren___nodes___ancestors___nodes wpChildren___nodes___children wpChildren___nodes___children___children wpChildren___nodes___children___id wpChildren___nodes___contentNodes___nodes wpChildren___nodes___count wpChildren___nodes___databaseId wpChildren___nodes___description wpChildren___nodes___id wpChildren___nodes___internal___content wpChildren___nodes___internal___contentDigest wpChildren___nodes___internal___description wpChildren___nodes___internal___fieldOwners wpChildren___nodes___internal___ignoreType wpChildren___nodes___internal___mediaType wpChildren___nodes___internal___owner wpChildren___nodes___internal___type wpChildren___nodes___isContentNode wpChildren___nodes___isTermNode wpChildren___nodes___link wpChildren___nodes___name wpChildren___nodes___nodeType wpChildren___nodes___parentDatabaseId wpChildren___nodes___parentId wpChildren___nodes___parent___children wpChildren___nodes___parent___id wpChildren___nodes___posts___nodes wpChildren___nodes___slug wpChildren___nodes___taxonomyName wpChildren___nodes___termGroupId wpChildren___nodes___termTaxonomyId wpChildren___nodes___uri wpChildren___nodes___wpChildren___nodes wpParent___node___ancestors___nodes wpParent___node___children wpParent___node___children___children wpParent___node___children___id wpParent___node___contentNodes___nodes wpParent___node___count wpParent___node___databaseId wpParent___node___description wpParent___node___id wpParent___node___internal___content wpParent___node___internal___contentDigest wpParent___node___internal___description wpParent___node___internal___fieldOwners wpParent___node___internal___ignoreType wpParent___node___internal___mediaType wpParent___node___internal___owner wpParent___node___internal___type wpParent___node___isContentNode wpParent___node___isTermNode wpParent___node___link wpParent___node___name wpParent___node___nodeType wpParent___node___parentDatabaseId wpParent___node___parentId wpParent___node___parent___children wpParent___node___parent___id wpParent___node___posts___nodes wpParent___node___slug wpParent___node___taxonomyName wpParent___node___termGroupId wpParent___node___termTaxonomyId wpParent___node___uri wpParent___node___wpChildren___nodes } input WpCategoryFilterInput { ancestors: WpCategoryToAncestorsCategoryConnectionFilterInput children: NodeFilterListInput contentNodes: WpCategoryToContentNodeConnectionFilterInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput link: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput posts: WpCategoryToPostConnectionFilterInput slug: StringQueryOperatorInput taxonomy: WpCategoryToTaxonomyConnectionEdgeFilterInput taxonomyName: StringQueryOperatorInput termGroupId: IntQueryOperatorInput termTaxonomyId: IntQueryOperatorInput uri: StringQueryOperatorInput wpChildren: WpCategoryToCategoryConnectionFilterInput wpParent: WpCategoryToParentCategoryConnectionEdgeFilterInput } input WpCategoryFilterListInput { elemMatch: WpCategoryFilterInput } type WpCategoryGroupConnection { distinct(field: WpCategoryFieldsEnum!): [String!]! edges: [WpCategoryEdge!]! field: String! fieldValue: String group(field: WpCategoryFieldsEnum!, limit: Int, skip: Int): [WpCategoryGroupConnection!]! max(field: WpCategoryFieldsEnum!): Float min(field: WpCategoryFieldsEnum!): Float nodes: [WpCategory!]! pageInfo: PageInfo! sum(field: WpCategoryFieldsEnum!): Float totalCount: Int! } input WpCategorySortInput { fields: [WpCategoryFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the category type and the category type """ type WpCategoryToAncestorsCategoryConnection { """ The nodes of the connection, without the edges """ nodes: [WpCategory] } input WpCategoryToAncestorsCategoryConnectionFilterInput { nodes: WpCategoryFilterListInput } """ Connection between the category type and the category type """ type WpCategoryToCategoryConnection { """ The nodes of the connection, without the edges """ nodes: [WpCategory] } input WpCategoryToCategoryConnectionFilterInput { nodes: WpCategoryFilterListInput } """ Connection between the category type and the ContentNode type """ type WpCategoryToContentNodeConnection { """ The nodes of the connection, without the edges """ nodes: [WpContentNode] } input WpCategoryToContentNodeConnectionFilterInput { nodes: WpContentNodeFilterListInput } """ Connection between the category type and the category type """ type WpCategoryToParentCategoryConnectionEdge { """ The node of the connection, without the edges """ node: WpCategory } input WpCategoryToParentCategoryConnectionEdgeFilterInput { node: WpCategoryFilterInput } """ Connection between the category type and the post type """ type WpCategoryToPostConnection { """ The nodes of the connection, without the edges """ nodes: [WpPost] } input WpCategoryToPostConnectionFilterInput { nodes: WpPostFilterListInput } """ Connection between the category type and the Taxonomy type """ type WpCategoryToTaxonomyConnectionEdge { """ The node of the connection, without the edges """ node: WpTaxonomy } input WpCategoryToTaxonomyConnectionEdgeFilterInput { node: WpTaxonomyFilterInput } """ A Comment object """ type WpComment implements Node & WpDatabaseIdentifier & WpNode { """ User agent used to post the comment. This field is equivalent to WP_Comment->comment_agent and the value matching the "comment_agent" column in SQL. """ agent: String """ The approval status of the comment. This field is equivalent to WP_Comment->comment_approved and the value matching the "comment_approved" column in SQL. """ approved: Boolean """ The author of the comment """ author: WpCommentToCommenterConnectionEdge """ IP address for the author. This field is equivalent to WP_Comment->comment_author_IP and the value matching the "comment_author_IP" column in SQL. """ authorIp: String children: [Node!]! """ Connection between the Comment type and the ContentNode type """ commentedOn: WpCommentToContentNodeConnectionEdge """ Content of the comment. This field is equivalent to WP_Comment->comment_content and the value matching the "comment_content" column in SQL. """ content: String """ The unique identifier stored in the database """ databaseId: Int! """ Date the comment was posted in local time. This field is equivalent to WP_Comment->date and the value matching the "date" column in SQL. """ date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ Date the comment was posted in GMT. This field is equivalent to WP_Comment->date_gmt and the value matching the "date_gmt" column in SQL. """ dateGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date id: ID! internal: Internal! """ Karma value for the comment. This field is equivalent to WP_Comment->comment_karma and the value matching the "comment_karma" column in SQL. """ karma: Int nodeType: String parent: Node """ The database id of the parent comment node or null if it is the root comment """ parentDatabaseId: Int """ The globally unique identifier of the parent comment node. """ parentId: ID """ Connection between the Comment type and the Comment type """ replies: WpCommentToCommentConnection """ Type of comment. This field is equivalent to WP_Comment->comment_type and the value matching the "comment_type" column in SQL. """ type: String """ Connection between the Comment type and the Comment type """ wpParent: WpCommentToParentCommentConnectionEdge } """ A Comment Author object """ type WpCommentAuthor implements Node & WpCommenter & WpNode { """ Avatar object for user. The avatar object can be retrieved in different sizes by specifying the size argument. """ avatar: WpAvatar children: [Node!]! """ Identifies the primary key from the database. """ databaseId: Int! """ The email for the comment author """ email: String id: ID! internal: Internal! """ The name for the comment author. """ name: String nodeType: String parent: Node """ The url the comment author. """ url: String } type WpCommentAuthorConnection { distinct(field: WpCommentAuthorFieldsEnum!): [String!]! edges: [WpCommentAuthorEdge!]! group(field: WpCommentAuthorFieldsEnum!, limit: Int, skip: Int): [WpCommentAuthorGroupConnection!]! max(field: WpCommentAuthorFieldsEnum!): Float min(field: WpCommentAuthorFieldsEnum!): Float nodes: [WpCommentAuthor!]! pageInfo: PageInfo! sum(field: WpCommentAuthorFieldsEnum!): Float totalCount: Int! } type WpCommentAuthorEdge { next: WpCommentAuthor node: WpCommentAuthor! previous: WpCommentAuthor } enum WpCommentAuthorFieldsEnum { avatar___default avatar___extraAttr avatar___forceDefault avatar___foundAvatar avatar___height avatar___rating avatar___scheme avatar___size avatar___url avatar___width children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id databaseId email id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type name nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id url } input WpCommentAuthorFilterInput { avatar: WpAvatarFilterInput children: NodeFilterListInput databaseId: IntQueryOperatorInput email: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput url: StringQueryOperatorInput } type WpCommentAuthorGroupConnection { distinct(field: WpCommentAuthorFieldsEnum!): [String!]! edges: [WpCommentAuthorEdge!]! field: String! fieldValue: String group(field: WpCommentAuthorFieldsEnum!, limit: Int, skip: Int): [WpCommentAuthorGroupConnection!]! max(field: WpCommentAuthorFieldsEnum!): Float min(field: WpCommentAuthorFieldsEnum!): Float nodes: [WpCommentAuthor!]! pageInfo: PageInfo! sum(field: WpCommentAuthorFieldsEnum!): Float totalCount: Int! } input WpCommentAuthorSortInput { fields: [WpCommentAuthorFieldsEnum] order: [SortOrderEnum] = [ASC] } type WpCommentConnection { distinct(field: WpCommentFieldsEnum!): [String!]! edges: [WpCommentEdge!]! group(field: WpCommentFieldsEnum!, limit: Int, skip: Int): [WpCommentGroupConnection!]! max(field: WpCommentFieldsEnum!): Float min(field: WpCommentFieldsEnum!): Float nodes: [WpComment!]! pageInfo: PageInfo! sum(field: WpCommentFieldsEnum!): Float totalCount: Int! } type WpCommentEdge { next: WpComment node: WpComment! previous: WpComment } enum WpCommentFieldsEnum { agent approved authorIp author___node___avatar___default author___node___avatar___extraAttr author___node___avatar___forceDefault author___node___avatar___foundAvatar author___node___avatar___height author___node___avatar___rating author___node___avatar___scheme author___node___avatar___size author___node___avatar___url author___node___avatar___width author___node___databaseId author___node___email author___node___id author___node___name author___node___url children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id commentedOn___node___children commentedOn___node___children___children commentedOn___node___children___id commentedOn___node___contentTypeName commentedOn___node___databaseId commentedOn___node___date commentedOn___node___dateGmt commentedOn___node___desiredSlug commentedOn___node___enclosure commentedOn___node___guid commentedOn___node___id commentedOn___node___internal___content commentedOn___node___internal___contentDigest commentedOn___node___internal___description commentedOn___node___internal___fieldOwners commentedOn___node___internal___ignoreType commentedOn___node___internal___mediaType commentedOn___node___internal___owner commentedOn___node___internal___type commentedOn___node___isContentNode commentedOn___node___isTermNode commentedOn___node___link commentedOn___node___modified commentedOn___node___modifiedGmt commentedOn___node___nodeType commentedOn___node___parent___children commentedOn___node___parent___id commentedOn___node___slug commentedOn___node___status commentedOn___node___template___templateName commentedOn___node___uri content databaseId date dateGmt id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type karma nodeType parentDatabaseId parentId parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id replies___nodes replies___nodes___agent replies___nodes___approved replies___nodes___authorIp replies___nodes___children replies___nodes___children___children replies___nodes___children___id replies___nodes___content replies___nodes___databaseId replies___nodes___date replies___nodes___dateGmt replies___nodes___id replies___nodes___internal___content replies___nodes___internal___contentDigest replies___nodes___internal___description replies___nodes___internal___fieldOwners replies___nodes___internal___ignoreType replies___nodes___internal___mediaType replies___nodes___internal___owner replies___nodes___internal___type replies___nodes___karma replies___nodes___nodeType replies___nodes___parentDatabaseId replies___nodes___parentId replies___nodes___parent___children replies___nodes___parent___id replies___nodes___replies___nodes replies___nodes___type type wpParent___node___agent wpParent___node___approved wpParent___node___authorIp wpParent___node___children wpParent___node___children___children wpParent___node___children___id wpParent___node___content wpParent___node___databaseId wpParent___node___date wpParent___node___dateGmt wpParent___node___id wpParent___node___internal___content wpParent___node___internal___contentDigest wpParent___node___internal___description wpParent___node___internal___fieldOwners wpParent___node___internal___ignoreType wpParent___node___internal___mediaType wpParent___node___internal___owner wpParent___node___internal___type wpParent___node___karma wpParent___node___nodeType wpParent___node___parentDatabaseId wpParent___node___parentId wpParent___node___parent___children wpParent___node___parent___id wpParent___node___replies___nodes wpParent___node___type } input WpCommentFilterInput { agent: StringQueryOperatorInput approved: BooleanQueryOperatorInput author: WpCommentToCommenterConnectionEdgeFilterInput authorIp: StringQueryOperatorInput children: NodeFilterListInput commentedOn: WpCommentToContentNodeConnectionEdgeFilterInput content: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput karma: IntQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput replies: WpCommentToCommentConnectionFilterInput type: StringQueryOperatorInput wpParent: WpCommentToParentCommentConnectionEdgeFilterInput } input WpCommentFilterListInput { elemMatch: WpCommentFilterInput } type WpCommentGroupConnection { distinct(field: WpCommentFieldsEnum!): [String!]! edges: [WpCommentEdge!]! field: String! fieldValue: String group(field: WpCommentFieldsEnum!, limit: Int, skip: Int): [WpCommentGroupConnection!]! max(field: WpCommentFieldsEnum!): Float min(field: WpCommentFieldsEnum!): Float nodes: [WpComment!]! pageInfo: PageInfo! sum(field: WpCommentFieldsEnum!): Float totalCount: Int! } input WpCommentSortInput { fields: [WpCommentFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the Comment type and the Comment type """ type WpCommentToCommentConnection { """ The nodes of the connection, without the edges """ nodes: [WpComment] } input WpCommentToCommentConnectionFilterInput { nodes: WpCommentFilterListInput } """ Connection between the Comment type and the Commenter type """ type WpCommentToCommenterConnectionEdge { """ The node of the connection, without the edges """ node: WpCommenter } input WpCommentToCommenterConnectionEdgeFilterInput { node: WpCommenterFilterInput } """ Connection between the Comment type and the ContentNode type """ type WpCommentToContentNodeConnectionEdge { """ The node of the connection, without the edges """ node: WpContentNode } input WpCommentToContentNodeConnectionEdgeFilterInput { node: WpContentNodeFilterInput } """ Connection between the Comment type and the Comment type """ type WpCommentToParentCommentConnectionEdge { """ The node of the connection, without the edges """ node: WpComment } input WpCommentToParentCommentConnectionEdgeFilterInput { node: WpCommentFilterInput } interface WpCommenter { """ Avatar object for user. The avatar object can be retrieved in different sizes by specifying the size argument. """ avatar: WpAvatar """ Identifies the primary key from the database. """ databaseId: Int! """ The email address of the author of a comment. """ email: String """ The globally unique identifier for the comment author. """ id: ID! """ The name of the author of a comment. """ name: String """ The url of the author of a comment. """ url: String } input WpCommenterFilterInput { avatar: WpAvatarFilterInput databaseId: IntQueryOperatorInput email: StringQueryOperatorInput id: IDQueryOperatorInput name: StringQueryOperatorInput url: StringQueryOperatorInput } type WpConnection { distinct(field: WpFieldsEnum!): [String!]! edges: [WpEdge!]! group(field: WpFieldsEnum!, limit: Int, skip: Int): [WpGroupConnection!]! max(field: WpFieldsEnum!): Float min(field: WpFieldsEnum!): Float nodes: [Wp!]! pageInfo: PageInfo! sum(field: WpFieldsEnum!): Float totalCount: Int! } interface WpContentNode implements Node { children: [Node!]! """ Connection between the ContentNode type and the ContentType type """ contentType: WpContentNodeToContentTypeConnectionEdge """ The name of the Content Type the node belongs to """ contentTypeName: String! """ The ID of the node in the database. """ databaseId: Int! """ Post publishing date. """ date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The publishing date set in GMT. """ dateGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The desired slug of the post """ desiredSlug: String """ The RSS enclosure for the object """ enclosure: String """ The global unique identifier for this post. This currently matches the value stored in WP_Post->guid and the guid column in the "post_objects" database table. """ guid: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The user that most recently edited the node """ lastEditedBy: WpContentNodeToEditLastConnectionEdge """ The permalink of the post """ link: String """ The local modified time for a post. If a post was recently updated the modified field will change to match the corresponding time. """ modified( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The GMT modified time for a post. If a post was recently updated the modified field will change to match the corresponding time in GMT. """ modifiedGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date nodeType: String parent: Node """ The uri slug for the post. This is equivalent to the WP_Post->post_name field and the post_name column in the database for the "post_objects" table. """ slug: String """ The current status of the object """ status: String """ The template assigned to a node of content """ template: WpContentTemplate """ The unique resource identifier path """ uri: String } type WpContentNodeConnection { distinct(field: WpContentNodeFieldsEnum!): [String!]! edges: [WpContentNodeEdge!]! group(field: WpContentNodeFieldsEnum!, limit: Int, skip: Int): [WpContentNodeGroupConnection!]! max(field: WpContentNodeFieldsEnum!): Float min(field: WpContentNodeFieldsEnum!): Float nodes: [WpContentNode!]! pageInfo: PageInfo! sum(field: WpContentNodeFieldsEnum!): Float totalCount: Int! } type WpContentNodeEdge { next: WpContentNode node: WpContentNode! previous: WpContentNode } enum WpContentNodeFieldsEnum { children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id contentTypeName contentType___node___archivePath contentType___node___canExport contentType___node___children contentType___node___children___children contentType___node___children___id contentType___node___connectedTaxonomies___nodes contentType___node___contentNodes___nodes contentType___node___deleteWithUser contentType___node___description contentType___node___excludeFromSearch contentType___node___graphqlPluralName contentType___node___graphqlSingleName contentType___node___hasArchive contentType___node___hierarchical contentType___node___id contentType___node___internal___content contentType___node___internal___contentDigest contentType___node___internal___description contentType___node___internal___fieldOwners contentType___node___internal___ignoreType contentType___node___internal___mediaType contentType___node___internal___owner contentType___node___internal___type contentType___node___isContentNode contentType___node___isFrontPage contentType___node___isPostsPage contentType___node___isTermNode contentType___node___label contentType___node___labels___addNew contentType___node___labels___addNewItem contentType___node___labels___allItems contentType___node___labels___archives contentType___node___labels___attributes contentType___node___labels___editItem contentType___node___labels___featuredImage contentType___node___labels___filterItemsList contentType___node___labels___insertIntoItem contentType___node___labels___itemsList contentType___node___labels___itemsListNavigation contentType___node___labels___menuName contentType___node___labels___name contentType___node___labels___newItem contentType___node___labels___notFound contentType___node___labels___notFoundInTrash contentType___node___labels___parentItemColon contentType___node___labels___removeFeaturedImage contentType___node___labels___searchItems contentType___node___labels___setFeaturedImage contentType___node___labels___singularName contentType___node___labels___uploadedToThisItem contentType___node___labels___useFeaturedImage contentType___node___labels___viewItem contentType___node___labels___viewItems contentType___node___menuIcon contentType___node___menuPosition contentType___node___name contentType___node___nodeType contentType___node___parent___children contentType___node___parent___id contentType___node___public contentType___node___publiclyQueryable contentType___node___restBase contentType___node___restControllerClass contentType___node___showInAdminBar contentType___node___showInGraphql contentType___node___showInMenu contentType___node___showInNavMenus contentType___node___showInRest contentType___node___showUi contentType___node___uri databaseId date dateGmt desiredSlug enclosure guid id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isTermNode lastEditedBy___node___avatar___default lastEditedBy___node___avatar___extraAttr lastEditedBy___node___avatar___forceDefault lastEditedBy___node___avatar___foundAvatar lastEditedBy___node___avatar___height lastEditedBy___node___avatar___rating lastEditedBy___node___avatar___scheme lastEditedBy___node___avatar___size lastEditedBy___node___avatar___url lastEditedBy___node___avatar___width lastEditedBy___node___blockEditorPreviews___nodes lastEditedBy___node___capKey lastEditedBy___node___capabilities lastEditedBy___node___children lastEditedBy___node___children___children lastEditedBy___node___children___id lastEditedBy___node___comments___nodes lastEditedBy___node___databaseId lastEditedBy___node___description lastEditedBy___node___email lastEditedBy___node___extraCapabilities lastEditedBy___node___firstName lastEditedBy___node___id lastEditedBy___node___internal___content lastEditedBy___node___internal___contentDigest lastEditedBy___node___internal___description lastEditedBy___node___internal___fieldOwners lastEditedBy___node___internal___ignoreType lastEditedBy___node___internal___mediaType lastEditedBy___node___internal___owner lastEditedBy___node___internal___type lastEditedBy___node___isContentNode lastEditedBy___node___isTermNode lastEditedBy___node___lastName lastEditedBy___node___locale lastEditedBy___node___name lastEditedBy___node___nicename lastEditedBy___node___nickname lastEditedBy___node___nodeType lastEditedBy___node___pages___nodes lastEditedBy___node___parent___children lastEditedBy___node___parent___id lastEditedBy___node___posts___nodes lastEditedBy___node___registeredDate lastEditedBy___node___roles___nodes lastEditedBy___node___slug lastEditedBy___node___uri lastEditedBy___node___url lastEditedBy___node___username link modified modifiedGmt nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id slug status template___templateName uri } input WpContentNodeFilterInput { children: NodeFilterListInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput slug: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput uri: StringQueryOperatorInput } input WpContentNodeFilterListInput { elemMatch: WpContentNodeFilterInput } type WpContentNodeGroupConnection { distinct(field: WpContentNodeFieldsEnum!): [String!]! edges: [WpContentNodeEdge!]! field: String! fieldValue: String group(field: WpContentNodeFieldsEnum!, limit: Int, skip: Int): [WpContentNodeGroupConnection!]! max(field: WpContentNodeFieldsEnum!): Float min(field: WpContentNodeFieldsEnum!): Float nodes: [WpContentNode!]! pageInfo: PageInfo! sum(field: WpContentNodeFieldsEnum!): Float totalCount: Int! } input WpContentNodeSortInput { fields: [WpContentNodeFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the ContentNode type and the ContentType type """ type WpContentNodeToContentTypeConnectionEdge { """ The node of the connection, without the edges """ node: WpContentType } input WpContentNodeToContentTypeConnectionEdgeFilterInput { node: WpContentTypeFilterInput } """ Connection between the ContentNode type and the User type """ type WpContentNodeToEditLastConnectionEdge { """ The node of the connection, without the edges """ node: WpUser } input WpContentNodeToEditLastConnectionEdgeFilterInput { node: WpUserFilterInput } """ Connection between the ContentNode type and the User type """ type WpContentNodeToEditLockConnectionEdge { """ The timestamp for when the node was last edited """ lockTimestamp: String """ The node of the connection, without the edges """ node: WpUser } interface WpContentTemplate { """ The name of the template """ templateName: String } input WpContentTemplateFilterInput { templateName: StringQueryOperatorInput } """ An Post Type object """ type WpContentType implements Node & WpNode & WpUniformResourceIdentifiable { """ The url path of the first page of the archive page for this content type. """ archivePath: String """ Whether this content type should can be exported. """ canExport: Boolean children: [Node!]! """ Connection between the ContentType type and the Taxonomy type """ connectedTaxonomies: WpContentTypeToTaxonomyConnection """ Connection between the ContentType type and the ContentNode type """ contentNodes: WpContentTypeToContentNodeConnection """ Whether content of this type should be deleted when the author of it is deleted from the system. """ deleteWithUser: Boolean """ Description of the content type. """ description: String """ Whether to exclude nodes of this content type from front end search results. """ excludeFromSearch: Boolean """ The plural name of the content type within the GraphQL Schema. """ graphqlPluralName: String """ The singular name of the content type within the GraphQL Schema. """ graphqlSingleName: String """ Whether this content type should have archives. Content archives are generated by type and by date. """ hasArchive: Boolean """ Whether the content type is hierarchical, for example pages. """ hierarchical: Boolean id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether this page is set to the static front page. """ isFrontPage: Boolean! """ Whether this page is set to the blog posts page. """ isPostsPage: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ Display name of the content type. """ label: String """ Details about the content type labels. """ labels: WpPostTypeLabelDetails """ The name of the icon file to display as a menu icon. """ menuIcon: String """ The position of this post type in the menu. Only applies if show_in_menu is true. """ menuPosition: Int """ The internal name of the post type. This should not be used for display purposes. """ name: String nodeType: String parent: Node """ Whether a content type is intended for use publicly either via the admin interface or by front-end users. While the default settings of exclude_from_search, publicly_queryable, show_ui, and show_in_nav_menus are inherited from public, each does not rely on this relationship and controls a very specific intention. """ public: Boolean """ Whether queries can be performed on the front end for the content type as part of parse_request(). """ publiclyQueryable: Boolean """ Name of content type to display in REST API "wp/v2" namespace. """ restBase: String """ The REST Controller class assigned to handling this content type. """ restControllerClass: String """ Makes this content type available via the admin bar. """ showInAdminBar: Boolean """ Whether to add the content type to the GraphQL Schema. """ showInGraphql: Boolean """ Where to show the content type in the admin menu. To work, $show_ui must be true. If true, the post type is shown in its own top level menu. If false, no menu is shown. If a string of an existing top level menu (eg. "tools.php" or "edit.php?post_type=page"), the post type will be placed as a sub-menu of that. """ showInMenu: Boolean """ Makes this content type available for selection in navigation menus. """ showInNavMenus: Boolean """ Whether the content type is associated with a route under the the REST API "wp/v2" namespace. """ showInRest: Boolean """ Whether to generate and allow a UI for managing this content type in the admin. """ showUi: Boolean """ The unique resource identifier path """ uri: String } type WpContentTypeConnection { distinct(field: WpContentTypeFieldsEnum!): [String!]! edges: [WpContentTypeEdge!]! group(field: WpContentTypeFieldsEnum!, limit: Int, skip: Int): [WpContentTypeGroupConnection!]! max(field: WpContentTypeFieldsEnum!): Float min(field: WpContentTypeFieldsEnum!): Float nodes: [WpContentType!]! pageInfo: PageInfo! sum(field: WpContentTypeFieldsEnum!): Float totalCount: Int! } type WpContentTypeEdge { next: WpContentType node: WpContentType! previous: WpContentType } enum WpContentTypeFieldsEnum { archivePath canExport children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id connectedTaxonomies___nodes connectedTaxonomies___nodes___archivePath connectedTaxonomies___nodes___children connectedTaxonomies___nodes___children___children connectedTaxonomies___nodes___children___id connectedTaxonomies___nodes___connectedContentTypes___nodes connectedTaxonomies___nodes___description connectedTaxonomies___nodes___graphqlPluralName connectedTaxonomies___nodes___graphqlSingleName connectedTaxonomies___nodes___hierarchical connectedTaxonomies___nodes___id connectedTaxonomies___nodes___internal___content connectedTaxonomies___nodes___internal___contentDigest connectedTaxonomies___nodes___internal___description connectedTaxonomies___nodes___internal___fieldOwners connectedTaxonomies___nodes___internal___ignoreType connectedTaxonomies___nodes___internal___mediaType connectedTaxonomies___nodes___internal___owner connectedTaxonomies___nodes___internal___type connectedTaxonomies___nodes___label connectedTaxonomies___nodes___name connectedTaxonomies___nodes___nodeType connectedTaxonomies___nodes___parent___children connectedTaxonomies___nodes___parent___id connectedTaxonomies___nodes___public connectedTaxonomies___nodes___restBase connectedTaxonomies___nodes___restControllerClass connectedTaxonomies___nodes___showCloud connectedTaxonomies___nodes___showInAdminColumn connectedTaxonomies___nodes___showInGraphql connectedTaxonomies___nodes___showInMenu connectedTaxonomies___nodes___showInNavMenus connectedTaxonomies___nodes___showInQuickEdit connectedTaxonomies___nodes___showInRest connectedTaxonomies___nodes___showUi contentNodes___nodes contentNodes___nodes___children contentNodes___nodes___children___children contentNodes___nodes___children___id contentNodes___nodes___contentTypeName contentNodes___nodes___databaseId contentNodes___nodes___date contentNodes___nodes___dateGmt contentNodes___nodes___desiredSlug contentNodes___nodes___enclosure contentNodes___nodes___guid contentNodes___nodes___id contentNodes___nodes___internal___content contentNodes___nodes___internal___contentDigest contentNodes___nodes___internal___description contentNodes___nodes___internal___fieldOwners contentNodes___nodes___internal___ignoreType contentNodes___nodes___internal___mediaType contentNodes___nodes___internal___owner contentNodes___nodes___internal___type contentNodes___nodes___isContentNode contentNodes___nodes___isTermNode contentNodes___nodes___link contentNodes___nodes___modified contentNodes___nodes___modifiedGmt contentNodes___nodes___nodeType contentNodes___nodes___parent___children contentNodes___nodes___parent___id contentNodes___nodes___slug contentNodes___nodes___status contentNodes___nodes___template___templateName contentNodes___nodes___uri deleteWithUser description excludeFromSearch graphqlPluralName graphqlSingleName hasArchive hierarchical id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isFrontPage isPostsPage isTermNode label labels___addNew labels___addNewItem labels___allItems labels___archives labels___attributes labels___editItem labels___featuredImage labels___filterItemsList labels___insertIntoItem labels___itemsList labels___itemsListNavigation labels___menuName labels___name labels___newItem labels___notFound labels___notFoundInTrash labels___parentItemColon labels___removeFeaturedImage labels___searchItems labels___setFeaturedImage labels___singularName labels___uploadedToThisItem labels___useFeaturedImage labels___viewItem labels___viewItems menuIcon menuPosition name nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id public publiclyQueryable restBase restControllerClass showInAdminBar showInGraphql showInMenu showInNavMenus showInRest showUi uri } input WpContentTypeFilterInput { archivePath: StringQueryOperatorInput canExport: BooleanQueryOperatorInput children: NodeFilterListInput connectedTaxonomies: WpContentTypeToTaxonomyConnectionFilterInput contentNodes: WpContentTypeToContentNodeConnectionFilterInput deleteWithUser: BooleanQueryOperatorInput description: StringQueryOperatorInput excludeFromSearch: BooleanQueryOperatorInput graphqlPluralName: StringQueryOperatorInput graphqlSingleName: StringQueryOperatorInput hasArchive: BooleanQueryOperatorInput hierarchical: BooleanQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isFrontPage: BooleanQueryOperatorInput isPostsPage: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput label: StringQueryOperatorInput labels: WpPostTypeLabelDetailsFilterInput menuIcon: StringQueryOperatorInput menuPosition: IntQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput public: BooleanQueryOperatorInput publiclyQueryable: BooleanQueryOperatorInput restBase: StringQueryOperatorInput restControllerClass: StringQueryOperatorInput showInAdminBar: BooleanQueryOperatorInput showInGraphql: BooleanQueryOperatorInput showInMenu: BooleanQueryOperatorInput showInNavMenus: BooleanQueryOperatorInput showInRest: BooleanQueryOperatorInput showUi: BooleanQueryOperatorInput uri: StringQueryOperatorInput } input WpContentTypeFilterListInput { elemMatch: WpContentTypeFilterInput } type WpContentTypeGroupConnection { distinct(field: WpContentTypeFieldsEnum!): [String!]! edges: [WpContentTypeEdge!]! field: String! fieldValue: String group(field: WpContentTypeFieldsEnum!, limit: Int, skip: Int): [WpContentTypeGroupConnection!]! max(field: WpContentTypeFieldsEnum!): Float min(field: WpContentTypeFieldsEnum!): Float nodes: [WpContentType!]! pageInfo: PageInfo! sum(field: WpContentTypeFieldsEnum!): Float totalCount: Int! } input WpContentTypeSortInput { fields: [WpContentTypeFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the ContentType type and the ContentNode type """ type WpContentTypeToContentNodeConnection { """ The nodes of the connection, without the edges """ nodes: [WpContentNode] } input WpContentTypeToContentNodeConnectionFilterInput { nodes: WpContentNodeFilterListInput } """ Connection between the ContentType type and the Taxonomy type """ type WpContentTypeToTaxonomyConnection { """ The nodes of the connection, without the edges """ nodes: [WpTaxonomy] } input WpContentTypeToTaxonomyConnectionFilterInput { nodes: WpTaxonomyFilterListInput } """ core/archives block """ type WpCoreArchivesBlock implements WpBlock { attributes: WpCoreArchivesBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreArchivesBlockAttributes { align: String className: String displayAsDropdown: Boolean! lock: JSON showPostCounts: Boolean! } """ core/audio block """ type WpCoreAudioBlock implements WpBlock { attributes: WpCoreAudioBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreAudioBlockAttributes { align: String anchor: String autoplay: Boolean caption: String className: String id: Float lock: JSON loop: Boolean preload: String src: String } union WpCoreAudioBlockAttributesUnion = WpCoreAudioBlockAttributes | WpCoreAudioBlockDeprecatedV1Attributes type WpCoreAudioBlockDeprecatedV1Attributes { align: String anchor: String autoplay: Boolean caption: String className: String id: Float lock: JSON loop: Boolean preload: String src: String } """ core/block block """ type WpCoreBlock implements WpBlock { attributes: WpCoreBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! reusableBlock: WpNode! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreBlockAttributes { lock: JSON ref: Float } """ core/button block """ type WpCoreButtonBlock implements WpBlock { attributes: WpCoreButtonBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreButtonBlockAttributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } union WpCoreButtonBlockAttributesUnion = WpCoreButtonBlockAttributes | WpCoreButtonBlockDeprecatedV1Attributes | WpCoreButtonBlockDeprecatedV2Attributes | WpCoreButtonBlockDeprecatedV3Attributes | WpCoreButtonBlockDeprecatedV4Attributes | WpCoreButtonBlockDeprecatedV5Attributes | WpCoreButtonBlockDeprecatedV6Attributes | WpCoreButtonBlockDeprecatedV7Attributes | WpCoreButtonBlockDeprecatedV8Attributes | WpCoreButtonBlockDeprecatedV9Attributes | WpCoreButtonBlockDeprecatedV10Attributes type WpCoreButtonBlockDeprecatedV1Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } type WpCoreButtonBlockDeprecatedV2Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } type WpCoreButtonBlockDeprecatedV3Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } type WpCoreButtonBlockDeprecatedV4Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } type WpCoreButtonBlockDeprecatedV5Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } type WpCoreButtonBlockDeprecatedV6Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } type WpCoreButtonBlockDeprecatedV7Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } type WpCoreButtonBlockDeprecatedV8Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } type WpCoreButtonBlockDeprecatedV9Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } type WpCoreButtonBlockDeprecatedV10Attributes { align: String anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String linkTarget: String lock: JSON placeholder: String rel: String style: JSON text: String textColor: String title: String url: String width: Float } """ core/buttons block """ type WpCoreButtonsBlock implements WpBlock { attributes: WpCoreButtonsBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreButtonsBlockAttributes { align: String anchor: String className: String layout: JSON lock: JSON style: JSON } union WpCoreButtonsBlockAttributesUnion = WpCoreButtonsBlockAttributes | WpCoreButtonsBlockDeprecatedV1Attributes | WpCoreButtonsBlockDeprecatedV2Attributes type WpCoreButtonsBlockDeprecatedV1Attributes { align: String anchor: String className: String layout: JSON lock: JSON style: JSON } type WpCoreButtonsBlockDeprecatedV2Attributes { align: String anchor: String className: String layout: JSON lock: JSON style: JSON } """ core/calendar block """ type WpCoreCalendarBlock implements WpBlock { attributes: WpCoreCalendarBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreCalendarBlockAttributes { align: String className: String lock: JSON month: Int year: Int } """ core/categories block """ type WpCoreCategoriesBlock implements WpBlock { attributes: WpCoreCategoriesBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreCategoriesBlockAttributes { align: String className: String displayAsDropdown: Boolean! lock: JSON showHierarchy: Boolean! showOnlyTopLevel: Boolean! showPostCounts: Boolean! } """ core/code block """ type WpCoreCodeBlock implements WpBlock { attributes: WpCoreCodeBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreCodeBlockAttributes { anchor: String backgroundColor: String borderColor: String className: String content: String fontSize: String gradient: String lock: JSON style: JSON textColor: String } """ core/column block """ type WpCoreColumnBlock implements WpBlock { attributes: WpCoreColumnBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreColumnBlockAttributes { allowedBlocks: JSON anchor: String backgroundColor: String className: String gradient: String lock: JSON style: JSON textColor: String verticalAlignment: String width: String } union WpCoreColumnBlockAttributesUnion = WpCoreColumnBlockAttributes | WpCoreColumnBlockDeprecatedV1Attributes type WpCoreColumnBlockDeprecatedV1Attributes { allowedBlocks: JSON anchor: String backgroundColor: String className: String gradient: String lock: JSON style: JSON textColor: String verticalAlignment: String width: String } """ core/columns block """ type WpCoreColumnsBlock implements WpBlock { attributes: WpCoreColumnsBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreColumnsBlockAttributes { align: String anchor: String backgroundColor: String className: String gradient: String isStackedOnMobile: Boolean! lock: JSON style: JSON textColor: String verticalAlignment: String } union WpCoreColumnsBlockAttributesUnion = WpCoreColumnsBlockAttributes | WpCoreColumnsBlockDeprecatedV1Attributes | WpCoreColumnsBlockDeprecatedV2Attributes | WpCoreColumnsBlockDeprecatedV3Attributes type WpCoreColumnsBlockDeprecatedV1Attributes { align: String anchor: String backgroundColor: String className: String gradient: String isStackedOnMobile: Boolean! lock: JSON style: JSON textColor: String verticalAlignment: String } type WpCoreColumnsBlockDeprecatedV2Attributes { align: String anchor: String backgroundColor: String className: String gradient: String isStackedOnMobile: Boolean! lock: JSON style: JSON textColor: String verticalAlignment: String } type WpCoreColumnsBlockDeprecatedV3Attributes { align: String anchor: String backgroundColor: String className: String gradient: String isStackedOnMobile: Boolean! lock: JSON style: JSON textColor: String verticalAlignment: String } """ core/cover block """ type WpCoreCoverBlock implements WpBlock { attributes: WpCoreCoverBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreCoverBlockAttributes { align: String allowedBlocks: JSON alt: String! anchor: String backgroundType: String! className: String contentPosition: String customGradient: String customOverlayColor: String dimRatio: Float! focalPoint: JSON gradient: String hasParallax: Boolean! id: Float isDark: Boolean! isRepeated: Boolean! lock: JSON minHeight: Float minHeightUnit: String overlayColor: String style: JSON url: String } union WpCoreCoverBlockAttributesUnion = WpCoreCoverBlockAttributes | WpCoreCoverBlockDeprecatedV1Attributes | WpCoreCoverBlockDeprecatedV2Attributes | WpCoreCoverBlockDeprecatedV3Attributes | WpCoreCoverBlockDeprecatedV4Attributes | WpCoreCoverBlockDeprecatedV5Attributes | WpCoreCoverBlockDeprecatedV6Attributes | WpCoreCoverBlockDeprecatedV7Attributes type WpCoreCoverBlockDeprecatedV1Attributes { align: String allowedBlocks: JSON alt: String! anchor: String backgroundType: String! className: String contentPosition: String customGradient: String customOverlayColor: String dimRatio: Float! focalPoint: JSON gradient: String hasParallax: Boolean! id: Float isDark: Boolean! isRepeated: Boolean! lock: JSON minHeight: Float minHeightUnit: String overlayColor: String style: JSON url: String } type WpCoreCoverBlockDeprecatedV2Attributes { align: String allowedBlocks: JSON alt: String! anchor: String backgroundType: String! className: String contentPosition: String customGradient: String customOverlayColor: String dimRatio: Float! focalPoint: JSON gradient: String hasParallax: Boolean! id: Float isDark: Boolean! isRepeated: Boolean! lock: JSON minHeight: Float minHeightUnit: String overlayColor: String style: JSON url: String } type WpCoreCoverBlockDeprecatedV3Attributes { align: String allowedBlocks: JSON alt: String! anchor: String backgroundType: String! className: String contentPosition: String customGradient: String customOverlayColor: String dimRatio: Float! focalPoint: JSON gradient: String hasParallax: Boolean! id: Float isDark: Boolean! isRepeated: Boolean! lock: JSON minHeight: Float minHeightUnit: String overlayColor: String style: JSON url: String } type WpCoreCoverBlockDeprecatedV4Attributes { align: String allowedBlocks: JSON alt: String! anchor: String backgroundType: String! className: String contentPosition: String customGradient: String customOverlayColor: String dimRatio: Float! focalPoint: JSON gradient: String hasParallax: Boolean! id: Float isDark: Boolean! isRepeated: Boolean! lock: JSON minHeight: Float minHeightUnit: String overlayColor: String style: JSON url: String } type WpCoreCoverBlockDeprecatedV5Attributes { align: String allowedBlocks: JSON alt: String! anchor: String backgroundType: String! className: String contentPosition: String customGradient: String customOverlayColor: String dimRatio: Float! focalPoint: JSON gradient: String hasParallax: Boolean! id: Float isDark: Boolean! isRepeated: Boolean! lock: JSON minHeight: Float minHeightUnit: String overlayColor: String style: JSON url: String } type WpCoreCoverBlockDeprecatedV6Attributes { align: String allowedBlocks: JSON alt: String! anchor: String backgroundType: String! className: String contentPosition: String customGradient: String customOverlayColor: String dimRatio: Float! focalPoint: JSON gradient: String hasParallax: Boolean! id: Float isDark: Boolean! isRepeated: Boolean! lock: JSON minHeight: Float minHeightUnit: String overlayColor: String style: JSON url: String } type WpCoreCoverBlockDeprecatedV7Attributes { align: String allowedBlocks: JSON alt: String! anchor: String backgroundType: String! className: String contentPosition: String customGradient: String customOverlayColor: String dimRatio: Float! focalPoint: JSON gradient: String hasParallax: Boolean! id: Float isDark: Boolean! isRepeated: Boolean! lock: JSON minHeight: Float minHeightUnit: String overlayColor: String style: JSON url: String } """ core/embed block """ type WpCoreEmbedBlock implements WpBlock { attributes: WpCoreEmbedBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreEmbedBlockAttributes { align: String allowResponsive: Boolean! caption: String className: String lock: JSON previewable: Boolean! providerNameSlug: String responsive: Boolean! type: String url: String } union WpCoreEmbedBlockAttributesUnion = WpCoreEmbedBlockAttributes | WpCoreEmbedBlockDeprecatedV1Attributes type WpCoreEmbedBlockDeprecatedV1Attributes { align: String allowResponsive: Boolean! caption: String className: String lock: JSON previewable: Boolean! providerNameSlug: String responsive: Boolean! type: String url: String } """ core/file block """ type WpCoreFileBlock implements WpBlock { attributes: WpCoreFileBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreFileBlockAttributes { align: String anchor: String className: String displayPreview: Boolean downloadButtonText: String fileId: String fileName: String href: String id: Float lock: JSON previewHeight: Float! showDownloadButton: Boolean! textLinkHref: String textLinkTarget: String } union WpCoreFileBlockAttributesUnion = WpCoreFileBlockAttributes | WpCoreFileBlockDeprecatedV1Attributes type WpCoreFileBlockDeprecatedV1Attributes { align: String anchor: String className: String displayPreview: Boolean downloadButtonText: String fileId: String fileName: String href: String id: Float lock: JSON previewHeight: Float! showDownloadButton: Boolean! textLinkHref: String textLinkTarget: String } """ core/freeform block """ type WpCoreFreeformBlock implements WpBlock { attributes: WpCoreFreeformBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreFreeformBlockAttributes { content: String lock: JSON } """ core/gallery block """ type WpCoreGalleryBlock implements WpBlock { attributes: WpCoreGalleryBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreGalleryBlockAttributes { align: String allowResize: Boolean! anchor: String caption: String className: String columns: Float fixedHeight: Boolean! ids: [Float]! imageCrop: Boolean! images: [WpCoreGalleryBlockAttributesImages]! linkTarget: String linkTo: String lock: JSON shortCodeTransforms: [WpBlockAttributesObject]! sizeSlug: String! } type WpCoreGalleryBlockAttributesImages { alt: String! caption: String fullUrl: String id: String link: String url: String } union WpCoreGalleryBlockAttributesUnion = WpCoreGalleryBlockAttributes | WpCoreGalleryBlockDeprecatedV1Attributes | WpCoreGalleryBlockDeprecatedV2Attributes | WpCoreGalleryBlockDeprecatedV3Attributes | WpCoreGalleryBlockDeprecatedV4Attributes | WpCoreGalleryBlockDeprecatedV5Attributes | WpCoreGalleryBlockDeprecatedV6Attributes type WpCoreGalleryBlockDeprecatedV1Attributes { align: String allowResize: Boolean! anchor: String caption: String className: String columns: Float fixedHeight: Boolean! ids: [Float]! imageCrop: Boolean! images: [WpCoreGalleryBlockDeprecatedV1AttributesImages]! linkTarget: String linkTo: String lock: JSON shortCodeTransforms: [WpBlockAttributesObject]! sizeSlug: String! } type WpCoreGalleryBlockDeprecatedV1AttributesImages { alt: String! caption: String fullUrl: String id: String link: String url: String } type WpCoreGalleryBlockDeprecatedV2Attributes { align: String allowResize: Boolean! anchor: String caption: String className: String columns: Float fixedHeight: Boolean! ids: [Float]! imageCrop: Boolean! images: [WpCoreGalleryBlockDeprecatedV2AttributesImages]! linkTarget: String linkTo: String lock: JSON shortCodeTransforms: [WpBlockAttributesObject]! sizeSlug: String! } type WpCoreGalleryBlockDeprecatedV2AttributesImages { alt: String! caption: String fullUrl: String id: String link: String url: String } type WpCoreGalleryBlockDeprecatedV3Attributes { align: String allowResize: Boolean! anchor: String caption: String className: String columns: Float fixedHeight: Boolean! ids: [Float]! imageCrop: Boolean! images: [WpCoreGalleryBlockDeprecatedV3AttributesImages]! linkTarget: String linkTo: String lock: JSON shortCodeTransforms: [WpBlockAttributesObject]! sizeSlug: String! } type WpCoreGalleryBlockDeprecatedV3AttributesImages { alt: String! caption: String fullUrl: String id: String link: String url: String } type WpCoreGalleryBlockDeprecatedV4Attributes { align: String allowResize: Boolean! anchor: String caption: String className: String columns: Float fixedHeight: Boolean! ids: [Float]! imageCrop: Boolean! images: [WpCoreGalleryBlockDeprecatedV4AttributesImages]! linkTarget: String linkTo: String lock: JSON shortCodeTransforms: [WpBlockAttributesObject]! sizeSlug: String! } type WpCoreGalleryBlockDeprecatedV4AttributesImages { alt: String! caption: String fullUrl: String id: String link: String url: String } type WpCoreGalleryBlockDeprecatedV5Attributes { align: String allowResize: Boolean! anchor: String caption: String className: String columns: Float fixedHeight: Boolean! ids: [Float]! imageCrop: Boolean! images: [WpCoreGalleryBlockDeprecatedV5AttributesImages]! linkTarget: String linkTo: String lock: JSON shortCodeTransforms: [WpBlockAttributesObject]! sizeSlug: String! } type WpCoreGalleryBlockDeprecatedV5AttributesImages { alt: String! caption: String fullUrl: String id: String link: String url: String } type WpCoreGalleryBlockDeprecatedV6Attributes { align: String allowResize: Boolean! anchor: String caption: String className: String columns: Float fixedHeight: Boolean! ids: [Float]! imageCrop: Boolean! images: [WpCoreGalleryBlockDeprecatedV6AttributesImages]! linkTarget: String linkTo: String lock: JSON shortCodeTransforms: [WpBlockAttributesObject]! sizeSlug: String! } type WpCoreGalleryBlockDeprecatedV6AttributesImages { alt: String! caption: String fullUrl: String id: String link: String url: String } """ core/group block """ type WpCoreGroupBlock implements WpBlock { attributes: WpCoreGroupBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreGroupBlockAttributes { align: String anchor: String backgroundColor: String borderColor: String className: String gradient: String layout: JSON lock: JSON style: JSON tagName: String! textColor: String } union WpCoreGroupBlockAttributesUnion = WpCoreGroupBlockAttributes | WpCoreGroupBlockDeprecatedV1Attributes | WpCoreGroupBlockDeprecatedV2Attributes | WpCoreGroupBlockDeprecatedV3Attributes | WpCoreGroupBlockDeprecatedV4Attributes type WpCoreGroupBlockDeprecatedV1Attributes { align: String anchor: String backgroundColor: String borderColor: String className: String gradient: String layout: JSON lock: JSON style: JSON tagName: String! textColor: String } type WpCoreGroupBlockDeprecatedV2Attributes { align: String anchor: String backgroundColor: String borderColor: String className: String gradient: String layout: JSON lock: JSON style: JSON tagName: String! textColor: String } type WpCoreGroupBlockDeprecatedV3Attributes { align: String anchor: String backgroundColor: String borderColor: String className: String gradient: String layout: JSON lock: JSON style: JSON tagName: String! textColor: String } type WpCoreGroupBlockDeprecatedV4Attributes { align: String anchor: String backgroundColor: String borderColor: String className: String gradient: String layout: JSON lock: JSON style: JSON tagName: String! textColor: String } """ core/heading block """ type WpCoreHeadingBlock implements WpBlock { attributes: WpCoreHeadingBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreHeadingBlockAttributes { align: String anchor: String backgroundColor: String className: String content: String! fontSize: String level: Float! lock: JSON placeholder: String style: JSON textAlign: String textColor: String } union WpCoreHeadingBlockAttributesUnion = WpCoreHeadingBlockAttributes | WpCoreHeadingBlockDeprecatedV1Attributes | WpCoreHeadingBlockDeprecatedV2Attributes | WpCoreHeadingBlockDeprecatedV3Attributes | WpCoreHeadingBlockDeprecatedV4Attributes type WpCoreHeadingBlockDeprecatedV1Attributes { align: String anchor: String backgroundColor: String className: String content: String! fontSize: String level: Float! lock: JSON placeholder: String style: JSON textAlign: String textColor: String } type WpCoreHeadingBlockDeprecatedV2Attributes { align: String anchor: String backgroundColor: String className: String content: String! fontSize: String level: Float! lock: JSON placeholder: String style: JSON textAlign: String textColor: String } type WpCoreHeadingBlockDeprecatedV3Attributes { align: String anchor: String backgroundColor: String className: String content: String! fontSize: String level: Float! lock: JSON placeholder: String style: JSON textAlign: String textColor: String } type WpCoreHeadingBlockDeprecatedV4Attributes { align: String anchor: String backgroundColor: String className: String content: String! fontSize: String level: Float! lock: JSON placeholder: String style: JSON textAlign: String textColor: String } """ core/html block """ type WpCoreHtmlBlock implements WpBlock { attributes: WpCoreHtmlBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreHtmlBlockAttributes { content: String lock: JSON } """ core/image block """ type WpCoreImageBlock implements WpBlock { attributes: WpCoreImageBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreImageBlockAttributes { align: String alt: String! anchor: String caption: String className: String height: Float href: String id: Float imageFluid: File linkClass: String linkDestination: String linkTarget: String lock: JSON rel: String sizeSlug: String style: JSON title: String url: String width: Float } union WpCoreImageBlockAttributesUnion = WpCoreImageBlockAttributes | WpCoreImageBlockDeprecatedV1Attributes | WpCoreImageBlockDeprecatedV2Attributes | WpCoreImageBlockDeprecatedV3Attributes type WpCoreImageBlockDeprecatedV1Attributes { align: String alt: String! anchor: String caption: String className: String height: Float href: String id: Float linkClass: String linkDestination: String linkTarget: String lock: JSON rel: String sizeSlug: String style: JSON title: String url: String width: Float } type WpCoreImageBlockDeprecatedV2Attributes { align: String alt: String! anchor: String caption: String className: String height: Float href: String id: Float linkClass: String linkDestination: String linkTarget: String lock: JSON rel: String sizeSlug: String style: JSON title: String url: String width: Float } type WpCoreImageBlockDeprecatedV3Attributes { align: String alt: String! anchor: String caption: String className: String height: Float href: String id: Float linkClass: String linkDestination: String linkTarget: String lock: JSON rel: String sizeSlug: String style: JSON title: String url: String width: Float } """ core/latest-comments block """ type WpCoreLatestCommentsBlock implements WpBlock { attributes: WpCoreLatestCommentsBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreLatestCommentsBlockAttributes { align: String className: String commentsToShow: Float! displayAvatar: Boolean! displayDate: Boolean! displayExcerpt: Boolean! lock: JSON } """ core/latest-posts block """ type WpCoreLatestPostsBlock implements WpBlock { attributes: WpCoreLatestPostsBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreLatestPostsBlockAttributes { addLinkToFeaturedImage: Boolean! align: String categories: [JSON] className: String columns: Float! displayAuthor: Boolean! displayFeaturedImage: Boolean! displayPostContent: Boolean! displayPostContentRadio: String! displayPostDate: Boolean! excerptLength: Float! featuredImageAlign: String featuredImageSizeHeight: Float featuredImageSizeSlug: String! featuredImageSizeWidth: Float lock: JSON order: String! orderBy: String! postLayout: String! postsToShow: Float! selectedAuthor: Float } union WpCoreLatestPostsBlockAttributesUnion = WpCoreLatestPostsBlockAttributes | WpCoreLatestPostsBlockDeprecatedV1Attributes type WpCoreLatestPostsBlockDeprecatedV1Attributes { addLinkToFeaturedImage: Boolean! align: String categories: [JSON] className: String columns: Float! displayAuthor: Boolean! displayFeaturedImage: Boolean! displayPostContent: Boolean! displayPostContentRadio: String! displayPostDate: Boolean! excerptLength: Float! featuredImageAlign: String featuredImageSizeHeight: Float featuredImageSizeSlug: String! featuredImageSizeWidth: Float lock: JSON order: String! orderBy: String! postLayout: String! postsToShow: Float! selectedAuthor: Float } """ core/legacy-widget block """ type WpCoreLegacyWidgetBlock implements WpBlock { attributes: WpCoreLegacyWidgetBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreLegacyWidgetBlockAttributes { id: String idBase: String instance: JSON lock: JSON } """ core/list block """ type WpCoreListBlock implements WpBlock { attributes: WpCoreListBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreListBlockAttributes { anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String lock: JSON ordered: Boolean! placeholder: String reversed: Boolean start: Float style: JSON textColor: String type: String values: String! } union WpCoreListBlockAttributesUnion = WpCoreListBlockAttributes | WpCoreListBlockDeprecatedV1Attributes type WpCoreListBlockDeprecatedV1Attributes { anchor: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String lock: JSON ordered: Boolean! placeholder: String reversed: Boolean start: Float style: JSON textColor: String type: String values: String! } """ core/loginout block """ type WpCoreLoginoutBlock implements WpBlock { attributes: WpCoreLoginoutBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreLoginoutBlockAttributes { className: String displayLoginAsForm: Boolean! lock: JSON redirectToCurrent: Boolean! } """ core/media-text block """ type WpCoreMediaTextBlock implements WpBlock { attributes: WpCoreMediaTextBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreMediaTextBlockAttributes { align: String! anchor: String backgroundColor: String className: String focalPoint: JSON gradient: String href: String imageFill: Boolean isStackedOnMobile: Boolean! linkClass: String linkDestination: String linkTarget: String lock: JSON mediaAlt: String! mediaId: Float mediaLink: String mediaPosition: String! mediaSizeSlug: String mediaType: String mediaUrl: String mediaWidth: Float! rel: String style: JSON textColor: String verticalAlignment: String } union WpCoreMediaTextBlockAttributesUnion = WpCoreMediaTextBlockAttributes | WpCoreMediaTextBlockDeprecatedV1Attributes | WpCoreMediaTextBlockDeprecatedV2Attributes | WpCoreMediaTextBlockDeprecatedV3Attributes type WpCoreMediaTextBlockDeprecatedV1Attributes { align: String! anchor: String backgroundColor: String className: String focalPoint: JSON gradient: String href: String imageFill: Boolean isStackedOnMobile: Boolean! linkClass: String linkDestination: String linkTarget: String lock: JSON mediaAlt: String! mediaId: Float mediaLink: String mediaPosition: String! mediaSizeSlug: String mediaType: String mediaUrl: String mediaWidth: Float! rel: String style: JSON textColor: String verticalAlignment: String } type WpCoreMediaTextBlockDeprecatedV2Attributes { align: String! anchor: String backgroundColor: String className: String focalPoint: JSON gradient: String href: String imageFill: Boolean isStackedOnMobile: Boolean! linkClass: String linkDestination: String linkTarget: String lock: JSON mediaAlt: String! mediaId: Float mediaLink: String mediaPosition: String! mediaSizeSlug: String mediaType: String mediaUrl: String mediaWidth: Float! rel: String style: JSON textColor: String verticalAlignment: String } type WpCoreMediaTextBlockDeprecatedV3Attributes { align: String! anchor: String backgroundColor: String className: String focalPoint: JSON gradient: String href: String imageFill: Boolean isStackedOnMobile: Boolean! linkClass: String linkDestination: String linkTarget: String lock: JSON mediaAlt: String! mediaId: Float mediaLink: String mediaPosition: String! mediaSizeSlug: String mediaType: String mediaUrl: String mediaWidth: Float! rel: String style: JSON textColor: String verticalAlignment: String } """ core/missing block """ type WpCoreMissingBlock implements WpBlock { attributes: WpCoreMissingBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreMissingBlockAttributes { lock: JSON originalContent: String originalName: String originalUndelimitedContent: String } """ core/more block """ type WpCoreMoreBlock implements WpBlock { attributes: WpCoreMoreBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreMoreBlockAttributes { customText: String lock: JSON noTeaser: Boolean! } """ core/navigation block """ type WpCoreNavigationBlock implements WpBlock { attributes: WpCoreNavigationBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreNavigationBlockAttributes { align: String anchor: String backgroundColor: String className: String customBackgroundColor: String customOverlayBackgroundColor: String customOverlayTextColor: String customTextColor: String fontFamily: String fontSize: String layout: JSON lock: JSON openSubmenusOnClick: Boolean! overlayBackgroundColor: String overlayMenu: String! overlayTextColor: String ref: Float rgbBackgroundColor: String rgbTextColor: String showSubmenuIcon: Boolean! style: JSON textColor: String unstableLocation: String } union WpCoreNavigationBlockAttributesUnion = WpCoreNavigationBlockAttributes | WpCoreNavigationBlockDeprecatedV1Attributes | WpCoreNavigationBlockDeprecatedV2Attributes | WpCoreNavigationBlockDeprecatedV3Attributes | WpCoreNavigationBlockDeprecatedV4Attributes | WpCoreNavigationBlockDeprecatedV5Attributes | WpCoreNavigationBlockDeprecatedV6Attributes type WpCoreNavigationBlockDeprecatedV1Attributes { align: String anchor: String backgroundColor: String className: String customBackgroundColor: String customOverlayBackgroundColor: String customOverlayTextColor: String customTextColor: String fontFamily: String fontSize: String layout: JSON lock: JSON openSubmenusOnClick: Boolean! overlayBackgroundColor: String overlayMenu: String! overlayTextColor: String ref: Float rgbBackgroundColor: String rgbTextColor: String showSubmenuIcon: Boolean! style: JSON textColor: String unstableLocation: String } type WpCoreNavigationBlockDeprecatedV2Attributes { align: String anchor: String backgroundColor: String className: String customBackgroundColor: String customOverlayBackgroundColor: String customOverlayTextColor: String customTextColor: String fontFamily: String fontSize: String layout: JSON lock: JSON openSubmenusOnClick: Boolean! overlayBackgroundColor: String overlayMenu: String! overlayTextColor: String ref: Float rgbBackgroundColor: String rgbTextColor: String showSubmenuIcon: Boolean! style: JSON textColor: String unstableLocation: String } type WpCoreNavigationBlockDeprecatedV3Attributes { align: String anchor: String backgroundColor: String className: String customBackgroundColor: String customOverlayBackgroundColor: String customOverlayTextColor: String customTextColor: String fontFamily: String fontSize: String layout: JSON lock: JSON openSubmenusOnClick: Boolean! overlayBackgroundColor: String overlayMenu: String! overlayTextColor: String ref: Float rgbBackgroundColor: String rgbTextColor: String showSubmenuIcon: Boolean! style: JSON textColor: String unstableLocation: String } type WpCoreNavigationBlockDeprecatedV4Attributes { align: String anchor: String backgroundColor: String className: String customBackgroundColor: String customOverlayBackgroundColor: String customOverlayTextColor: String customTextColor: String fontFamily: String fontSize: String layout: JSON lock: JSON openSubmenusOnClick: Boolean! overlayBackgroundColor: String overlayMenu: String! overlayTextColor: String ref: Float rgbBackgroundColor: String rgbTextColor: String showSubmenuIcon: Boolean! style: JSON textColor: String unstableLocation: String } type WpCoreNavigationBlockDeprecatedV5Attributes { align: String anchor: String backgroundColor: String className: String customBackgroundColor: String customOverlayBackgroundColor: String customOverlayTextColor: String customTextColor: String fontFamily: String fontSize: String layout: JSON lock: JSON openSubmenusOnClick: Boolean! overlayBackgroundColor: String overlayMenu: String! overlayTextColor: String ref: Float rgbBackgroundColor: String rgbTextColor: String showSubmenuIcon: Boolean! style: JSON textColor: String unstableLocation: String } type WpCoreNavigationBlockDeprecatedV6Attributes { align: String anchor: String backgroundColor: String className: String customBackgroundColor: String customOverlayBackgroundColor: String customOverlayTextColor: String customTextColor: String fontFamily: String fontSize: String layout: JSON lock: JSON openSubmenusOnClick: Boolean! overlayBackgroundColor: String overlayMenu: String! overlayTextColor: String ref: Float rgbBackgroundColor: String rgbTextColor: String showSubmenuIcon: Boolean! style: JSON textColor: String unstableLocation: String } """ core/navigation-link block """ type WpCoreNavigationLinkBlock implements WpBlock { attributes: WpCoreNavigationLinkBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreNavigationLinkBlockAttributes { className: String description: String id: Float isTopLevelLink: Boolean kind: String label: String lock: JSON opensInNewTab: Boolean! rel: String title: String type: String url: String } union WpCoreNavigationLinkBlockAttributesUnion = WpCoreNavigationLinkBlockAttributes | WpCoreNavigationLinkBlockDeprecatedV1Attributes type WpCoreNavigationLinkBlockDeprecatedV1Attributes { className: String description: String id: Float isTopLevelLink: Boolean kind: String label: String lock: JSON opensInNewTab: Boolean! rel: String title: String type: String url: String } """ core/navigation-submenu block """ type WpCoreNavigationSubmenuBlock implements WpBlock { attributes: WpCoreNavigationSubmenuBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreNavigationSubmenuBlockAttributes { className: String description: String id: Float isTopLevelItem: Boolean kind: String label: String lock: JSON opensInNewTab: Boolean! rel: String title: String type: String url: String } """ core/nextpage block """ type WpCoreNextpageBlock implements WpBlock { """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreNextpageBlockAttributes { lock: JSON } """ core/page-list block """ type WpCorePageListBlock implements WpBlock { attributes: WpCorePageListBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePageListBlockAttributes { className: String lock: JSON } """ core/paragraph block """ type WpCoreParagraphBlock implements WpBlock { attributes: WpCoreParagraphBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreParagraphBlockAttributes { align: String anchor: String backgroundColor: String className: String content: String! direction: String dropCap: Boolean! fontSize: String lock: JSON placeholder: String style: JSON textColor: String } union WpCoreParagraphBlockAttributesUnion = WpCoreParagraphBlockAttributes | WpCoreParagraphBlockDeprecatedV1Attributes | WpCoreParagraphBlockDeprecatedV2Attributes | WpCoreParagraphBlockDeprecatedV3Attributes | WpCoreParagraphBlockDeprecatedV4Attributes | WpCoreParagraphBlockDeprecatedV5Attributes type WpCoreParagraphBlockDeprecatedV1Attributes { align: String anchor: String backgroundColor: String className: String content: String! direction: String dropCap: Boolean! fontSize: String lock: JSON placeholder: String style: JSON textColor: String } type WpCoreParagraphBlockDeprecatedV2Attributes { align: String anchor: String backgroundColor: String className: String content: String! direction: String dropCap: Boolean! fontSize: String lock: JSON placeholder: String style: JSON textColor: String } type WpCoreParagraphBlockDeprecatedV3Attributes { align: String anchor: String backgroundColor: String className: String content: String! direction: String dropCap: Boolean! fontSize: String lock: JSON placeholder: String style: JSON textColor: String } type WpCoreParagraphBlockDeprecatedV4Attributes { align: String anchor: String backgroundColor: String className: String content: String! direction: String dropCap: Boolean! fontSize: String lock: JSON placeholder: String style: JSON textColor: String } type WpCoreParagraphBlockDeprecatedV5Attributes { align: String anchor: String backgroundColor: String className: String content: String! direction: String dropCap: Boolean! fontSize: String lock: JSON placeholder: String style: JSON textColor: String } """ core/pattern block """ type WpCorePatternBlock implements WpBlock { attributes: WpCorePatternBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePatternBlockAttributes { className: String lock: JSON slug: String } """ core/post-author block """ type WpCorePostAuthorBlock implements WpBlock { attributes: WpCorePostAuthorBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostAuthorBlockAttributes { avatarSize: Float! backgroundColor: String byline: String className: String fontSize: String gradient: String lock: JSON showAvatar: Boolean! showBio: Boolean style: JSON textAlign: String textColor: String } """ core/post-comments block """ type WpCorePostCommentsBlock implements WpBlock { attributes: WpCorePostCommentsBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostCommentsBlockAttributes { align: String backgroundColor: String className: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String } """ core/post-content block """ type WpCorePostContentBlock implements WpBlock { attributes: WpCorePostContentBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostContentBlockAttributes { align: String className: String layout: JSON lock: JSON } """ core/post-date block """ type WpCorePostDateBlock implements WpBlock { attributes: WpCorePostDateBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostDateBlockAttributes { backgroundColor: String className: String fontFamily: String fontSize: String format: String gradient: String isLink: Boolean! lock: JSON style: JSON textAlign: String textColor: String } union WpCorePostDateBlockAttributesUnion = WpCorePostDateBlockAttributes | WpCorePostDateBlockDeprecatedV1Attributes type WpCorePostDateBlockDeprecatedV1Attributes { backgroundColor: String className: String fontFamily: String fontSize: String format: String gradient: String isLink: Boolean! lock: JSON style: JSON textAlign: String textColor: String } """ core/post-excerpt block """ type WpCorePostExcerptBlock implements WpBlock { attributes: WpCorePostExcerptBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostExcerptBlockAttributes { backgroundColor: String className: String fontSize: String gradient: String lock: JSON moreText: String showMoreOnNewLine: Boolean! style: JSON textAlign: String textColor: String } """ core/post-featured-image block """ type WpCorePostFeaturedImageBlock implements WpBlock { attributes: WpCorePostFeaturedImageBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostFeaturedImageBlockAttributes { align: String className: String height: String isLink: Boolean! lock: JSON scale: String! style: JSON width: String } """ core/post-navigation-link block """ type WpCorePostNavigationLinkBlock implements WpBlock { attributes: WpCorePostNavigationLinkBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostNavigationLinkBlockAttributes { className: String fontSize: String label: String linkLabel: Boolean! lock: JSON showTitle: Boolean! style: JSON textAlign: String type: String! } """ core/post-template block """ type WpCorePostTemplateBlock implements WpBlock { attributes: WpCorePostTemplateBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostTemplateBlockAttributes { align: String className: String layout: JSON lock: JSON } """ core/post-terms block """ type WpCorePostTermsBlock implements WpBlock { attributes: WpCorePostTermsBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostTermsBlockAttributes { backgroundColor: String className: String fontSize: String gradient: String lock: JSON separator: String! style: JSON term: String textAlign: String textColor: String } """ core/post-title block """ type WpCorePostTitleBlock implements WpBlock { attributes: WpCorePostTitleBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePostTitleBlockAttributes { align: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String isLink: Boolean! level: Float! linkTarget: String! lock: JSON rel: String! style: JSON textAlign: String textColor: String } union WpCorePostTitleBlockAttributesUnion = WpCorePostTitleBlockAttributes | WpCorePostTitleBlockDeprecatedV1Attributes type WpCorePostTitleBlockDeprecatedV1Attributes { align: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String isLink: Boolean! level: Float! linkTarget: String! lock: JSON rel: String! style: JSON textAlign: String textColor: String } """ core/preformatted block """ type WpCorePreformattedBlock implements WpBlock { attributes: WpCorePreformattedBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePreformattedBlockAttributes { anchor: String backgroundColor: String className: String content: String! fontSize: String gradient: String lock: JSON style: JSON textColor: String } """ core/pullquote block """ type WpCorePullquoteBlock implements WpBlock { attributes: WpCorePullquoteBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCorePullquoteBlockAttributes { align: String anchor: String backgroundColor: String borderColor: String citation: String! className: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String value: String } union WpCorePullquoteBlockAttributesUnion = WpCorePullquoteBlockAttributes | WpCorePullquoteBlockDeprecatedV1Attributes | WpCorePullquoteBlockDeprecatedV2Attributes | WpCorePullquoteBlockDeprecatedV3Attributes | WpCorePullquoteBlockDeprecatedV4Attributes | WpCorePullquoteBlockDeprecatedV5Attributes type WpCorePullquoteBlockDeprecatedV1Attributes { align: String anchor: String backgroundColor: String borderColor: String citation: String! className: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String value: String } type WpCorePullquoteBlockDeprecatedV2Attributes { align: String anchor: String backgroundColor: String borderColor: String citation: String! className: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String value: String } type WpCorePullquoteBlockDeprecatedV3Attributes { align: String anchor: String backgroundColor: String borderColor: String citation: String! className: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String value: String } type WpCorePullquoteBlockDeprecatedV4Attributes { align: String anchor: String backgroundColor: String borderColor: String citation: String! className: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String value: String } type WpCorePullquoteBlockDeprecatedV5Attributes { align: String anchor: String backgroundColor: String borderColor: String citation: String! className: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String value: String } """ core/query block """ type WpCoreQueryBlock implements WpBlock { attributes: WpCoreQueryBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreQueryBlockAttributes { align: String backgroundColor: String className: String displayLayout: JSON! gradient: String layout: JSON lock: JSON query: JSON! queryId: Float style: JSON tagName: String! textColor: String } union WpCoreQueryBlockAttributesUnion = WpCoreQueryBlockAttributes | WpCoreQueryBlockDeprecatedV1Attributes type WpCoreQueryBlockDeprecatedV1Attributes { align: String backgroundColor: String className: String displayLayout: JSON! gradient: String layout: JSON lock: JSON query: JSON! queryId: Float style: JSON tagName: String! textColor: String } """ core/query-pagination block """ type WpCoreQueryPaginationBlock implements WpBlock { attributes: WpCoreQueryPaginationBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreQueryPaginationBlockAttributes { align: String backgroundColor: String className: String gradient: String layout: JSON lock: JSON paginationArrow: String! style: JSON textColor: String } union WpCoreQueryPaginationBlockAttributesUnion = WpCoreQueryPaginationBlockAttributes | WpCoreQueryPaginationBlockDeprecatedV1Attributes type WpCoreQueryPaginationBlockDeprecatedV1Attributes { align: String backgroundColor: String className: String gradient: String layout: JSON lock: JSON paginationArrow: String! style: JSON textColor: String } """ core/query-pagination-next block """ type WpCoreQueryPaginationNextBlock implements WpBlock { attributes: WpCoreQueryPaginationNextBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreQueryPaginationNextBlockAttributes { backgroundColor: String className: String fontSize: String gradient: String label: String lock: JSON style: JSON textColor: String } """ core/query-pagination-numbers block """ type WpCoreQueryPaginationNumbersBlock implements WpBlock { attributes: WpCoreQueryPaginationNumbersBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreQueryPaginationNumbersBlockAttributes { className: String lock: JSON } """ core/query-pagination-previous block """ type WpCoreQueryPaginationPreviousBlock implements WpBlock { attributes: WpCoreQueryPaginationPreviousBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreQueryPaginationPreviousBlockAttributes { backgroundColor: String className: String fontSize: String gradient: String label: String lock: JSON style: JSON textColor: String } """ core/query-title block """ type WpCoreQueryTitleBlock implements WpBlock { attributes: WpCoreQueryTitleBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreQueryTitleBlockAttributes { align: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String level: Float! lock: JSON style: JSON textAlign: String textColor: String type: String } union WpCoreQueryTitleBlockAttributesUnion = WpCoreQueryTitleBlockAttributes | WpCoreQueryTitleBlockDeprecatedV1Attributes type WpCoreQueryTitleBlockDeprecatedV1Attributes { align: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String level: Float! lock: JSON style: JSON textAlign: String textColor: String type: String } """ core/quote block """ type WpCoreQuoteBlock implements WpBlock { attributes: WpCoreQuoteBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreQuoteBlockAttributes { align: String anchor: String citation: String! className: String fontSize: String lock: JSON style: JSON value: String! } union WpCoreQuoteBlockAttributesUnion = WpCoreQuoteBlockAttributes | WpCoreQuoteBlockDeprecatedV1Attributes | WpCoreQuoteBlockDeprecatedV2Attributes | WpCoreQuoteBlockDeprecatedV3Attributes type WpCoreQuoteBlockDeprecatedV1Attributes { align: String anchor: String citation: String! className: String fontSize: String lock: JSON style: JSON value: String! } type WpCoreQuoteBlockDeprecatedV2Attributes { align: String anchor: String citation: String! className: String fontSize: String lock: JSON style: JSON value: String! } type WpCoreQuoteBlockDeprecatedV3Attributes { align: String anchor: String citation: String! className: String fontSize: String lock: JSON style: JSON value: String! } """ core/rss block """ type WpCoreRssBlock implements WpBlock { attributes: WpCoreRssBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreRssBlockAttributes { align: String blockLayout: String! className: String columns: Float! displayAuthor: Boolean! displayDate: Boolean! displayExcerpt: Boolean! excerptLength: Float! feedURL: String! itemsToShow: Float! lock: JSON } """ core/search block """ type WpCoreSearchBlock implements WpBlock { attributes: WpCoreSearchBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreSearchBlockAttributes { align: String backgroundColor: String borderColor: String buttonPosition: String! buttonText: String buttonUseIcon: Boolean! className: String gradient: String label: String lock: JSON placeholder: String! showLabel: Boolean! style: JSON textColor: String width: Float widthUnit: String } """ core/separator block """ type WpCoreSeparatorBlock implements WpBlock { attributes: WpCoreSeparatorBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreSeparatorBlockAttributes { align: String anchor: String className: String color: String customColor: String lock: JSON } """ core/shortcode block """ type WpCoreShortcodeBlock implements WpBlock { attributes: WpCoreShortcodeBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreShortcodeBlockAttributes { lock: JSON text: String } """ core/site-logo block """ type WpCoreSiteLogoBlock implements WpBlock { attributes: WpCoreSiteLogoBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreSiteLogoBlockAttributes { align: String className: String isLink: Boolean! linkTarget: String! lock: JSON shouldSyncIcon: Boolean style: JSON width: Float } """ core/site-tagline block """ type WpCoreSiteTaglineBlock implements WpBlock { attributes: WpCoreSiteTaglineBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreSiteTaglineBlockAttributes { align: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String } union WpCoreSiteTaglineBlockAttributesUnion = WpCoreSiteTaglineBlockAttributes | WpCoreSiteTaglineBlockDeprecatedV1Attributes type WpCoreSiteTaglineBlockDeprecatedV1Attributes { align: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String } """ core/site-title block """ type WpCoreSiteTitleBlock implements WpBlock { attributes: WpCoreSiteTitleBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreSiteTitleBlockAttributes { align: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String isLink: Boolean! level: Float! linkTarget: String! lock: JSON style: JSON textAlign: String textColor: String } union WpCoreSiteTitleBlockAttributesUnion = WpCoreSiteTitleBlockAttributes | WpCoreSiteTitleBlockDeprecatedV1Attributes type WpCoreSiteTitleBlockDeprecatedV1Attributes { align: String backgroundColor: String className: String fontFamily: String fontSize: String gradient: String isLink: Boolean! level: Float! linkTarget: String! lock: JSON style: JSON textAlign: String textColor: String } """ core/social-link block """ type WpCoreSocialLinkBlock implements WpBlock { attributes: WpCoreSocialLinkBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreSocialLinkBlockAttributes { className: String label: String lock: JSON service: String url: String } """ core/social-links block """ type WpCoreSocialLinksBlock implements WpBlock { attributes: WpCoreSocialLinksBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreSocialLinksBlockAttributes { align: String anchor: String className: String customIconBackgroundColor: String customIconColor: String iconBackgroundColor: String iconBackgroundColorValue: String iconColor: String iconColorValue: String layout: JSON lock: JSON openInNewTab: Boolean! size: String style: JSON } union WpCoreSocialLinksBlockAttributesUnion = WpCoreSocialLinksBlockAttributes | WpCoreSocialLinksBlockDeprecatedV1Attributes type WpCoreSocialLinksBlockDeprecatedV1Attributes { align: String anchor: String className: String customIconBackgroundColor: String customIconColor: String iconBackgroundColor: String iconBackgroundColorValue: String iconColor: String iconColorValue: String layout: JSON lock: JSON openInNewTab: Boolean! size: String style: JSON } """ core/spacer block """ type WpCoreSpacerBlock implements WpBlock { attributes: WpCoreSpacerBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreSpacerBlockAttributes { anchor: String className: String height: String! lock: JSON width: String } union WpCoreSpacerBlockAttributesUnion = WpCoreSpacerBlockAttributes | WpCoreSpacerBlockDeprecatedV1Attributes type WpCoreSpacerBlockDeprecatedV1Attributes { anchor: String className: String height: String! lock: JSON width: String } """ core/table block """ type WpCoreTableBlock implements WpBlock { attributes: WpCoreTableBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreTableBlockAttributes { align: String anchor: String backgroundColor: String body: [WpCoreTableBlockAttributesBody]! borderColor: String caption: String! className: String fontSize: String foot: [WpCoreTableBlockAttributesFoot]! gradient: String hasFixedLayout: Boolean! head: [WpCoreTableBlockAttributesHead]! lock: JSON style: JSON textColor: String } type WpCoreTableBlockAttributesBody { cells: [WpCoreTableBlockAttributesBodyCells]! } type WpCoreTableBlockAttributesBodyCells { align: String content: String scope: String tag: String! } type WpCoreTableBlockAttributesFoot { cells: [WpCoreTableBlockAttributesFootCells]! } type WpCoreTableBlockAttributesFootCells { align: String content: String scope: String tag: String! } type WpCoreTableBlockAttributesHead { cells: [WpCoreTableBlockAttributesHeadCells]! } type WpCoreTableBlockAttributesHeadCells { align: String content: String scope: String tag: String! } union WpCoreTableBlockAttributesUnion = WpCoreTableBlockAttributes | WpCoreTableBlockDeprecatedV1Attributes | WpCoreTableBlockDeprecatedV2Attributes type WpCoreTableBlockDeprecatedV1Attributes { align: String anchor: String backgroundColor: String body: [WpCoreTableBlockDeprecatedV1AttributesBody]! borderColor: String caption: String! className: String fontSize: String foot: [WpCoreTableBlockDeprecatedV1AttributesFoot]! gradient: String hasFixedLayout: Boolean! head: [WpCoreTableBlockDeprecatedV1AttributesHead]! lock: JSON style: JSON textColor: String } type WpCoreTableBlockDeprecatedV1AttributesBody { cells: [WpCoreTableBlockDeprecatedV1AttributesBodyCells]! } type WpCoreTableBlockDeprecatedV1AttributesBodyCells { align: String content: String scope: String tag: String! } type WpCoreTableBlockDeprecatedV1AttributesFoot { cells: [WpCoreTableBlockDeprecatedV1AttributesFootCells]! } type WpCoreTableBlockDeprecatedV1AttributesFootCells { align: String content: String scope: String tag: String! } type WpCoreTableBlockDeprecatedV1AttributesHead { cells: [WpCoreTableBlockDeprecatedV1AttributesHeadCells]! } type WpCoreTableBlockDeprecatedV1AttributesHeadCells { align: String content: String scope: String tag: String! } type WpCoreTableBlockDeprecatedV2Attributes { align: String anchor: String backgroundColor: String body: [WpCoreTableBlockDeprecatedV2AttributesBody]! borderColor: String caption: String! className: String fontSize: String foot: [WpCoreTableBlockDeprecatedV2AttributesFoot]! gradient: String hasFixedLayout: Boolean! head: [WpCoreTableBlockDeprecatedV2AttributesHead]! lock: JSON style: JSON textColor: String } type WpCoreTableBlockDeprecatedV2AttributesBody { cells: [WpCoreTableBlockDeprecatedV2AttributesBodyCells]! } type WpCoreTableBlockDeprecatedV2AttributesBodyCells { align: String content: String scope: String tag: String! } type WpCoreTableBlockDeprecatedV2AttributesFoot { cells: [WpCoreTableBlockDeprecatedV2AttributesFootCells]! } type WpCoreTableBlockDeprecatedV2AttributesFootCells { align: String content: String scope: String tag: String! } type WpCoreTableBlockDeprecatedV2AttributesHead { cells: [WpCoreTableBlockDeprecatedV2AttributesHeadCells]! } type WpCoreTableBlockDeprecatedV2AttributesHeadCells { align: String content: String scope: String tag: String! } """ core/tag-cloud block """ type WpCoreTagCloudBlock implements WpBlock { attributes: WpCoreTagCloudBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreTagCloudBlockAttributes { align: String className: String lock: JSON numberOfTags: Float! showTagCounts: Boolean! taxonomy: String! } """ core/template-part block """ type WpCoreTemplatePartBlock implements WpBlock { attributes: WpCoreTemplatePartBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreTemplatePartBlockAttributes { align: String area: String className: String lock: JSON slug: String tagName: String theme: String } """ core/term-description block """ type WpCoreTermDescriptionBlock implements WpBlock { attributes: WpCoreTermDescriptionBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreTermDescriptionBlockAttributes { align: String backgroundColor: String className: String fontSize: String lock: JSON style: JSON textAlign: String textColor: String } """ core/text-columns block """ type WpCoreTextColumnsBlock implements WpBlock { attributes: WpCoreTextColumnsBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreTextColumnsBlockAttributes { className: String columns: Float! content: [WpCoreTextColumnsBlockAttributesContent]! lock: JSON width: String } type WpCoreTextColumnsBlockAttributesContent { wpChildren: String } """ core/verse block """ type WpCoreVerseBlock implements WpBlock { attributes: WpCoreVerseBlockAttributesUnion """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreVerseBlockAttributes { anchor: String backgroundColor: String className: String content: String! fontFamily: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String } union WpCoreVerseBlockAttributesUnion = WpCoreVerseBlockAttributes | WpCoreVerseBlockDeprecatedV1Attributes | WpCoreVerseBlockDeprecatedV2Attributes type WpCoreVerseBlockDeprecatedV1Attributes { anchor: String backgroundColor: String className: String content: String! fontFamily: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String } type WpCoreVerseBlockDeprecatedV2Attributes { anchor: String backgroundColor: String className: String content: String! fontFamily: String fontSize: String gradient: String lock: JSON style: JSON textAlign: String textColor: String } """ core/video block """ type WpCoreVideoBlock implements WpBlock { attributes: WpCoreVideoBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpCoreVideoBlockAttributes { align: String anchor: String autoplay: Boolean caption: String className: String controls: Boolean! id: Float lock: JSON loop: Boolean muted: Boolean playsInline: Boolean poster: String preload: String! src: String tracks: [WpBlockAttributesObject]! } interface WpDatabaseIdentifier { """ The unique identifier stored in the database """ databaseId: Int! } """ The template assigned to the node """ type WpDefaultTemplate implements WpContentTemplate { """ The name of the template """ templateName: String } """ The discussion setting type """ type WpDiscussionSettings { """ Erlaube Besuchern, neue Beiträge zu kommentieren. """ defaultCommentStatus: String """ Link-Benachrichtigungen von anderen Blogs (Pingbacks und Trackbacks) zu neuen Beiträgen erlauben. """ defaultPingStatus: String } input WpDiscussionSettingsFilterInput { defaultCommentStatus: StringQueryOperatorInput defaultPingStatus: StringQueryOperatorInput } type WpEdge { next: Wp node: Wp! previous: Wp } enum WpFieldsEnum { allSettings___discussionSettingsDefaultCommentStatus allSettings___discussionSettingsDefaultPingStatus allSettings___generalSettingsDateFormat allSettings___generalSettingsDescription allSettings___generalSettingsEmail allSettings___generalSettingsLanguage allSettings___generalSettingsStartOfWeek allSettings___generalSettingsTimeFormat allSettings___generalSettingsTimezone allSettings___generalSettingsTitle allSettings___generalSettingsUrl allSettings___readingSettingsPostsPerPage allSettings___writingSettingsDefaultCategory allSettings___writingSettingsDefaultPostFormat allSettings___writingSettingsUseSmilies children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id discussionSettings___defaultCommentStatus discussionSettings___defaultPingStatus generalSettings___dateFormat generalSettings___description generalSettings___email generalSettings___language generalSettings___startOfWeek generalSettings___timeFormat generalSettings___timezone generalSettings___title generalSettings___url id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id readingSettings___postsPerPage wpGatsby___arePrettyPermalinksEnabled wpGatsby___isPreviewFrontendOnline writingSettings___defaultCategory writingSettings___defaultPostFormat writingSettings___useSmilies } input WpFilterInput { allSettings: WpSettingsFilterInput children: NodeFilterListInput discussionSettings: WpDiscussionSettingsFilterInput generalSettings: WpGeneralSettingsFilterInput id: StringQueryOperatorInput internal: InternalFilterInput nodeType: StringQueryOperatorInput parent: NodeFilterInput readingSettings: WpReadingSettingsFilterInput wpGatsby: WpWPGatsbyFilterInput writingSettings: WpWritingSettingsFilterInput } """ The general setting type """ type WpGeneralSettings { """ Ein Zeitformat für alle datumsbasierten Zeichenfolgen. """ dateFormat: String """ Website-Untertitel. """ description: String """ Diese Adresse wird für administrative Zwecke verwendet, wie Benachrichtigungen über neue Benutzer. """ email: String """ WordPress-Ländercode. """ language: String """ Die Zahl eines Wochentages, mit dem die Woche beginnen sollte. """ startOfWeek: Int """ Ein Zeitformat für alle zeitbasierten Zeichenfolgen. """ timeFormat: String """ Eine Stadt in deiner Zeitzone. """ timezone: String """ Website-Titel. """ title: String """ Website-URL. """ url: String } input WpGeneralSettingsFilterInput { dateFormat: StringQueryOperatorInput description: StringQueryOperatorInput email: StringQueryOperatorInput language: StringQueryOperatorInput startOfWeek: IntQueryOperatorInput timeFormat: StringQueryOperatorInput timezone: StringQueryOperatorInput title: StringQueryOperatorInput url: StringQueryOperatorInput } type WpGroupConnection { distinct(field: WpFieldsEnum!): [String!]! edges: [WpEdge!]! field: String! fieldValue: String group(field: WpFieldsEnum!, limit: Int, skip: Int): [WpGroupConnection!]! max(field: WpFieldsEnum!): Float min(field: WpFieldsEnum!): Float nodes: [Wp!]! pageInfo: PageInfo! sum(field: WpFieldsEnum!): Float totalCount: Int! } interface WpHierarchicalContentNode { """ Returns ancestors of the node. Default ordered as lowest (closest to the child) to highest (closest to the root). """ ancestors: WpHierarchicalContentNodeToContentNodeAncestorsConnection """ Database id of the parent node """ parentDatabaseId: Int """ The globally unique identifier of the parent node. """ parentId: ID """ Connection between the HierarchicalContentNode type and the ContentNode type """ wpChildren: WpHierarchicalContentNodeToContentNodeChildrenConnection """ The parent of the node. The parent object can be of various types """ wpParent: WpHierarchicalContentNodeToParentContentNodeConnectionEdge } """ Connection between the HierarchicalContentNode type and the ContentNode type """ type WpHierarchicalContentNodeToContentNodeAncestorsConnection { """ The nodes of the connection, without the edges """ nodes: [WpContentNode] } input WpHierarchicalContentNodeToContentNodeAncestorsConnectionFilterInput { nodes: WpContentNodeFilterListInput } """ Connection between the HierarchicalContentNode type and the ContentNode type """ type WpHierarchicalContentNodeToContentNodeChildrenConnection { """ The nodes of the connection, without the edges """ nodes: [WpContentNode] } input WpHierarchicalContentNodeToContentNodeChildrenConnectionFilterInput { nodes: WpContentNodeFilterListInput } """ Connection between the HierarchicalContentNode type and the ContentNode type """ type WpHierarchicalContentNodeToParentContentNodeConnectionEdge { """ The node of the connection, without the edges """ node: WpContentNode } input WpHierarchicalContentNodeToParentContentNodeConnectionEdgeFilterInput { node: WpContentNodeFilterInput } interface WpHierarchicalTermNode { """ Database id of the parent node """ parentDatabaseId: Int """ The globally unique identifier of the parent node. """ parentId: ID } """ lazyblock-core/free block """ type WpLazyblockCoreFreeBlock implements WpBlock { attributes: WpLazyblockCoreFreeBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpLazyblockCoreFreeBlockAttributes { className: String lock: JSON } """ lazyblock/image-repeater block """ type WpLazyblockImageRepeaterBlock implements WpBlock { attributes: WpLazyblockImageRepeaterBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpLazyblockImageRepeaterBlockAttributes { align: String! anchor: String! blockId: String! blockUniqueClass: String! className: String ghostkitSR: String! ghostkitSpacings: JSON! images: String! innerBlock: String! lazyblock: JSON! lock: JSON } """ lazyblock/lightbox-image block """ type WpLazyblockLightboxImageBlock implements WpBlock { attributes: WpLazyblockLightboxImageBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpLazyblockLightboxImageBlockAttributes { align: String! anchor: String! blockId: String! blockUniqueClass: String! className: String ghostkitSR: String! ghostkitSpacings: JSON! image: String! lazyblock: JSON! lock: JSON } """ lazyblock/project-highlight block """ type WpLazyblockProjectHighlightBlock implements WpBlock { attributes: WpLazyblockProjectHighlightBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpLazyblockProjectHighlightBlockAttributes { align: String! anchor: String! blockId: String! blockUniqueClass: String! className: String ghostkitSR: String! ghostkitSpacings: JSON! highlights: String! images: String! lazyblock: JSON! lock: JSON title: String! } """ lazyblock/projectecho block """ type WpLazyblockProjectechoBlock implements WpBlock { attributes: WpLazyblockProjectechoBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpLazyblockProjectechoBlockAttributes { align: String! anchor: String! blockId: String! blockUniqueClass: String! className: String gallery: String! ghostkitSR: String! ghostkitSpacings: JSON! lazyblock: JSON! lock: JSON } """ File details for a Media Item """ type WpMediaDetails { """ The filename of the mediaItem """ file: String """ The height of the mediaItem """ height: Int """ Meta information associated with the mediaItem """ meta: WpMediaItemMeta """ The available sizes of the mediaItem """ sizes: [WpMediaSize] """ The width of the mediaItem """ width: Int } input WpMediaDetailsFilterInput { file: StringQueryOperatorInput height: IntQueryOperatorInput meta: WpMediaItemMetaFilterInput sizes: WpMediaSizeFilterListInput width: IntQueryOperatorInput } """ The mediaItem type """ type WpMediaItem implements Node & RemoteFile & WpContentNode & WpDatabaseIdentifier & WpHierarchicalContentNode & WpNode & WpNodeWithAuthor & WpNodeWithComments & WpNodeWithTemplate & WpNodeWithTitle & WpUniformResourceIdentifiable { """ Alternative text to display when resource is not displayed """ altText: String """ Returns ancestors of the node. Default ordered as lowest (closest to the child) to highest (closest to the root). """ ancestors: WpHierarchicalContentNodeToContentNodeAncestorsConnection """ Connection between the NodeWithAuthor type and the User type """ author: WpNodeWithAuthorToUserConnectionEdge """ The database identifier of the author of the node """ authorDatabaseId: Int """ The globally unique identifier of the author of the node """ authorId: ID """ The caption for the resource """ caption: String children: [Node!]! """ The number of comments. Even though WPGraphQL denotes this field as an integer, in WordPress this field should be saved as a numeric string for compatibility. """ commentCount: Int """ Whether the comments are open or closed for this particular post. """ commentStatus: String """ Connection between the mediaItem type and the Comment type """ comments: WpMediaItemToCommentConnection """ Connection between the ContentNode type and the ContentType type """ contentType: WpContentNodeToContentTypeConnectionEdge """ The name of the Content Type the node belongs to """ contentTypeName: String! """ The unique identifier stored in the database """ databaseId: Int! """ Post publishing date. """ date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The publishing date set in GMT. """ dateGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ Description of the image (stored as post_content) """ description: String """ The desired slug of the post """ desiredSlug: String """ The RSS enclosure for the object """ enclosure: String """ The filesize in bytes of the resource """ fileSize: Int filename: String! filesize: Int """ Data used in the component. See https://gatsby.dev/img for more info. """ gatsbyImage( """ If set along with width or height, this will set the value of the other dimension to match the provided aspect ratio, cropping the image if needed. If neither width or height is provided, height will be set based on the intrinsic width of the source image. """ aspectRatio: Float """ Background color applied to the wrapper, or when "letterboxing" an image to another aspect ratio. """ backgroundColor: String """ Specifies the image widths to generate. You should rarely need to change this. For FIXED and CONSTRAINED images it is better to allow these to be determined automatically, based on the image size. For FULL_WIDTH images this can be used to override the default, which is [750, 1080, 1366, 1920]. It will never generate any images larger than the source. """ breakpoints: [Int] = [750, 1080, 1366, 1920] cropFocus: [RemoteFileCropFocus] fit: RemoteFileFit = COVER """ The image formats to generate. Valid values are AUTO (meaning the same format as the source image), JPG, PNG, WEBP and AVIF. The default value is [AUTO, WEBP, AVIF], and you should rarely need to change this. Take care if you specify JPG or PNG when you do not know the formats of the source images, as this could lead to unwanted results such as converting JPEGs to PNGs. Specifying both PNG and JPG is not supported and will be ignored. """ formats: [RemoteFileFormat!] = [AUTO, WEBP, AVIF] """ If set, the height of the generated image. If omitted, it is calculated from the supplied width, matching the aspect ratio of the source image. """ height: Int """ The layout for the image. FIXED: A static image sized, that does not resize according to the screen width FULL_WIDTH: The image resizes to fit its container. Pass a "sizes" option if it isn't going to be the full width of the screen. CONSTRAINED: Resizes to fit its container, up to a maximum width, at which point it will remain fixed in size. """ layout: RemoteFileLayout = CONSTRAINED """ A list of image pixel densities to generate for FIXED and CONSTRAINED images. You should rarely need to change this. It will never generate images larger than the source, and will always include a 1x image. Default is [ 1, 2 ] for fixed images, meaning 1x, 2x, and [0.25, 0.5, 1, 2] for fluid. In this case, an image with a fluid layout and width = 400 would generate images at 100, 200, 400 and 800px wide. """ outputPixelDensities: [Float] = [0.25, 0.5, 1, 2] """ Format of generated placeholder image, displayed while the main image loads. BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. TRACED_SVG: a low-resolution traced SVG of the image. NONE: no placeholder. Set the argument "backgroundColor" to use a fixed background color. """ placeholder: RemoteFilePlaceholder = DOMINANT_COLOR quality: Int = 75 """ The "sizes" property, passed to the img tag. This describes the display size of the image. This does not affect the generated images, but is used by the browser to decide which images to download. You can leave this blank for fixed images, or if the responsive image container will be the full width of the screen. In these cases we will generate an appropriate value. """ sizes: String """ The display width of the generated image for layout = FIXED, and the display width of the largest image for layout = CONSTRAINED. The actual largest image resolution will be this value multiplied by the largest value in outputPixelDensities Ignored if layout = FLUID. """ width: Int ): JSON """ The global unique identifier for this post. This currently matches the value stored in WP_Post->guid and the guid column in the "post_objects" database table. """ guid: String height: Int id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The user that most recently edited the node """ lastEditedBy: WpContentNodeToEditLastConnectionEdge """ The permalink of the post """ link: String localFile: File """ Details about the mediaItem """ mediaDetails: WpMediaDetails """ Url of the mediaItem """ mediaItemUrl: String """ Type of resource """ mediaType: String mimeType: String! """ The local modified time for a post. If a post was recently updated the modified field will change to match the corresponding time. """ modified( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The GMT modified time for a post. If a post was recently updated the modified field will change to match the corresponding time in GMT. """ modifiedGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date nodeType: String parent: Node """ Database id of the parent node """ parentDatabaseId: Int """ The globally unique identifier of the parent node. """ parentId: ID publicUrl: String! remoteFile: File @deprecated(reason: "MediaItem.remoteFile was renamed to localFile") resize( cropFocus: [RemoteFileCropFocus] fit: RemoteFileFit = COVER """ The image formats to generate. Valid values are AUTO (meaning the same format as the source image), JPG, PNG, WEBP and AVIF. The default value is [AUTO, WEBP, AVIF], and you should rarely need to change this. Take care if you specify JPG or PNG when you do not know the formats of the source images, as this could lead to unwanted results such as converting JPEGs to PNGs. Specifying both PNG and JPG is not supported and will be ignored. """ format: RemoteFileFormat = AUTO height: Int quality: Int = 75 width: Int ): RemoteFileResize """ The sizes attribute value for an image. """ sizes: String """ The uri slug for the post. This is equivalent to the WP_Post->post_name field and the post_name column in the database for the "post_objects" table. """ slug: String """ Url of the mediaItem """ sourceUrl: String """ The srcset attribute specifies the URL of the image to use in different situations. It is a comma separated string of urls and their widths. """ srcSet: String """ The current status of the object """ status: String """ The template assigned to the node """ template: WpContentTemplate """ The title of the post. This is currently just the raw title. An amendment to support rendered title needs to be made. """ title: String """ The unique resource identifier path """ uri: String width: Int """ Connection between the HierarchicalContentNode type and the ContentNode type """ wpChildren: WpHierarchicalContentNodeToContentNodeChildrenConnection """ The parent of the node. The parent object can be of various types """ wpParent: WpHierarchicalContentNodeToParentContentNodeConnectionEdge } type WpMediaItemConnection { distinct(field: WpMediaItemFieldsEnum!): [String!]! edges: [WpMediaItemEdge!]! group(field: WpMediaItemFieldsEnum!, limit: Int, skip: Int): [WpMediaItemGroupConnection!]! max(field: WpMediaItemFieldsEnum!): Float min(field: WpMediaItemFieldsEnum!): Float nodes: [WpMediaItem!]! pageInfo: PageInfo! sum(field: WpMediaItemFieldsEnum!): Float totalCount: Int! } type WpMediaItemEdge { next: WpMediaItem node: WpMediaItem! previous: WpMediaItem } enum WpMediaItemFieldsEnum { altText ancestors___nodes ancestors___nodes___children ancestors___nodes___children___children ancestors___nodes___children___id ancestors___nodes___contentTypeName ancestors___nodes___databaseId ancestors___nodes___date ancestors___nodes___dateGmt ancestors___nodes___desiredSlug ancestors___nodes___enclosure ancestors___nodes___guid ancestors___nodes___id ancestors___nodes___internal___content ancestors___nodes___internal___contentDigest ancestors___nodes___internal___description ancestors___nodes___internal___fieldOwners ancestors___nodes___internal___ignoreType ancestors___nodes___internal___mediaType ancestors___nodes___internal___owner ancestors___nodes___internal___type ancestors___nodes___isContentNode ancestors___nodes___isTermNode ancestors___nodes___link ancestors___nodes___modified ancestors___nodes___modifiedGmt ancestors___nodes___nodeType ancestors___nodes___parent___children ancestors___nodes___parent___id ancestors___nodes___slug ancestors___nodes___status ancestors___nodes___template___templateName ancestors___nodes___uri authorDatabaseId authorId author___node___avatar___default author___node___avatar___extraAttr author___node___avatar___forceDefault author___node___avatar___foundAvatar author___node___avatar___height author___node___avatar___rating author___node___avatar___scheme author___node___avatar___size author___node___avatar___url author___node___avatar___width author___node___blockEditorPreviews___nodes author___node___capKey author___node___capabilities author___node___children author___node___children___children author___node___children___id author___node___comments___nodes author___node___databaseId author___node___description author___node___email author___node___extraCapabilities author___node___firstName author___node___id author___node___internal___content author___node___internal___contentDigest author___node___internal___description author___node___internal___fieldOwners author___node___internal___ignoreType author___node___internal___mediaType author___node___internal___owner author___node___internal___type author___node___isContentNode author___node___isTermNode author___node___lastName author___node___locale author___node___name author___node___nicename author___node___nickname author___node___nodeType author___node___pages___nodes author___node___parent___children author___node___parent___id author___node___posts___nodes author___node___registeredDate author___node___roles___nodes author___node___slug author___node___uri author___node___url author___node___username caption children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id commentCount commentStatus comments___nodes comments___nodes___agent comments___nodes___approved comments___nodes___authorIp comments___nodes___children comments___nodes___children___children comments___nodes___children___id comments___nodes___content comments___nodes___databaseId comments___nodes___date comments___nodes___dateGmt comments___nodes___id comments___nodes___internal___content comments___nodes___internal___contentDigest comments___nodes___internal___description comments___nodes___internal___fieldOwners comments___nodes___internal___ignoreType comments___nodes___internal___mediaType comments___nodes___internal___owner comments___nodes___internal___type comments___nodes___karma comments___nodes___nodeType comments___nodes___parentDatabaseId comments___nodes___parentId comments___nodes___parent___children comments___nodes___parent___id comments___nodes___replies___nodes comments___nodes___type contentTypeName contentType___node___archivePath contentType___node___canExport contentType___node___children contentType___node___children___children contentType___node___children___id contentType___node___connectedTaxonomies___nodes contentType___node___contentNodes___nodes contentType___node___deleteWithUser contentType___node___description contentType___node___excludeFromSearch contentType___node___graphqlPluralName contentType___node___graphqlSingleName contentType___node___hasArchive contentType___node___hierarchical contentType___node___id contentType___node___internal___content contentType___node___internal___contentDigest contentType___node___internal___description contentType___node___internal___fieldOwners contentType___node___internal___ignoreType contentType___node___internal___mediaType contentType___node___internal___owner contentType___node___internal___type contentType___node___isContentNode contentType___node___isFrontPage contentType___node___isPostsPage contentType___node___isTermNode contentType___node___label contentType___node___labels___addNew contentType___node___labels___addNewItem contentType___node___labels___allItems contentType___node___labels___archives contentType___node___labels___attributes contentType___node___labels___editItem contentType___node___labels___featuredImage contentType___node___labels___filterItemsList contentType___node___labels___insertIntoItem contentType___node___labels___itemsList contentType___node___labels___itemsListNavigation contentType___node___labels___menuName contentType___node___labels___name contentType___node___labels___newItem contentType___node___labels___notFound contentType___node___labels___notFoundInTrash contentType___node___labels___parentItemColon contentType___node___labels___removeFeaturedImage contentType___node___labels___searchItems contentType___node___labels___setFeaturedImage contentType___node___labels___singularName contentType___node___labels___uploadedToThisItem contentType___node___labels___useFeaturedImage contentType___node___labels___viewItem contentType___node___labels___viewItems contentType___node___menuIcon contentType___node___menuPosition contentType___node___name contentType___node___nodeType contentType___node___parent___children contentType___node___parent___id contentType___node___public contentType___node___publiclyQueryable contentType___node___restBase contentType___node___restControllerClass contentType___node___showInAdminBar contentType___node___showInGraphql contentType___node___showInMenu contentType___node___showInNavMenus contentType___node___showInRest contentType___node___showUi contentType___node___uri databaseId date dateGmt description desiredSlug enclosure fileSize filename filesize gatsbyImage guid height id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isTermNode lastEditedBy___node___avatar___default lastEditedBy___node___avatar___extraAttr lastEditedBy___node___avatar___forceDefault lastEditedBy___node___avatar___foundAvatar lastEditedBy___node___avatar___height lastEditedBy___node___avatar___rating lastEditedBy___node___avatar___scheme lastEditedBy___node___avatar___size lastEditedBy___node___avatar___url lastEditedBy___node___avatar___width lastEditedBy___node___blockEditorPreviews___nodes lastEditedBy___node___capKey lastEditedBy___node___capabilities lastEditedBy___node___children lastEditedBy___node___children___children lastEditedBy___node___children___id lastEditedBy___node___comments___nodes lastEditedBy___node___databaseId lastEditedBy___node___description lastEditedBy___node___email lastEditedBy___node___extraCapabilities lastEditedBy___node___firstName lastEditedBy___node___id lastEditedBy___node___internal___content lastEditedBy___node___internal___contentDigest lastEditedBy___node___internal___description lastEditedBy___node___internal___fieldOwners lastEditedBy___node___internal___ignoreType lastEditedBy___node___internal___mediaType lastEditedBy___node___internal___owner lastEditedBy___node___internal___type lastEditedBy___node___isContentNode lastEditedBy___node___isTermNode lastEditedBy___node___lastName lastEditedBy___node___locale lastEditedBy___node___name lastEditedBy___node___nicename lastEditedBy___node___nickname lastEditedBy___node___nodeType lastEditedBy___node___pages___nodes lastEditedBy___node___parent___children lastEditedBy___node___parent___id lastEditedBy___node___posts___nodes lastEditedBy___node___registeredDate lastEditedBy___node___roles___nodes lastEditedBy___node___slug lastEditedBy___node___uri lastEditedBy___node___url lastEditedBy___node___username link localFile___absolutePath localFile___accessTime localFile___atime localFile___atimeMs localFile___base localFile___birthTime localFile___birthtime localFile___birthtimeMs localFile___blksize localFile___blocks localFile___changeTime localFile___childImageSharp___children localFile___childImageSharp___children___children localFile___childImageSharp___children___id localFile___childImageSharp___fixed___aspectRatio localFile___childImageSharp___fixed___base64 localFile___childImageSharp___fixed___height localFile___childImageSharp___fixed___originalName localFile___childImageSharp___fixed___src localFile___childImageSharp___fixed___srcSet localFile___childImageSharp___fixed___srcSetWebp localFile___childImageSharp___fixed___srcWebp localFile___childImageSharp___fixed___tracedSVG localFile___childImageSharp___fixed___width localFile___childImageSharp___fluid___aspectRatio localFile___childImageSharp___fluid___base64 localFile___childImageSharp___fluid___originalImg localFile___childImageSharp___fluid___originalName localFile___childImageSharp___fluid___presentationHeight localFile___childImageSharp___fluid___presentationWidth localFile___childImageSharp___fluid___sizes localFile___childImageSharp___fluid___src localFile___childImageSharp___fluid___srcSet localFile___childImageSharp___fluid___srcSetWebp localFile___childImageSharp___fluid___srcWebp localFile___childImageSharp___fluid___tracedSVG localFile___childImageSharp___gatsbyImageData localFile___childImageSharp___id localFile___childImageSharp___internal___content localFile___childImageSharp___internal___contentDigest localFile___childImageSharp___internal___description localFile___childImageSharp___internal___fieldOwners localFile___childImageSharp___internal___ignoreType localFile___childImageSharp___internal___mediaType localFile___childImageSharp___internal___owner localFile___childImageSharp___internal___type localFile___childImageSharp___original___height localFile___childImageSharp___original___src localFile___childImageSharp___original___width localFile___childImageSharp___parent___children localFile___childImageSharp___parent___id localFile___childImageSharp___resize___aspectRatio localFile___childImageSharp___resize___height localFile___childImageSharp___resize___originalName localFile___childImageSharp___resize___src localFile___childImageSharp___resize___tracedSVG localFile___childImageSharp___resize___width localFile___children localFile___childrenImageSharp localFile___childrenImageSharp___children localFile___childrenImageSharp___children___children localFile___childrenImageSharp___children___id localFile___childrenImageSharp___fixed___aspectRatio localFile___childrenImageSharp___fixed___base64 localFile___childrenImageSharp___fixed___height localFile___childrenImageSharp___fixed___originalName localFile___childrenImageSharp___fixed___src localFile___childrenImageSharp___fixed___srcSet localFile___childrenImageSharp___fixed___srcSetWebp localFile___childrenImageSharp___fixed___srcWebp localFile___childrenImageSharp___fixed___tracedSVG localFile___childrenImageSharp___fixed___width localFile___childrenImageSharp___fluid___aspectRatio localFile___childrenImageSharp___fluid___base64 localFile___childrenImageSharp___fluid___originalImg localFile___childrenImageSharp___fluid___originalName localFile___childrenImageSharp___fluid___presentationHeight localFile___childrenImageSharp___fluid___presentationWidth localFile___childrenImageSharp___fluid___sizes localFile___childrenImageSharp___fluid___src localFile___childrenImageSharp___fluid___srcSet localFile___childrenImageSharp___fluid___srcSetWebp localFile___childrenImageSharp___fluid___srcWebp localFile___childrenImageSharp___fluid___tracedSVG localFile___childrenImageSharp___gatsbyImageData localFile___childrenImageSharp___id localFile___childrenImageSharp___internal___content localFile___childrenImageSharp___internal___contentDigest localFile___childrenImageSharp___internal___description localFile___childrenImageSharp___internal___fieldOwners localFile___childrenImageSharp___internal___ignoreType localFile___childrenImageSharp___internal___mediaType localFile___childrenImageSharp___internal___owner localFile___childrenImageSharp___internal___type localFile___childrenImageSharp___original___height localFile___childrenImageSharp___original___src localFile___childrenImageSharp___original___width localFile___childrenImageSharp___parent___children localFile___childrenImageSharp___parent___id localFile___childrenImageSharp___resize___aspectRatio localFile___childrenImageSharp___resize___height localFile___childrenImageSharp___resize___originalName localFile___childrenImageSharp___resize___src localFile___childrenImageSharp___resize___tracedSVG localFile___childrenImageSharp___resize___width localFile___children___children localFile___children___children___children localFile___children___children___id localFile___children___id localFile___children___internal___content localFile___children___internal___contentDigest localFile___children___internal___description localFile___children___internal___fieldOwners localFile___children___internal___ignoreType localFile___children___internal___mediaType localFile___children___internal___owner localFile___children___internal___type localFile___children___parent___children localFile___children___parent___id localFile___ctime localFile___ctimeMs localFile___dev localFile___dir localFile___ext localFile___extension localFile___gid localFile___hash localFile___id localFile___ino localFile___internal___content localFile___internal___contentDigest localFile___internal___description localFile___internal___fieldOwners localFile___internal___ignoreType localFile___internal___mediaType localFile___internal___owner localFile___internal___type localFile___mode localFile___modifiedTime localFile___mtime localFile___mtimeMs localFile___name localFile___nlink localFile___parent___children localFile___parent___children___children localFile___parent___children___id localFile___parent___id localFile___parent___internal___content localFile___parent___internal___contentDigest localFile___parent___internal___description localFile___parent___internal___fieldOwners localFile___parent___internal___ignoreType localFile___parent___internal___mediaType localFile___parent___internal___owner localFile___parent___internal___type localFile___parent___parent___children localFile___parent___parent___id localFile___prettySize localFile___publicURL localFile___rdev localFile___relativeDirectory localFile___relativePath localFile___root localFile___size localFile___sourceInstanceName localFile___uid mediaDetails___file mediaDetails___height mediaDetails___meta___aperture mediaDetails___meta___camera mediaDetails___meta___caption mediaDetails___meta___copyright mediaDetails___meta___createdTimestamp mediaDetails___meta___credit mediaDetails___meta___focalLength mediaDetails___meta___iso mediaDetails___meta___keywords mediaDetails___meta___orientation mediaDetails___meta___shutterSpeed mediaDetails___meta___title mediaDetails___sizes mediaDetails___sizes___file mediaDetails___sizes___fileSize mediaDetails___sizes___height mediaDetails___sizes___mimeType mediaDetails___sizes___name mediaDetails___sizes___sourceUrl mediaDetails___sizes___width mediaDetails___width mediaItemUrl mediaType mimeType modified modifiedGmt nodeType parentDatabaseId parentId parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id publicUrl remoteFile___absolutePath remoteFile___accessTime remoteFile___atime remoteFile___atimeMs remoteFile___base remoteFile___birthTime remoteFile___birthtime remoteFile___birthtimeMs remoteFile___blksize remoteFile___blocks remoteFile___changeTime remoteFile___childImageSharp___children remoteFile___childImageSharp___children___children remoteFile___childImageSharp___children___id remoteFile___childImageSharp___fixed___aspectRatio remoteFile___childImageSharp___fixed___base64 remoteFile___childImageSharp___fixed___height remoteFile___childImageSharp___fixed___originalName remoteFile___childImageSharp___fixed___src remoteFile___childImageSharp___fixed___srcSet remoteFile___childImageSharp___fixed___srcSetWebp remoteFile___childImageSharp___fixed___srcWebp remoteFile___childImageSharp___fixed___tracedSVG remoteFile___childImageSharp___fixed___width remoteFile___childImageSharp___fluid___aspectRatio remoteFile___childImageSharp___fluid___base64 remoteFile___childImageSharp___fluid___originalImg remoteFile___childImageSharp___fluid___originalName remoteFile___childImageSharp___fluid___presentationHeight remoteFile___childImageSharp___fluid___presentationWidth remoteFile___childImageSharp___fluid___sizes remoteFile___childImageSharp___fluid___src remoteFile___childImageSharp___fluid___srcSet remoteFile___childImageSharp___fluid___srcSetWebp remoteFile___childImageSharp___fluid___srcWebp remoteFile___childImageSharp___fluid___tracedSVG remoteFile___childImageSharp___gatsbyImageData remoteFile___childImageSharp___id remoteFile___childImageSharp___internal___content remoteFile___childImageSharp___internal___contentDigest remoteFile___childImageSharp___internal___description remoteFile___childImageSharp___internal___fieldOwners remoteFile___childImageSharp___internal___ignoreType remoteFile___childImageSharp___internal___mediaType remoteFile___childImageSharp___internal___owner remoteFile___childImageSharp___internal___type remoteFile___childImageSharp___original___height remoteFile___childImageSharp___original___src remoteFile___childImageSharp___original___width remoteFile___childImageSharp___parent___children remoteFile___childImageSharp___parent___id remoteFile___childImageSharp___resize___aspectRatio remoteFile___childImageSharp___resize___height remoteFile___childImageSharp___resize___originalName remoteFile___childImageSharp___resize___src remoteFile___childImageSharp___resize___tracedSVG remoteFile___childImageSharp___resize___width remoteFile___children remoteFile___childrenImageSharp remoteFile___childrenImageSharp___children remoteFile___childrenImageSharp___children___children remoteFile___childrenImageSharp___children___id remoteFile___childrenImageSharp___fixed___aspectRatio remoteFile___childrenImageSharp___fixed___base64 remoteFile___childrenImageSharp___fixed___height remoteFile___childrenImageSharp___fixed___originalName remoteFile___childrenImageSharp___fixed___src remoteFile___childrenImageSharp___fixed___srcSet remoteFile___childrenImageSharp___fixed___srcSetWebp remoteFile___childrenImageSharp___fixed___srcWebp remoteFile___childrenImageSharp___fixed___tracedSVG remoteFile___childrenImageSharp___fixed___width remoteFile___childrenImageSharp___fluid___aspectRatio remoteFile___childrenImageSharp___fluid___base64 remoteFile___childrenImageSharp___fluid___originalImg remoteFile___childrenImageSharp___fluid___originalName remoteFile___childrenImageSharp___fluid___presentationHeight remoteFile___childrenImageSharp___fluid___presentationWidth remoteFile___childrenImageSharp___fluid___sizes remoteFile___childrenImageSharp___fluid___src remoteFile___childrenImageSharp___fluid___srcSet remoteFile___childrenImageSharp___fluid___srcSetWebp remoteFile___childrenImageSharp___fluid___srcWebp remoteFile___childrenImageSharp___fluid___tracedSVG remoteFile___childrenImageSharp___gatsbyImageData remoteFile___childrenImageSharp___id remoteFile___childrenImageSharp___internal___content remoteFile___childrenImageSharp___internal___contentDigest remoteFile___childrenImageSharp___internal___description remoteFile___childrenImageSharp___internal___fieldOwners remoteFile___childrenImageSharp___internal___ignoreType remoteFile___childrenImageSharp___internal___mediaType remoteFile___childrenImageSharp___internal___owner remoteFile___childrenImageSharp___internal___type remoteFile___childrenImageSharp___original___height remoteFile___childrenImageSharp___original___src remoteFile___childrenImageSharp___original___width remoteFile___childrenImageSharp___parent___children remoteFile___childrenImageSharp___parent___id remoteFile___childrenImageSharp___resize___aspectRatio remoteFile___childrenImageSharp___resize___height remoteFile___childrenImageSharp___resize___originalName remoteFile___childrenImageSharp___resize___src remoteFile___childrenImageSharp___resize___tracedSVG remoteFile___childrenImageSharp___resize___width remoteFile___children___children remoteFile___children___children___children remoteFile___children___children___id remoteFile___children___id remoteFile___children___internal___content remoteFile___children___internal___contentDigest remoteFile___children___internal___description remoteFile___children___internal___fieldOwners remoteFile___children___internal___ignoreType remoteFile___children___internal___mediaType remoteFile___children___internal___owner remoteFile___children___internal___type remoteFile___children___parent___children remoteFile___children___parent___id remoteFile___ctime remoteFile___ctimeMs remoteFile___dev remoteFile___dir remoteFile___ext remoteFile___extension remoteFile___gid remoteFile___hash remoteFile___id remoteFile___ino remoteFile___internal___content remoteFile___internal___contentDigest remoteFile___internal___description remoteFile___internal___fieldOwners remoteFile___internal___ignoreType remoteFile___internal___mediaType remoteFile___internal___owner remoteFile___internal___type remoteFile___mode remoteFile___modifiedTime remoteFile___mtime remoteFile___mtimeMs remoteFile___name remoteFile___nlink remoteFile___parent___children remoteFile___parent___children___children remoteFile___parent___children___id remoteFile___parent___id remoteFile___parent___internal___content remoteFile___parent___internal___contentDigest remoteFile___parent___internal___description remoteFile___parent___internal___fieldOwners remoteFile___parent___internal___ignoreType remoteFile___parent___internal___mediaType remoteFile___parent___internal___owner remoteFile___parent___internal___type remoteFile___parent___parent___children remoteFile___parent___parent___id remoteFile___prettySize remoteFile___publicURL remoteFile___rdev remoteFile___relativeDirectory remoteFile___relativePath remoteFile___root remoteFile___size remoteFile___sourceInstanceName remoteFile___uid resize___height resize___src resize___width sizes slug sourceUrl srcSet status template___templateName title uri width wpChildren___nodes wpChildren___nodes___children wpChildren___nodes___children___children wpChildren___nodes___children___id wpChildren___nodes___contentTypeName wpChildren___nodes___databaseId wpChildren___nodes___date wpChildren___nodes___dateGmt wpChildren___nodes___desiredSlug wpChildren___nodes___enclosure wpChildren___nodes___guid wpChildren___nodes___id wpChildren___nodes___internal___content wpChildren___nodes___internal___contentDigest wpChildren___nodes___internal___description wpChildren___nodes___internal___fieldOwners wpChildren___nodes___internal___ignoreType wpChildren___nodes___internal___mediaType wpChildren___nodes___internal___owner wpChildren___nodes___internal___type wpChildren___nodes___isContentNode wpChildren___nodes___isTermNode wpChildren___nodes___link wpChildren___nodes___modified wpChildren___nodes___modifiedGmt wpChildren___nodes___nodeType wpChildren___nodes___parent___children wpChildren___nodes___parent___id wpChildren___nodes___slug wpChildren___nodes___status wpChildren___nodes___template___templateName wpChildren___nodes___uri wpParent___node___children wpParent___node___children___children wpParent___node___children___id wpParent___node___contentTypeName wpParent___node___databaseId wpParent___node___date wpParent___node___dateGmt wpParent___node___desiredSlug wpParent___node___enclosure wpParent___node___guid wpParent___node___id wpParent___node___internal___content wpParent___node___internal___contentDigest wpParent___node___internal___description wpParent___node___internal___fieldOwners wpParent___node___internal___ignoreType wpParent___node___internal___mediaType wpParent___node___internal___owner wpParent___node___internal___type wpParent___node___isContentNode wpParent___node___isTermNode wpParent___node___link wpParent___node___modified wpParent___node___modifiedGmt wpParent___node___nodeType wpParent___node___parent___children wpParent___node___parent___id wpParent___node___slug wpParent___node___status wpParent___node___template___templateName wpParent___node___uri } input WpMediaItemFilterInput { altText: StringQueryOperatorInput ancestors: WpHierarchicalContentNodeToContentNodeAncestorsConnectionFilterInput author: WpNodeWithAuthorToUserConnectionEdgeFilterInput authorDatabaseId: IntQueryOperatorInput authorId: IDQueryOperatorInput caption: StringQueryOperatorInput children: NodeFilterListInput commentCount: IntQueryOperatorInput commentStatus: StringQueryOperatorInput comments: WpMediaItemToCommentConnectionFilterInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput description: StringQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput fileSize: IntQueryOperatorInput filename: StringQueryOperatorInput filesize: IntQueryOperatorInput gatsbyImage: JSONQueryOperatorInput guid: StringQueryOperatorInput height: IntQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput localFile: FileFilterInput mediaDetails: WpMediaDetailsFilterInput mediaItemUrl: StringQueryOperatorInput mediaType: StringQueryOperatorInput mimeType: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput publicUrl: StringQueryOperatorInput remoteFile: FileFilterInput resize: RemoteFileResizeFilterInput sizes: StringQueryOperatorInput slug: StringQueryOperatorInput sourceUrl: StringQueryOperatorInput srcSet: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput title: StringQueryOperatorInput uri: StringQueryOperatorInput width: IntQueryOperatorInput wpChildren: WpHierarchicalContentNodeToContentNodeChildrenConnectionFilterInput wpParent: WpHierarchicalContentNodeToParentContentNodeConnectionEdgeFilterInput } type WpMediaItemGroupConnection { distinct(field: WpMediaItemFieldsEnum!): [String!]! edges: [WpMediaItemEdge!]! field: String! fieldValue: String group(field: WpMediaItemFieldsEnum!, limit: Int, skip: Int): [WpMediaItemGroupConnection!]! max(field: WpMediaItemFieldsEnum!): Float min(field: WpMediaItemFieldsEnum!): Float nodes: [WpMediaItem!]! pageInfo: PageInfo! sum(field: WpMediaItemFieldsEnum!): Float totalCount: Int! } """ Meta connected to a MediaItem """ type WpMediaItemMeta { """ Aperture measurement of the media item. """ aperture: Float """ Information about the camera used to create the media item. """ camera: String """ The text string description associated with the media item. """ caption: String """ Copyright information associated with the media item. """ copyright: String """ The date/time when the media was created. """ createdTimestamp: Int """ The original creator of the media item. """ credit: String """ The focal length value of the media item. """ focalLength: Float """ The ISO (International Organization for Standardization) value of the media item. """ iso: Int """ List of keywords used to describe or identfy the media item. """ keywords: [String] """ The vertical or horizontal aspect of the media item. """ orientation: String """ The shutter speed information of the media item. """ shutterSpeed: Float """ A useful title for the media item. """ title: String } input WpMediaItemMetaFilterInput { aperture: FloatQueryOperatorInput camera: StringQueryOperatorInput caption: StringQueryOperatorInput copyright: StringQueryOperatorInput createdTimestamp: IntQueryOperatorInput credit: StringQueryOperatorInput focalLength: FloatQueryOperatorInput iso: IntQueryOperatorInput keywords: StringQueryOperatorInput orientation: StringQueryOperatorInput shutterSpeed: FloatQueryOperatorInput title: StringQueryOperatorInput } input WpMediaItemSortInput { fields: [WpMediaItemFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the mediaItem type and the Comment type """ type WpMediaItemToCommentConnection { """ The nodes of the connection, without the edges """ nodes: [WpComment] } input WpMediaItemToCommentConnectionFilterInput { nodes: WpCommentFilterListInput } """ Details of an available size for a media item """ type WpMediaSize { """ The filename of the referenced size """ file: String """ The filesize of the resource """ fileSize: Int """ The height of the referenced size """ height: String """ The mime type of the referenced size """ mimeType: String """ The referenced size name """ name: String """ The url of the referenced size """ sourceUrl: String """ The width of the referenced size """ width: String } input WpMediaSizeFilterInput { file: StringQueryOperatorInput fileSize: IntQueryOperatorInput height: StringQueryOperatorInput mimeType: StringQueryOperatorInput name: StringQueryOperatorInput sourceUrl: StringQueryOperatorInput width: StringQueryOperatorInput } input WpMediaSizeFilterListInput { elemMatch: WpMediaSizeFilterInput } """ Menus are the containers for navigation items. Menus can be assigned to menu locations, which are typically registered by the active theme. """ type WpMenu implements Node & WpDatabaseIdentifier & WpNode { children: [Node!]! """ The number of items in the menu """ count: Int """ The unique identifier stored in the database """ databaseId: Int! id: ID! internal: Internal! """ The locations a menu is assigned to """ locations: [WpMenuLocationEnum] """ Connection between the Menu type and the MenuItem type """ menuItems: WpMenuToMenuItemConnection """ Display name of the menu. Equivalent to WP_Term->name. """ name: String nodeType: String parent: Node """ The url friendly name of the menu. Equivalent to WP_Term->slug """ slug: String } type WpMenuConnection { distinct(field: WpMenuFieldsEnum!): [String!]! edges: [WpMenuEdge!]! group(field: WpMenuFieldsEnum!, limit: Int, skip: Int): [WpMenuGroupConnection!]! max(field: WpMenuFieldsEnum!): Float min(field: WpMenuFieldsEnum!): Float nodes: [WpMenu!]! pageInfo: PageInfo! sum(field: WpMenuFieldsEnum!): Float totalCount: Int! } type WpMenuEdge { next: WpMenu node: WpMenu! previous: WpMenu } enum WpMenuFieldsEnum { children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id count databaseId id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type locations menuItems___nodes menuItems___nodes___childItems___nodes menuItems___nodes___children menuItems___nodes___children___children menuItems___nodes___children___id menuItems___nodes___cssClasses menuItems___nodes___databaseId menuItems___nodes___description menuItems___nodes___id menuItems___nodes___internal___content menuItems___nodes___internal___contentDigest menuItems___nodes___internal___description menuItems___nodes___internal___fieldOwners menuItems___nodes___internal___ignoreType menuItems___nodes___internal___mediaType menuItems___nodes___internal___owner menuItems___nodes___internal___type menuItems___nodes___label menuItems___nodes___linkRelationship menuItems___nodes___locations menuItems___nodes___nodeType menuItems___nodes___order menuItems___nodes___parentDatabaseId menuItems___nodes___parentId menuItems___nodes___parent___children menuItems___nodes___parent___id menuItems___nodes___path menuItems___nodes___target menuItems___nodes___title menuItems___nodes___url name nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id slug } input WpMenuFilterInput { children: NodeFilterListInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput locations: WpMenuLocationEnumQueryOperatorInput menuItems: WpMenuToMenuItemConnectionFilterInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput slug: StringQueryOperatorInput } type WpMenuGroupConnection { distinct(field: WpMenuFieldsEnum!): [String!]! edges: [WpMenuEdge!]! field: String! fieldValue: String group(field: WpMenuFieldsEnum!, limit: Int, skip: Int): [WpMenuGroupConnection!]! max(field: WpMenuFieldsEnum!): Float min(field: WpMenuFieldsEnum!): Float nodes: [WpMenu!]! pageInfo: PageInfo! sum(field: WpMenuFieldsEnum!): Float totalCount: Int! } """ Navigation menu items are the individual items assigned to a menu. These are rendered as the links in a navigation menu. """ type WpMenuItem implements Node & WpDatabaseIdentifier & WpNode { """ Connection between the MenuItem type and the MenuItem type """ childItems: WpMenuItemToMenuItemConnection children: [Node!]! """ Connection from MenuItem to it's connected node """ connectedNode: WpMenuItemToMenuItemLinkableConnectionEdge """ Class attribute for the menu item link """ cssClasses: [String] """ The unique identifier stored in the database """ databaseId: Int! """ Description of the menu item. """ description: String id: ID! internal: Internal! """ Label or title of the menu item. """ label: String """ Link relationship (XFN) of the menu item. """ linkRelationship: String """ The locations the menu item's Menu is assigned to """ locations: [WpMenuLocationEnum] """ The Menu a MenuItem is part of """ menu: WpMenuItemToMenuConnectionEdge nodeType: String """ Menu item order """ order: Int parent: Node """ The database id of the parent menu item or null if it is the root """ parentDatabaseId: Int """ The globally unique identifier of the parent nav menu item object. """ parentId: ID """ Path for the resource. Relative path for internal resources. Absolute path for external resources. """ path: String """ Target attribute for the menu item link. """ target: String """ Title attribute for the menu item link """ title: String """ URL or destination of the menu item. """ url: String } type WpMenuItemConnection { distinct(field: WpMenuItemFieldsEnum!): [String!]! edges: [WpMenuItemEdge!]! group(field: WpMenuItemFieldsEnum!, limit: Int, skip: Int): [WpMenuItemGroupConnection!]! max(field: WpMenuItemFieldsEnum!): Float min(field: WpMenuItemFieldsEnum!): Float nodes: [WpMenuItem!]! pageInfo: PageInfo! sum(field: WpMenuItemFieldsEnum!): Float totalCount: Int! } type WpMenuItemEdge { next: WpMenuItem node: WpMenuItem! previous: WpMenuItem } enum WpMenuItemFieldsEnum { childItems___nodes childItems___nodes___childItems___nodes childItems___nodes___children childItems___nodes___children___children childItems___nodes___children___id childItems___nodes___cssClasses childItems___nodes___databaseId childItems___nodes___description childItems___nodes___id childItems___nodes___internal___content childItems___nodes___internal___contentDigest childItems___nodes___internal___description childItems___nodes___internal___fieldOwners childItems___nodes___internal___ignoreType childItems___nodes___internal___mediaType childItems___nodes___internal___owner childItems___nodes___internal___type childItems___nodes___label childItems___nodes___linkRelationship childItems___nodes___locations childItems___nodes___nodeType childItems___nodes___order childItems___nodes___parentDatabaseId childItems___nodes___parentId childItems___nodes___parent___children childItems___nodes___parent___id childItems___nodes___path childItems___nodes___target childItems___nodes___title childItems___nodes___url children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id connectedNode___node___databaseId connectedNode___node___id connectedNode___node___uri cssClasses databaseId description id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type label linkRelationship locations menu___node___children menu___node___children___children menu___node___children___id menu___node___count menu___node___databaseId menu___node___id menu___node___internal___content menu___node___internal___contentDigest menu___node___internal___description menu___node___internal___fieldOwners menu___node___internal___ignoreType menu___node___internal___mediaType menu___node___internal___owner menu___node___internal___type menu___node___locations menu___node___menuItems___nodes menu___node___name menu___node___nodeType menu___node___parent___children menu___node___parent___id menu___node___slug nodeType order parentDatabaseId parentId parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id path target title url } input WpMenuItemFilterInput { childItems: WpMenuItemToMenuItemConnectionFilterInput children: NodeFilterListInput connectedNode: WpMenuItemToMenuItemLinkableConnectionEdgeFilterInput cssClasses: StringQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput label: StringQueryOperatorInput linkRelationship: StringQueryOperatorInput locations: WpMenuLocationEnumQueryOperatorInput menu: WpMenuItemToMenuConnectionEdgeFilterInput nodeType: StringQueryOperatorInput order: IntQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput path: StringQueryOperatorInput target: StringQueryOperatorInput title: StringQueryOperatorInput url: StringQueryOperatorInput } input WpMenuItemFilterListInput { elemMatch: WpMenuItemFilterInput } type WpMenuItemGroupConnection { distinct(field: WpMenuItemFieldsEnum!): [String!]! edges: [WpMenuItemEdge!]! field: String! fieldValue: String group(field: WpMenuItemFieldsEnum!, limit: Int, skip: Int): [WpMenuItemGroupConnection!]! max(field: WpMenuItemFieldsEnum!): Float min(field: WpMenuItemFieldsEnum!): Float nodes: [WpMenuItem!]! pageInfo: PageInfo! sum(field: WpMenuItemFieldsEnum!): Float totalCount: Int! } interface WpMenuItemLinkable { """ The unique resource identifier path """ databaseId: Int! """ The unique resource identifier path """ id: ID! """ The unique resource identifier path """ uri: String } input WpMenuItemLinkableFilterInput { databaseId: IntQueryOperatorInput id: IDQueryOperatorInput uri: StringQueryOperatorInput } input WpMenuItemSortInput { fields: [WpMenuItemFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the MenuItem type and the Menu type """ type WpMenuItemToMenuConnectionEdge { """ The node of the connection, without the edges """ node: WpMenu } input WpMenuItemToMenuConnectionEdgeFilterInput { node: WpMenuFilterInput } """ Connection between the MenuItem type and the MenuItem type """ type WpMenuItemToMenuItemConnection { """ The nodes of the connection, without the edges """ nodes: [WpMenuItem] } input WpMenuItemToMenuItemConnectionFilterInput { nodes: WpMenuItemFilterListInput } """ Connection between the MenuItem type and the MenuItemLinkable type """ type WpMenuItemToMenuItemLinkableConnectionEdge { """ The node of the connection, without the edges """ node: WpMenuItemLinkable } input WpMenuItemToMenuItemLinkableConnectionEdgeFilterInput { node: WpMenuItemLinkableFilterInput } """ Registered menu locations """ enum WpMenuLocationEnum { EMPTY } input WpMenuLocationEnumQueryOperatorInput { eq: WpMenuLocationEnum in: [WpMenuLocationEnum] ne: WpMenuLocationEnum nin: [WpMenuLocationEnum] } input WpMenuSortInput { fields: [WpMenuFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the Menu type and the MenuItem type """ type WpMenuToMenuItemConnection { """ The nodes of the connection, without the edges """ nodes: [WpMenuItem] } input WpMenuToMenuItemConnectionFilterInput { nodes: WpMenuItemFilterListInput } interface WpNode { """ The globally unique ID for the object """ id: ID! } input WpNodeFilterInput { id: IDQueryOperatorInput } interface WpNodeWithAuthor { """ Connection between the NodeWithAuthor type and the User type """ author: WpNodeWithAuthorToUserConnectionEdge """ The database identifier of the author of the node """ authorDatabaseId: Int """ The globally unique identifier of the author of the node """ authorId: ID } """ Connection between the NodeWithAuthor type and the User type """ type WpNodeWithAuthorToUserConnectionEdge { """ The node of the connection, without the edges """ node: WpUser } input WpNodeWithAuthorToUserConnectionEdgeFilterInput { node: WpUserFilterInput } interface WpNodeWithComments { """ The number of comments. Even though WPGraphQL denotes this field as an integer, in WordPress this field should be saved as a numeric string for compatibility. """ commentCount: Int """ Whether the comments are open or closed for this particular post. """ commentStatus: String } interface WpNodeWithContentEditor { """ The content of the post. """ content: String } interface WpNodeWithExcerpt { """ The excerpt of the post. """ excerpt: String } interface WpNodeWithFeaturedImage { """ Connection between the ContentNode type and the ContentType type """ contentType: WpContentNodeToContentTypeConnectionEdge """ The name of the Content Type the node belongs to """ contentTypeName: String! """ The unique identifier stored in the database """ databaseId: Int! """ Post publishing date. """ date: Date """ The publishing date set in GMT. """ dateGmt: Date """ The desired slug of the post """ desiredSlug: String """ The RSS enclosure for the object """ enclosure: String """ Connection between the NodeWithFeaturedImage type and the MediaItem type """ featuredImage: WpNodeWithFeaturedImageToMediaItemConnectionEdge """ The database identifier for the featured image node assigned to the content node """ featuredImageDatabaseId: Int """ Globally unique ID of the featured image assigned to the node """ featuredImageId: ID """ The global unique identifier for this post. This currently matches the value stored in WP_Post->guid and the guid column in the "post_objects" database table. """ guid: String """ The unique resource identifier path """ id: ID! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The user that most recently edited the node """ lastEditedBy: WpContentNodeToEditLastConnectionEdge """ The permalink of the post """ link: String """ The local modified time for a post. If a post was recently updated the modified field will change to match the corresponding time. """ modified: Date """ The GMT modified time for a post. If a post was recently updated the modified field will change to match the corresponding time in GMT. """ modifiedGmt: Date """ The uri slug for the post. This is equivalent to the WP_Post->post_name field and the post_name column in the database for the "post_objects" table. """ slug: String """ The current status of the object """ status: String """ The template assigned to a node of content """ template: WpContentTemplate """ The unique resource identifier path """ uri: String } """ Connection between the NodeWithFeaturedImage type and the MediaItem type """ type WpNodeWithFeaturedImageToMediaItemConnectionEdge { """ The node of the connection, without the edges """ node: WpMediaItem } input WpNodeWithFeaturedImageToMediaItemConnectionEdgeFilterInput { node: WpMediaItemFilterInput } interface WpNodeWithPageAttributes { """ A field used for ordering posts. This is typically used with nav menu items or for special ordering of hierarchical content types. """ menuOrder: Int } interface WpNodeWithRevisions { """ True if the node is a revision of another node """ isRevision: Boolean } """ Connection between the NodeWithRevisions type and the ContentNode type """ type WpNodeWithRevisionsToContentNodeConnectionEdge { """ The node of the connection, without the edges """ node: WpContentNode } interface WpNodeWithTemplate { """ The template assigned to the node """ template: WpContentTemplate } interface WpNodeWithTitle { """ The title of the post. This is currently just the raw title. An amendment to support rendered title needs to be made. """ title: String } interface WpNodeWithTrackbacks { """ Whether the pings are open or closed for this particular post. """ pingStatus: String """ URLs that have been pinged. """ pinged: [String] """ URLs queued to be pinged. """ toPing: [String] } """ The page type """ type WpPage implements Node & WpBlockEditorContentNode & WpContentNode & WpDatabaseIdentifier & WpHierarchicalContentNode & WpMenuItemLinkable & WpNode & WpNodeWithAuthor & WpNodeWithComments & WpNodeWithContentEditor & WpNodeWithFeaturedImage & WpNodeWithPageAttributes & WpNodeWithRevisions & WpNodeWithTemplate & WpNodeWithTitle & WpUniformResourceIdentifiable { """ Returns ancestors of the node. Default ordered as lowest (closest to the child) to highest (closest to the root). """ ancestors: WpHierarchicalContentNodeToContentNodeAncestorsConnection """ Connection between the NodeWithAuthor type and the User type """ author: WpNodeWithAuthorToUserConnectionEdge """ The database identifier of the author of the node """ authorDatabaseId: Int """ The globally unique identifier of the author of the node """ authorId: ID """ Gutenberg blocks """ blocks: [WpBlock!] """ Gutenberg blocks as json string """ blocksJSON: String children: [Node!]! """ The number of comments. Even though WPGraphQL denotes this field as an integer, in WordPress this field should be saved as a numeric string for compatibility. """ commentCount: Int """ Whether the comments are open or closed for this particular post. """ commentStatus: String """ Connection between the page type and the Comment type """ comments: WpPageToCommentConnection """ The content of the post. """ content: String """ Connection between the ContentNode type and the ContentType type """ contentType: WpContentNodeToContentTypeConnectionEdge """ The name of the Content Type the node belongs to """ contentTypeName: String! """ The unique resource identifier path """ databaseId: Int! """ Post publishing date. """ date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The publishing date set in GMT. """ dateGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The desired slug of the post """ desiredSlug: String """ The RSS enclosure for the object """ enclosure: String """ Connection between the NodeWithFeaturedImage type and the MediaItem type """ featuredImage: WpNodeWithFeaturedImageToMediaItemConnectionEdge """ The database identifier for the featured image node assigned to the content node """ featuredImageDatabaseId: Int """ Globally unique ID of the featured image assigned to the node """ featuredImageId: ID """ The global unique identifier for this post. This currently matches the value stored in WP_Post->guid and the guid column in the "post_objects" database table. """ guid: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether this page is set to the static front page. """ isFrontPage: Boolean! """ Whether this page is set to the blog posts page. """ isPostsPage: Boolean! """ Whether this page is set to the privacy page. """ isPrivacyPage: Boolean! """ True if the node is a revision of another node """ isRevision: Boolean """ Whether the node is a Term """ isTermNode: Boolean! """ The user that most recently edited the node """ lastEditedBy: WpContentNodeToEditLastConnectionEdge """ The permalink of the post """ link: String """ A field used for ordering posts. This is typically used with nav menu items or for special ordering of hierarchical content types. """ menuOrder: Int """ The local modified time for a post. If a post was recently updated the modified field will change to match the corresponding time. """ modified( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The GMT modified time for a post. If a post was recently updated the modified field will change to match the corresponding time in GMT. """ modifiedGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date nodeType: String parent: Node """ Database id of the parent node """ parentDatabaseId: Int """ The globally unique identifier of the parent node. """ parentId: ID """ Previewed gutenberg blocks """ previewBlocks: [WpBlock!] """ Previewed Gutenberg blocks as json string """ previewBlocksJSON: String """ The uri slug for the post. This is equivalent to the WP_Post->post_name field and the post_name column in the database for the "post_objects" table. """ slug: String """ The current status of the object """ status: String """ The template assigned to a node of content """ template: WpContentTemplate """ The title of the post. This is currently just the raw title. An amendment to support rendered title needs to be made. """ title: String """ The unique resource identifier path """ uri: String """ Connection between the HierarchicalContentNode type and the ContentNode type """ wpChildren: WpHierarchicalContentNodeToContentNodeChildrenConnection """ The parent of the node. The parent object can be of various types """ wpParent: WpHierarchicalContentNodeToParentContentNodeConnectionEdge } type WpPageConnection { distinct(field: WpPageFieldsEnum!): [String!]! edges: [WpPageEdge!]! group(field: WpPageFieldsEnum!, limit: Int, skip: Int): [WpPageGroupConnection!]! max(field: WpPageFieldsEnum!): Float min(field: WpPageFieldsEnum!): Float nodes: [WpPage!]! pageInfo: PageInfo! sum(field: WpPageFieldsEnum!): Float totalCount: Int! } type WpPageEdge { next: WpPage node: WpPage! previous: WpPage } enum WpPageFieldsEnum { ancestors___nodes ancestors___nodes___children ancestors___nodes___children___children ancestors___nodes___children___id ancestors___nodes___contentTypeName ancestors___nodes___databaseId ancestors___nodes___date ancestors___nodes___dateGmt ancestors___nodes___desiredSlug ancestors___nodes___enclosure ancestors___nodes___guid ancestors___nodes___id ancestors___nodes___internal___content ancestors___nodes___internal___contentDigest ancestors___nodes___internal___description ancestors___nodes___internal___fieldOwners ancestors___nodes___internal___ignoreType ancestors___nodes___internal___mediaType ancestors___nodes___internal___owner ancestors___nodes___internal___type ancestors___nodes___isContentNode ancestors___nodes___isTermNode ancestors___nodes___link ancestors___nodes___modified ancestors___nodes___modifiedGmt ancestors___nodes___nodeType ancestors___nodes___parent___children ancestors___nodes___parent___id ancestors___nodes___slug ancestors___nodes___status ancestors___nodes___template___templateName ancestors___nodes___uri authorDatabaseId authorId author___node___avatar___default author___node___avatar___extraAttr author___node___avatar___forceDefault author___node___avatar___foundAvatar author___node___avatar___height author___node___avatar___rating author___node___avatar___scheme author___node___avatar___size author___node___avatar___url author___node___avatar___width author___node___blockEditorPreviews___nodes author___node___capKey author___node___capabilities author___node___children author___node___children___children author___node___children___id author___node___comments___nodes author___node___databaseId author___node___description author___node___email author___node___extraCapabilities author___node___firstName author___node___id author___node___internal___content author___node___internal___contentDigest author___node___internal___description author___node___internal___fieldOwners author___node___internal___ignoreType author___node___internal___mediaType author___node___internal___owner author___node___internal___type author___node___isContentNode author___node___isTermNode author___node___lastName author___node___locale author___node___name author___node___nicename author___node___nickname author___node___nodeType author___node___pages___nodes author___node___parent___children author___node___parent___id author___node___posts___nodes author___node___registeredDate author___node___roles___nodes author___node___slug author___node___uri author___node___url author___node___username blocks blocksJSON blocks___attributesJSON blocks___dynamicContent blocks___innerBlocks blocks___innerBlocks___attributesJSON blocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___attributesJSON blocks___innerBlocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___isDynamic blocks___innerBlocks___innerBlocks___name blocks___innerBlocks___innerBlocks___order blocks___innerBlocks___innerBlocks___originalContent blocks___innerBlocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___innerBlocks___saveContent blocks___innerBlocks___isDynamic blocks___innerBlocks___name blocks___innerBlocks___order blocks___innerBlocks___originalContent blocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___parentNode___id blocks___innerBlocks___saveContent blocks___isDynamic blocks___name blocks___order blocks___originalContent blocks___parentNodeDatabaseId blocks___parentNode___id blocks___saveContent children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id commentCount commentStatus comments___nodes comments___nodes___agent comments___nodes___approved comments___nodes___authorIp comments___nodes___children comments___nodes___children___children comments___nodes___children___id comments___nodes___content comments___nodes___databaseId comments___nodes___date comments___nodes___dateGmt comments___nodes___id comments___nodes___internal___content comments___nodes___internal___contentDigest comments___nodes___internal___description comments___nodes___internal___fieldOwners comments___nodes___internal___ignoreType comments___nodes___internal___mediaType comments___nodes___internal___owner comments___nodes___internal___type comments___nodes___karma comments___nodes___nodeType comments___nodes___parentDatabaseId comments___nodes___parentId comments___nodes___parent___children comments___nodes___parent___id comments___nodes___replies___nodes comments___nodes___type content contentTypeName contentType___node___archivePath contentType___node___canExport contentType___node___children contentType___node___children___children contentType___node___children___id contentType___node___connectedTaxonomies___nodes contentType___node___contentNodes___nodes contentType___node___deleteWithUser contentType___node___description contentType___node___excludeFromSearch contentType___node___graphqlPluralName contentType___node___graphqlSingleName contentType___node___hasArchive contentType___node___hierarchical contentType___node___id contentType___node___internal___content contentType___node___internal___contentDigest contentType___node___internal___description contentType___node___internal___fieldOwners contentType___node___internal___ignoreType contentType___node___internal___mediaType contentType___node___internal___owner contentType___node___internal___type contentType___node___isContentNode contentType___node___isFrontPage contentType___node___isPostsPage contentType___node___isTermNode contentType___node___label contentType___node___labels___addNew contentType___node___labels___addNewItem contentType___node___labels___allItems contentType___node___labels___archives contentType___node___labels___attributes contentType___node___labels___editItem contentType___node___labels___featuredImage contentType___node___labels___filterItemsList contentType___node___labels___insertIntoItem contentType___node___labels___itemsList contentType___node___labels___itemsListNavigation contentType___node___labels___menuName contentType___node___labels___name contentType___node___labels___newItem contentType___node___labels___notFound contentType___node___labels___notFoundInTrash contentType___node___labels___parentItemColon contentType___node___labels___removeFeaturedImage contentType___node___labels___searchItems contentType___node___labels___setFeaturedImage contentType___node___labels___singularName contentType___node___labels___uploadedToThisItem contentType___node___labels___useFeaturedImage contentType___node___labels___viewItem contentType___node___labels___viewItems contentType___node___menuIcon contentType___node___menuPosition contentType___node___name contentType___node___nodeType contentType___node___parent___children contentType___node___parent___id contentType___node___public contentType___node___publiclyQueryable contentType___node___restBase contentType___node___restControllerClass contentType___node___showInAdminBar contentType___node___showInGraphql contentType___node___showInMenu contentType___node___showInNavMenus contentType___node___showInRest contentType___node___showUi contentType___node___uri databaseId date dateGmt desiredSlug enclosure featuredImageDatabaseId featuredImageId featuredImage___node___altText featuredImage___node___ancestors___nodes featuredImage___node___authorDatabaseId featuredImage___node___authorId featuredImage___node___caption featuredImage___node___children featuredImage___node___children___children featuredImage___node___children___id featuredImage___node___commentCount featuredImage___node___commentStatus featuredImage___node___comments___nodes featuredImage___node___contentTypeName featuredImage___node___databaseId featuredImage___node___date featuredImage___node___dateGmt featuredImage___node___description featuredImage___node___desiredSlug featuredImage___node___enclosure featuredImage___node___fileSize featuredImage___node___filename featuredImage___node___filesize featuredImage___node___gatsbyImage featuredImage___node___guid featuredImage___node___height featuredImage___node___id featuredImage___node___internal___content featuredImage___node___internal___contentDigest featuredImage___node___internal___description featuredImage___node___internal___fieldOwners featuredImage___node___internal___ignoreType featuredImage___node___internal___mediaType featuredImage___node___internal___owner featuredImage___node___internal___type featuredImage___node___isContentNode featuredImage___node___isTermNode featuredImage___node___link featuredImage___node___localFile___absolutePath featuredImage___node___localFile___accessTime featuredImage___node___localFile___atime featuredImage___node___localFile___atimeMs featuredImage___node___localFile___base featuredImage___node___localFile___birthTime featuredImage___node___localFile___birthtime featuredImage___node___localFile___birthtimeMs featuredImage___node___localFile___blksize featuredImage___node___localFile___blocks featuredImage___node___localFile___changeTime featuredImage___node___localFile___children featuredImage___node___localFile___childrenImageSharp featuredImage___node___localFile___ctime featuredImage___node___localFile___ctimeMs featuredImage___node___localFile___dev featuredImage___node___localFile___dir featuredImage___node___localFile___ext featuredImage___node___localFile___extension featuredImage___node___localFile___gid featuredImage___node___localFile___hash featuredImage___node___localFile___id featuredImage___node___localFile___ino featuredImage___node___localFile___mode featuredImage___node___localFile___modifiedTime featuredImage___node___localFile___mtime featuredImage___node___localFile___mtimeMs featuredImage___node___localFile___name featuredImage___node___localFile___nlink featuredImage___node___localFile___prettySize featuredImage___node___localFile___publicURL featuredImage___node___localFile___rdev featuredImage___node___localFile___relativeDirectory featuredImage___node___localFile___relativePath featuredImage___node___localFile___root featuredImage___node___localFile___size featuredImage___node___localFile___sourceInstanceName featuredImage___node___localFile___uid featuredImage___node___mediaDetails___file featuredImage___node___mediaDetails___height featuredImage___node___mediaDetails___sizes featuredImage___node___mediaDetails___width featuredImage___node___mediaItemUrl featuredImage___node___mediaType featuredImage___node___mimeType featuredImage___node___modified featuredImage___node___modifiedGmt featuredImage___node___nodeType featuredImage___node___parentDatabaseId featuredImage___node___parentId featuredImage___node___parent___children featuredImage___node___parent___id featuredImage___node___publicUrl featuredImage___node___remoteFile___absolutePath featuredImage___node___remoteFile___accessTime featuredImage___node___remoteFile___atime featuredImage___node___remoteFile___atimeMs featuredImage___node___remoteFile___base featuredImage___node___remoteFile___birthTime featuredImage___node___remoteFile___birthtime featuredImage___node___remoteFile___birthtimeMs featuredImage___node___remoteFile___blksize featuredImage___node___remoteFile___blocks featuredImage___node___remoteFile___changeTime featuredImage___node___remoteFile___children featuredImage___node___remoteFile___childrenImageSharp featuredImage___node___remoteFile___ctime featuredImage___node___remoteFile___ctimeMs featuredImage___node___remoteFile___dev featuredImage___node___remoteFile___dir featuredImage___node___remoteFile___ext featuredImage___node___remoteFile___extension featuredImage___node___remoteFile___gid featuredImage___node___remoteFile___hash featuredImage___node___remoteFile___id featuredImage___node___remoteFile___ino featuredImage___node___remoteFile___mode featuredImage___node___remoteFile___modifiedTime featuredImage___node___remoteFile___mtime featuredImage___node___remoteFile___mtimeMs featuredImage___node___remoteFile___name featuredImage___node___remoteFile___nlink featuredImage___node___remoteFile___prettySize featuredImage___node___remoteFile___publicURL featuredImage___node___remoteFile___rdev featuredImage___node___remoteFile___relativeDirectory featuredImage___node___remoteFile___relativePath featuredImage___node___remoteFile___root featuredImage___node___remoteFile___size featuredImage___node___remoteFile___sourceInstanceName featuredImage___node___remoteFile___uid featuredImage___node___resize___height featuredImage___node___resize___src featuredImage___node___resize___width featuredImage___node___sizes featuredImage___node___slug featuredImage___node___sourceUrl featuredImage___node___srcSet featuredImage___node___status featuredImage___node___template___templateName featuredImage___node___title featuredImage___node___uri featuredImage___node___width featuredImage___node___wpChildren___nodes guid id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isFrontPage isPostsPage isPrivacyPage isRevision isTermNode lastEditedBy___node___avatar___default lastEditedBy___node___avatar___extraAttr lastEditedBy___node___avatar___forceDefault lastEditedBy___node___avatar___foundAvatar lastEditedBy___node___avatar___height lastEditedBy___node___avatar___rating lastEditedBy___node___avatar___scheme lastEditedBy___node___avatar___size lastEditedBy___node___avatar___url lastEditedBy___node___avatar___width lastEditedBy___node___blockEditorPreviews___nodes lastEditedBy___node___capKey lastEditedBy___node___capabilities lastEditedBy___node___children lastEditedBy___node___children___children lastEditedBy___node___children___id lastEditedBy___node___comments___nodes lastEditedBy___node___databaseId lastEditedBy___node___description lastEditedBy___node___email lastEditedBy___node___extraCapabilities lastEditedBy___node___firstName lastEditedBy___node___id lastEditedBy___node___internal___content lastEditedBy___node___internal___contentDigest lastEditedBy___node___internal___description lastEditedBy___node___internal___fieldOwners lastEditedBy___node___internal___ignoreType lastEditedBy___node___internal___mediaType lastEditedBy___node___internal___owner lastEditedBy___node___internal___type lastEditedBy___node___isContentNode lastEditedBy___node___isTermNode lastEditedBy___node___lastName lastEditedBy___node___locale lastEditedBy___node___name lastEditedBy___node___nicename lastEditedBy___node___nickname lastEditedBy___node___nodeType lastEditedBy___node___pages___nodes lastEditedBy___node___parent___children lastEditedBy___node___parent___id lastEditedBy___node___posts___nodes lastEditedBy___node___registeredDate lastEditedBy___node___roles___nodes lastEditedBy___node___slug lastEditedBy___node___uri lastEditedBy___node___url lastEditedBy___node___username link menuOrder modified modifiedGmt nodeType parentDatabaseId parentId parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id previewBlocks previewBlocksJSON previewBlocks___attributesJSON previewBlocks___dynamicContent previewBlocks___innerBlocks previewBlocks___innerBlocks___attributesJSON previewBlocks___innerBlocks___dynamicContent previewBlocks___innerBlocks___innerBlocks previewBlocks___innerBlocks___innerBlocks___attributesJSON previewBlocks___innerBlocks___innerBlocks___dynamicContent previewBlocks___innerBlocks___innerBlocks___innerBlocks previewBlocks___innerBlocks___innerBlocks___isDynamic previewBlocks___innerBlocks___innerBlocks___name previewBlocks___innerBlocks___innerBlocks___order previewBlocks___innerBlocks___innerBlocks___originalContent previewBlocks___innerBlocks___innerBlocks___parentNodeDatabaseId previewBlocks___innerBlocks___innerBlocks___saveContent previewBlocks___innerBlocks___isDynamic previewBlocks___innerBlocks___name previewBlocks___innerBlocks___order previewBlocks___innerBlocks___originalContent previewBlocks___innerBlocks___parentNodeDatabaseId previewBlocks___innerBlocks___parentNode___id previewBlocks___innerBlocks___saveContent previewBlocks___isDynamic previewBlocks___name previewBlocks___order previewBlocks___originalContent previewBlocks___parentNodeDatabaseId previewBlocks___parentNode___id previewBlocks___saveContent slug status template___templateName title uri wpChildren___nodes wpChildren___nodes___children wpChildren___nodes___children___children wpChildren___nodes___children___id wpChildren___nodes___contentTypeName wpChildren___nodes___databaseId wpChildren___nodes___date wpChildren___nodes___dateGmt wpChildren___nodes___desiredSlug wpChildren___nodes___enclosure wpChildren___nodes___guid wpChildren___nodes___id wpChildren___nodes___internal___content wpChildren___nodes___internal___contentDigest wpChildren___nodes___internal___description wpChildren___nodes___internal___fieldOwners wpChildren___nodes___internal___ignoreType wpChildren___nodes___internal___mediaType wpChildren___nodes___internal___owner wpChildren___nodes___internal___type wpChildren___nodes___isContentNode wpChildren___nodes___isTermNode wpChildren___nodes___link wpChildren___nodes___modified wpChildren___nodes___modifiedGmt wpChildren___nodes___nodeType wpChildren___nodes___parent___children wpChildren___nodes___parent___id wpChildren___nodes___slug wpChildren___nodes___status wpChildren___nodes___template___templateName wpChildren___nodes___uri wpParent___node___children wpParent___node___children___children wpParent___node___children___id wpParent___node___contentTypeName wpParent___node___databaseId wpParent___node___date wpParent___node___dateGmt wpParent___node___desiredSlug wpParent___node___enclosure wpParent___node___guid wpParent___node___id wpParent___node___internal___content wpParent___node___internal___contentDigest wpParent___node___internal___description wpParent___node___internal___fieldOwners wpParent___node___internal___ignoreType wpParent___node___internal___mediaType wpParent___node___internal___owner wpParent___node___internal___type wpParent___node___isContentNode wpParent___node___isTermNode wpParent___node___link wpParent___node___modified wpParent___node___modifiedGmt wpParent___node___nodeType wpParent___node___parent___children wpParent___node___parent___id wpParent___node___slug wpParent___node___status wpParent___node___template___templateName wpParent___node___uri } input WpPageFilterInput { ancestors: WpHierarchicalContentNodeToContentNodeAncestorsConnectionFilterInput author: WpNodeWithAuthorToUserConnectionEdgeFilterInput authorDatabaseId: IntQueryOperatorInput authorId: IDQueryOperatorInput blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput children: NodeFilterListInput commentCount: IntQueryOperatorInput commentStatus: StringQueryOperatorInput comments: WpPageToCommentConnectionFilterInput content: StringQueryOperatorInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput featuredImage: WpNodeWithFeaturedImageToMediaItemConnectionEdgeFilterInput featuredImageDatabaseId: IntQueryOperatorInput featuredImageId: IDQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isFrontPage: BooleanQueryOperatorInput isPostsPage: BooleanQueryOperatorInput isPrivacyPage: BooleanQueryOperatorInput isRevision: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput menuOrder: IntQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput parentDatabaseId: IntQueryOperatorInput parentId: IDQueryOperatorInput previewBlocks: WpBlockFilterListInput previewBlocksJSON: StringQueryOperatorInput slug: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput title: StringQueryOperatorInput uri: StringQueryOperatorInput wpChildren: WpHierarchicalContentNodeToContentNodeChildrenConnectionFilterInput wpParent: WpHierarchicalContentNodeToParentContentNodeConnectionEdgeFilterInput } input WpPageFilterListInput { elemMatch: WpPageFilterInput } type WpPageGroupConnection { distinct(field: WpPageFieldsEnum!): [String!]! edges: [WpPageEdge!]! field: String! fieldValue: String group(field: WpPageFieldsEnum!, limit: Int, skip: Int): [WpPageGroupConnection!]! max(field: WpPageFieldsEnum!): Float min(field: WpPageFieldsEnum!): Float nodes: [WpPage!]! pageInfo: PageInfo! sum(field: WpPageFieldsEnum!): Float totalCount: Int! } input WpPageSortInput { fields: [WpPageFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the page type and the Comment type """ type WpPageToCommentConnection { """ The nodes of the connection, without the edges """ nodes: [WpComment] } input WpPageToCommentConnectionFilterInput { nodes: WpCommentFilterListInput } """ The post type """ type WpPost implements Node & WpBlockEditorContentNode & WpContentNode & WpDatabaseIdentifier & WpMenuItemLinkable & WpNode & WpNodeWithAuthor & WpNodeWithComments & WpNodeWithContentEditor & WpNodeWithExcerpt & WpNodeWithFeaturedImage & WpNodeWithRevisions & WpNodeWithTemplate & WpNodeWithTitle & WpNodeWithTrackbacks & WpUniformResourceIdentifiable { """ Connection between the NodeWithAuthor type and the User type """ author: WpNodeWithAuthorToUserConnectionEdge """ The database identifier of the author of the node """ authorDatabaseId: Int """ The globally unique identifier of the author of the node """ authorId: ID """ Gutenberg blocks """ blocks: [WpBlock!] """ Gutenberg blocks as json string """ blocksJSON: String """ Connection between the post type and the category type """ categories: WpPostToCategoryConnection children: [Node!]! """ The number of comments. Even though WPGraphQL denotes this field as an integer, in WordPress this field should be saved as a numeric string for compatibility. """ commentCount: Int """ Whether the comments are open or closed for this particular post. """ commentStatus: String """ Connection between the post type and the Comment type """ comments: WpPostToCommentConnection """ The content of the post. """ content: String """ Connection between the ContentNode type and the ContentType type """ contentType: WpContentNodeToContentTypeConnectionEdge """ The name of the Content Type the node belongs to """ contentTypeName: String! """ The unique resource identifier path """ databaseId: Int! """ Post publishing date. """ date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The publishing date set in GMT. """ dateGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The desired slug of the post """ desiredSlug: String """ The RSS enclosure for the object """ enclosure: String """ The excerpt of the post. """ excerpt: String """ Connection between the NodeWithFeaturedImage type and the MediaItem type """ featuredImage: WpNodeWithFeaturedImageToMediaItemConnectionEdge """ The database identifier for the featured image node assigned to the content node """ featuredImageDatabaseId: Int """ Globally unique ID of the featured image assigned to the node """ featuredImageId: ID """ The global unique identifier for this post. This currently matches the value stored in WP_Post->guid and the guid column in the "post_objects" database table. """ guid: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ True if the node is a revision of another node """ isRevision: Boolean """ Whether this page is sticky """ isSticky: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The user that most recently edited the node """ lastEditedBy: WpContentNodeToEditLastConnectionEdge """ The permalink of the post """ link: String """ The local modified time for a post. If a post was recently updated the modified field will change to match the corresponding time. """ modified( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The GMT modified time for a post. If a post was recently updated the modified field will change to match the corresponding time in GMT. """ modifiedGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date nodeType: String parent: Node """ Whether the pings are open or closed for this particular post. """ pingStatus: String """ URLs that have been pinged. """ pinged: [String] """ Connection between the post type and the postFormat type """ postFormats: WpPostToPostFormatConnection """ Previewed gutenberg blocks """ previewBlocks: [WpBlock!] """ Previewed Gutenberg blocks as json string """ previewBlocksJSON: String """ The uri slug for the post. This is equivalent to the WP_Post->post_name field and the post_name column in the database for the "post_objects" table. """ slug: String """ The current status of the object """ status: String """ Connection between the post type and the tag type """ tags: WpPostToTagConnection """ The template assigned to a node of content """ template: WpContentTemplate """ Connection between the post type and the TermNode type """ terms: WpPostToTermNodeConnection """ The title of the post. This is currently just the raw title. An amendment to support rendered title needs to be made. """ title: String """ URLs queued to be pinged. """ toPing: [String] """ The unique resource identifier path """ uri: String } type WpPostConnection { distinct(field: WpPostFieldsEnum!): [String!]! edges: [WpPostEdge!]! group(field: WpPostFieldsEnum!, limit: Int, skip: Int): [WpPostGroupConnection!]! max(field: WpPostFieldsEnum!): Float min(field: WpPostFieldsEnum!): Float nodes: [WpPost!]! pageInfo: PageInfo! sum(field: WpPostFieldsEnum!): Float totalCount: Int! } type WpPostEdge { next: WpPost node: WpPost! previous: WpPost } enum WpPostFieldsEnum { authorDatabaseId authorId author___node___avatar___default author___node___avatar___extraAttr author___node___avatar___forceDefault author___node___avatar___foundAvatar author___node___avatar___height author___node___avatar___rating author___node___avatar___scheme author___node___avatar___size author___node___avatar___url author___node___avatar___width author___node___blockEditorPreviews___nodes author___node___capKey author___node___capabilities author___node___children author___node___children___children author___node___children___id author___node___comments___nodes author___node___databaseId author___node___description author___node___email author___node___extraCapabilities author___node___firstName author___node___id author___node___internal___content author___node___internal___contentDigest author___node___internal___description author___node___internal___fieldOwners author___node___internal___ignoreType author___node___internal___mediaType author___node___internal___owner author___node___internal___type author___node___isContentNode author___node___isTermNode author___node___lastName author___node___locale author___node___name author___node___nicename author___node___nickname author___node___nodeType author___node___pages___nodes author___node___parent___children author___node___parent___id author___node___posts___nodes author___node___registeredDate author___node___roles___nodes author___node___slug author___node___uri author___node___url author___node___username blocks blocksJSON blocks___attributesJSON blocks___dynamicContent blocks___innerBlocks blocks___innerBlocks___attributesJSON blocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___attributesJSON blocks___innerBlocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___isDynamic blocks___innerBlocks___innerBlocks___name blocks___innerBlocks___innerBlocks___order blocks___innerBlocks___innerBlocks___originalContent blocks___innerBlocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___innerBlocks___saveContent blocks___innerBlocks___isDynamic blocks___innerBlocks___name blocks___innerBlocks___order blocks___innerBlocks___originalContent blocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___parentNode___id blocks___innerBlocks___saveContent blocks___isDynamic blocks___name blocks___order blocks___originalContent blocks___parentNodeDatabaseId blocks___parentNode___id blocks___saveContent categories___nodes categories___nodes___ancestors___nodes categories___nodes___children categories___nodes___children___children categories___nodes___children___id categories___nodes___contentNodes___nodes categories___nodes___count categories___nodes___databaseId categories___nodes___description categories___nodes___id categories___nodes___internal___content categories___nodes___internal___contentDigest categories___nodes___internal___description categories___nodes___internal___fieldOwners categories___nodes___internal___ignoreType categories___nodes___internal___mediaType categories___nodes___internal___owner categories___nodes___internal___type categories___nodes___isContentNode categories___nodes___isTermNode categories___nodes___link categories___nodes___name categories___nodes___nodeType categories___nodes___parentDatabaseId categories___nodes___parentId categories___nodes___parent___children categories___nodes___parent___id categories___nodes___posts___nodes categories___nodes___slug categories___nodes___taxonomyName categories___nodes___termGroupId categories___nodes___termTaxonomyId categories___nodes___uri categories___nodes___wpChildren___nodes children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id commentCount commentStatus comments___nodes comments___nodes___agent comments___nodes___approved comments___nodes___authorIp comments___nodes___children comments___nodes___children___children comments___nodes___children___id comments___nodes___content comments___nodes___databaseId comments___nodes___date comments___nodes___dateGmt comments___nodes___id comments___nodes___internal___content comments___nodes___internal___contentDigest comments___nodes___internal___description comments___nodes___internal___fieldOwners comments___nodes___internal___ignoreType comments___nodes___internal___mediaType comments___nodes___internal___owner comments___nodes___internal___type comments___nodes___karma comments___nodes___nodeType comments___nodes___parentDatabaseId comments___nodes___parentId comments___nodes___parent___children comments___nodes___parent___id comments___nodes___replies___nodes comments___nodes___type content contentTypeName contentType___node___archivePath contentType___node___canExport contentType___node___children contentType___node___children___children contentType___node___children___id contentType___node___connectedTaxonomies___nodes contentType___node___contentNodes___nodes contentType___node___deleteWithUser contentType___node___description contentType___node___excludeFromSearch contentType___node___graphqlPluralName contentType___node___graphqlSingleName contentType___node___hasArchive contentType___node___hierarchical contentType___node___id contentType___node___internal___content contentType___node___internal___contentDigest contentType___node___internal___description contentType___node___internal___fieldOwners contentType___node___internal___ignoreType contentType___node___internal___mediaType contentType___node___internal___owner contentType___node___internal___type contentType___node___isContentNode contentType___node___isFrontPage contentType___node___isPostsPage contentType___node___isTermNode contentType___node___label contentType___node___labels___addNew contentType___node___labels___addNewItem contentType___node___labels___allItems contentType___node___labels___archives contentType___node___labels___attributes contentType___node___labels___editItem contentType___node___labels___featuredImage contentType___node___labels___filterItemsList contentType___node___labels___insertIntoItem contentType___node___labels___itemsList contentType___node___labels___itemsListNavigation contentType___node___labels___menuName contentType___node___labels___name contentType___node___labels___newItem contentType___node___labels___notFound contentType___node___labels___notFoundInTrash contentType___node___labels___parentItemColon contentType___node___labels___removeFeaturedImage contentType___node___labels___searchItems contentType___node___labels___setFeaturedImage contentType___node___labels___singularName contentType___node___labels___uploadedToThisItem contentType___node___labels___useFeaturedImage contentType___node___labels___viewItem contentType___node___labels___viewItems contentType___node___menuIcon contentType___node___menuPosition contentType___node___name contentType___node___nodeType contentType___node___parent___children contentType___node___parent___id contentType___node___public contentType___node___publiclyQueryable contentType___node___restBase contentType___node___restControllerClass contentType___node___showInAdminBar contentType___node___showInGraphql contentType___node___showInMenu contentType___node___showInNavMenus contentType___node___showInRest contentType___node___showUi contentType___node___uri databaseId date dateGmt desiredSlug enclosure excerpt featuredImageDatabaseId featuredImageId featuredImage___node___altText featuredImage___node___ancestors___nodes featuredImage___node___authorDatabaseId featuredImage___node___authorId featuredImage___node___caption featuredImage___node___children featuredImage___node___children___children featuredImage___node___children___id featuredImage___node___commentCount featuredImage___node___commentStatus featuredImage___node___comments___nodes featuredImage___node___contentTypeName featuredImage___node___databaseId featuredImage___node___date featuredImage___node___dateGmt featuredImage___node___description featuredImage___node___desiredSlug featuredImage___node___enclosure featuredImage___node___fileSize featuredImage___node___filename featuredImage___node___filesize featuredImage___node___gatsbyImage featuredImage___node___guid featuredImage___node___height featuredImage___node___id featuredImage___node___internal___content featuredImage___node___internal___contentDigest featuredImage___node___internal___description featuredImage___node___internal___fieldOwners featuredImage___node___internal___ignoreType featuredImage___node___internal___mediaType featuredImage___node___internal___owner featuredImage___node___internal___type featuredImage___node___isContentNode featuredImage___node___isTermNode featuredImage___node___link featuredImage___node___localFile___absolutePath featuredImage___node___localFile___accessTime featuredImage___node___localFile___atime featuredImage___node___localFile___atimeMs featuredImage___node___localFile___base featuredImage___node___localFile___birthTime featuredImage___node___localFile___birthtime featuredImage___node___localFile___birthtimeMs featuredImage___node___localFile___blksize featuredImage___node___localFile___blocks featuredImage___node___localFile___changeTime featuredImage___node___localFile___children featuredImage___node___localFile___childrenImageSharp featuredImage___node___localFile___ctime featuredImage___node___localFile___ctimeMs featuredImage___node___localFile___dev featuredImage___node___localFile___dir featuredImage___node___localFile___ext featuredImage___node___localFile___extension featuredImage___node___localFile___gid featuredImage___node___localFile___hash featuredImage___node___localFile___id featuredImage___node___localFile___ino featuredImage___node___localFile___mode featuredImage___node___localFile___modifiedTime featuredImage___node___localFile___mtime featuredImage___node___localFile___mtimeMs featuredImage___node___localFile___name featuredImage___node___localFile___nlink featuredImage___node___localFile___prettySize featuredImage___node___localFile___publicURL featuredImage___node___localFile___rdev featuredImage___node___localFile___relativeDirectory featuredImage___node___localFile___relativePath featuredImage___node___localFile___root featuredImage___node___localFile___size featuredImage___node___localFile___sourceInstanceName featuredImage___node___localFile___uid featuredImage___node___mediaDetails___file featuredImage___node___mediaDetails___height featuredImage___node___mediaDetails___sizes featuredImage___node___mediaDetails___width featuredImage___node___mediaItemUrl featuredImage___node___mediaType featuredImage___node___mimeType featuredImage___node___modified featuredImage___node___modifiedGmt featuredImage___node___nodeType featuredImage___node___parentDatabaseId featuredImage___node___parentId featuredImage___node___parent___children featuredImage___node___parent___id featuredImage___node___publicUrl featuredImage___node___remoteFile___absolutePath featuredImage___node___remoteFile___accessTime featuredImage___node___remoteFile___atime featuredImage___node___remoteFile___atimeMs featuredImage___node___remoteFile___base featuredImage___node___remoteFile___birthTime featuredImage___node___remoteFile___birthtime featuredImage___node___remoteFile___birthtimeMs featuredImage___node___remoteFile___blksize featuredImage___node___remoteFile___blocks featuredImage___node___remoteFile___changeTime featuredImage___node___remoteFile___children featuredImage___node___remoteFile___childrenImageSharp featuredImage___node___remoteFile___ctime featuredImage___node___remoteFile___ctimeMs featuredImage___node___remoteFile___dev featuredImage___node___remoteFile___dir featuredImage___node___remoteFile___ext featuredImage___node___remoteFile___extension featuredImage___node___remoteFile___gid featuredImage___node___remoteFile___hash featuredImage___node___remoteFile___id featuredImage___node___remoteFile___ino featuredImage___node___remoteFile___mode featuredImage___node___remoteFile___modifiedTime featuredImage___node___remoteFile___mtime featuredImage___node___remoteFile___mtimeMs featuredImage___node___remoteFile___name featuredImage___node___remoteFile___nlink featuredImage___node___remoteFile___prettySize featuredImage___node___remoteFile___publicURL featuredImage___node___remoteFile___rdev featuredImage___node___remoteFile___relativeDirectory featuredImage___node___remoteFile___relativePath featuredImage___node___remoteFile___root featuredImage___node___remoteFile___size featuredImage___node___remoteFile___sourceInstanceName featuredImage___node___remoteFile___uid featuredImage___node___resize___height featuredImage___node___resize___src featuredImage___node___resize___width featuredImage___node___sizes featuredImage___node___slug featuredImage___node___sourceUrl featuredImage___node___srcSet featuredImage___node___status featuredImage___node___template___templateName featuredImage___node___title featuredImage___node___uri featuredImage___node___width featuredImage___node___wpChildren___nodes guid id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isRevision isSticky isTermNode lastEditedBy___node___avatar___default lastEditedBy___node___avatar___extraAttr lastEditedBy___node___avatar___forceDefault lastEditedBy___node___avatar___foundAvatar lastEditedBy___node___avatar___height lastEditedBy___node___avatar___rating lastEditedBy___node___avatar___scheme lastEditedBy___node___avatar___size lastEditedBy___node___avatar___url lastEditedBy___node___avatar___width lastEditedBy___node___blockEditorPreviews___nodes lastEditedBy___node___capKey lastEditedBy___node___capabilities lastEditedBy___node___children lastEditedBy___node___children___children lastEditedBy___node___children___id lastEditedBy___node___comments___nodes lastEditedBy___node___databaseId lastEditedBy___node___description lastEditedBy___node___email lastEditedBy___node___extraCapabilities lastEditedBy___node___firstName lastEditedBy___node___id lastEditedBy___node___internal___content lastEditedBy___node___internal___contentDigest lastEditedBy___node___internal___description lastEditedBy___node___internal___fieldOwners lastEditedBy___node___internal___ignoreType lastEditedBy___node___internal___mediaType lastEditedBy___node___internal___owner lastEditedBy___node___internal___type lastEditedBy___node___isContentNode lastEditedBy___node___isTermNode lastEditedBy___node___lastName lastEditedBy___node___locale lastEditedBy___node___name lastEditedBy___node___nicename lastEditedBy___node___nickname lastEditedBy___node___nodeType lastEditedBy___node___pages___nodes lastEditedBy___node___parent___children lastEditedBy___node___parent___id lastEditedBy___node___posts___nodes lastEditedBy___node___registeredDate lastEditedBy___node___roles___nodes lastEditedBy___node___slug lastEditedBy___node___uri lastEditedBy___node___url lastEditedBy___node___username link modified modifiedGmt nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id pingStatus pinged postFormats___nodes postFormats___nodes___children postFormats___nodes___children___children postFormats___nodes___children___id postFormats___nodes___contentNodes___nodes postFormats___nodes___count postFormats___nodes___databaseId postFormats___nodes___description postFormats___nodes___id postFormats___nodes___internal___content postFormats___nodes___internal___contentDigest postFormats___nodes___internal___description postFormats___nodes___internal___fieldOwners postFormats___nodes___internal___ignoreType postFormats___nodes___internal___mediaType postFormats___nodes___internal___owner postFormats___nodes___internal___type postFormats___nodes___isContentNode postFormats___nodes___isTermNode postFormats___nodes___link postFormats___nodes___name postFormats___nodes___nodeType postFormats___nodes___parent___children postFormats___nodes___parent___id postFormats___nodes___posts___nodes postFormats___nodes___slug postFormats___nodes___taxonomyName postFormats___nodes___termGroupId postFormats___nodes___termTaxonomyId postFormats___nodes___uri previewBlocks previewBlocksJSON previewBlocks___attributesJSON previewBlocks___dynamicContent previewBlocks___innerBlocks previewBlocks___innerBlocks___attributesJSON previewBlocks___innerBlocks___dynamicContent previewBlocks___innerBlocks___innerBlocks previewBlocks___innerBlocks___innerBlocks___attributesJSON previewBlocks___innerBlocks___innerBlocks___dynamicContent previewBlocks___innerBlocks___innerBlocks___innerBlocks previewBlocks___innerBlocks___innerBlocks___isDynamic previewBlocks___innerBlocks___innerBlocks___name previewBlocks___innerBlocks___innerBlocks___order previewBlocks___innerBlocks___innerBlocks___originalContent previewBlocks___innerBlocks___innerBlocks___parentNodeDatabaseId previewBlocks___innerBlocks___innerBlocks___saveContent previewBlocks___innerBlocks___isDynamic previewBlocks___innerBlocks___name previewBlocks___innerBlocks___order previewBlocks___innerBlocks___originalContent previewBlocks___innerBlocks___parentNodeDatabaseId previewBlocks___innerBlocks___parentNode___id previewBlocks___innerBlocks___saveContent previewBlocks___isDynamic previewBlocks___name previewBlocks___order previewBlocks___originalContent previewBlocks___parentNodeDatabaseId previewBlocks___parentNode___id previewBlocks___saveContent slug status tags___nodes tags___nodes___children tags___nodes___children___children tags___nodes___children___id tags___nodes___contentNodes___nodes tags___nodes___count tags___nodes___databaseId tags___nodes___description tags___nodes___id tags___nodes___internal___content tags___nodes___internal___contentDigest tags___nodes___internal___description tags___nodes___internal___fieldOwners tags___nodes___internal___ignoreType tags___nodes___internal___mediaType tags___nodes___internal___owner tags___nodes___internal___type tags___nodes___isContentNode tags___nodes___isTermNode tags___nodes___link tags___nodes___name tags___nodes___nodeType tags___nodes___parent___children tags___nodes___parent___id tags___nodes___posts___nodes tags___nodes___slug tags___nodes___taxonomyName tags___nodes___termGroupId tags___nodes___termTaxonomyId tags___nodes___uri template___templateName terms___nodes terms___nodes___children terms___nodes___children___children terms___nodes___children___id terms___nodes___count terms___nodes___databaseId terms___nodes___description terms___nodes___id terms___nodes___internal___content terms___nodes___internal___contentDigest terms___nodes___internal___description terms___nodes___internal___fieldOwners terms___nodes___internal___ignoreType terms___nodes___internal___mediaType terms___nodes___internal___owner terms___nodes___internal___type terms___nodes___isContentNode terms___nodes___isTermNode terms___nodes___link terms___nodes___name terms___nodes___nodeType terms___nodes___parent___children terms___nodes___parent___id terms___nodes___slug terms___nodes___taxonomyName terms___nodes___termGroupId terms___nodes___termTaxonomyId terms___nodes___uri title toPing uri } input WpPostFilterInput { author: WpNodeWithAuthorToUserConnectionEdgeFilterInput authorDatabaseId: IntQueryOperatorInput authorId: IDQueryOperatorInput blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput categories: WpPostToCategoryConnectionFilterInput children: NodeFilterListInput commentCount: IntQueryOperatorInput commentStatus: StringQueryOperatorInput comments: WpPostToCommentConnectionFilterInput content: StringQueryOperatorInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput excerpt: StringQueryOperatorInput featuredImage: WpNodeWithFeaturedImageToMediaItemConnectionEdgeFilterInput featuredImageDatabaseId: IntQueryOperatorInput featuredImageId: IDQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isRevision: BooleanQueryOperatorInput isSticky: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput pingStatus: StringQueryOperatorInput pinged: StringQueryOperatorInput postFormats: WpPostToPostFormatConnectionFilterInput previewBlocks: WpBlockFilterListInput previewBlocksJSON: StringQueryOperatorInput slug: StringQueryOperatorInput status: StringQueryOperatorInput tags: WpPostToTagConnectionFilterInput template: WpContentTemplateFilterInput terms: WpPostToTermNodeConnectionFilterInput title: StringQueryOperatorInput toPing: StringQueryOperatorInput uri: StringQueryOperatorInput } input WpPostFilterListInput { elemMatch: WpPostFilterInput } """ The postFormat type """ type WpPostFormat implements Node & WpDatabaseIdentifier & WpNode & WpTermNode & WpUniformResourceIdentifiable { children: [Node!]! """ Connection between the postFormat type and the ContentNode type """ contentNodes: WpPostFormatToContentNodeConnection """ The number of objects connected to the object """ count: Int """ The unique identifier stored in the database """ databaseId: Int! """ The description of the object """ description: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The link to the term """ link: String """ The human friendly name of the object. """ name: String nodeType: String parent: Node """ Connection between the postFormat type and the post type """ posts: WpPostFormatToPostConnection """ An alphanumeric identifier for the object unique to its type. """ slug: String """ Connection between the postFormat type and the Taxonomy type """ taxonomy: WpPostFormatToTaxonomyConnectionEdge """ The name of the taxonomy that the object is associated with """ taxonomyName: String """ The ID of the term group that this term object belongs to """ termGroupId: Int """ The taxonomy ID that the object is associated with """ termTaxonomyId: Int """ The unique resource identifier path """ uri: String } type WpPostFormatConnection { distinct(field: WpPostFormatFieldsEnum!): [String!]! edges: [WpPostFormatEdge!]! group(field: WpPostFormatFieldsEnum!, limit: Int, skip: Int): [WpPostFormatGroupConnection!]! max(field: WpPostFormatFieldsEnum!): Float min(field: WpPostFormatFieldsEnum!): Float nodes: [WpPostFormat!]! pageInfo: PageInfo! sum(field: WpPostFormatFieldsEnum!): Float totalCount: Int! } type WpPostFormatEdge { next: WpPostFormat node: WpPostFormat! previous: WpPostFormat } enum WpPostFormatFieldsEnum { children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id contentNodes___nodes contentNodes___nodes___children contentNodes___nodes___children___children contentNodes___nodes___children___id contentNodes___nodes___contentTypeName contentNodes___nodes___databaseId contentNodes___nodes___date contentNodes___nodes___dateGmt contentNodes___nodes___desiredSlug contentNodes___nodes___enclosure contentNodes___nodes___guid contentNodes___nodes___id contentNodes___nodes___internal___content contentNodes___nodes___internal___contentDigest contentNodes___nodes___internal___description contentNodes___nodes___internal___fieldOwners contentNodes___nodes___internal___ignoreType contentNodes___nodes___internal___mediaType contentNodes___nodes___internal___owner contentNodes___nodes___internal___type contentNodes___nodes___isContentNode contentNodes___nodes___isTermNode contentNodes___nodes___link contentNodes___nodes___modified contentNodes___nodes___modifiedGmt contentNodes___nodes___nodeType contentNodes___nodes___parent___children contentNodes___nodes___parent___id contentNodes___nodes___slug contentNodes___nodes___status contentNodes___nodes___template___templateName contentNodes___nodes___uri count databaseId description id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isTermNode link name nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id posts___nodes posts___nodes___authorDatabaseId posts___nodes___authorId posts___nodes___blocks posts___nodes___blocksJSON posts___nodes___blocks___attributesJSON posts___nodes___blocks___dynamicContent posts___nodes___blocks___innerBlocks posts___nodes___blocks___isDynamic posts___nodes___blocks___name posts___nodes___blocks___order posts___nodes___blocks___originalContent posts___nodes___blocks___parentNodeDatabaseId posts___nodes___blocks___saveContent posts___nodes___categories___nodes posts___nodes___children posts___nodes___children___children posts___nodes___children___id posts___nodes___commentCount posts___nodes___commentStatus posts___nodes___comments___nodes posts___nodes___content posts___nodes___contentTypeName posts___nodes___databaseId posts___nodes___date posts___nodes___dateGmt posts___nodes___desiredSlug posts___nodes___enclosure posts___nodes___excerpt posts___nodes___featuredImageDatabaseId posts___nodes___featuredImageId posts___nodes___guid posts___nodes___id posts___nodes___internal___content posts___nodes___internal___contentDigest posts___nodes___internal___description posts___nodes___internal___fieldOwners posts___nodes___internal___ignoreType posts___nodes___internal___mediaType posts___nodes___internal___owner posts___nodes___internal___type posts___nodes___isContentNode posts___nodes___isRevision posts___nodes___isSticky posts___nodes___isTermNode posts___nodes___link posts___nodes___modified posts___nodes___modifiedGmt posts___nodes___nodeType posts___nodes___parent___children posts___nodes___parent___id posts___nodes___pingStatus posts___nodes___pinged posts___nodes___postFormats___nodes posts___nodes___previewBlocks posts___nodes___previewBlocksJSON posts___nodes___previewBlocks___attributesJSON posts___nodes___previewBlocks___dynamicContent posts___nodes___previewBlocks___innerBlocks posts___nodes___previewBlocks___isDynamic posts___nodes___previewBlocks___name posts___nodes___previewBlocks___order posts___nodes___previewBlocks___originalContent posts___nodes___previewBlocks___parentNodeDatabaseId posts___nodes___previewBlocks___saveContent posts___nodes___slug posts___nodes___status posts___nodes___tags___nodes posts___nodes___template___templateName posts___nodes___terms___nodes posts___nodes___title posts___nodes___toPing posts___nodes___uri slug taxonomyName taxonomy___node___archivePath taxonomy___node___children taxonomy___node___children___children taxonomy___node___children___id taxonomy___node___connectedContentTypes___nodes taxonomy___node___description taxonomy___node___graphqlPluralName taxonomy___node___graphqlSingleName taxonomy___node___hierarchical taxonomy___node___id taxonomy___node___internal___content taxonomy___node___internal___contentDigest taxonomy___node___internal___description taxonomy___node___internal___fieldOwners taxonomy___node___internal___ignoreType taxonomy___node___internal___mediaType taxonomy___node___internal___owner taxonomy___node___internal___type taxonomy___node___label taxonomy___node___name taxonomy___node___nodeType taxonomy___node___parent___children taxonomy___node___parent___id taxonomy___node___public taxonomy___node___restBase taxonomy___node___restControllerClass taxonomy___node___showCloud taxonomy___node___showInAdminColumn taxonomy___node___showInGraphql taxonomy___node___showInMenu taxonomy___node___showInNavMenus taxonomy___node___showInQuickEdit taxonomy___node___showInRest taxonomy___node___showUi termGroupId termTaxonomyId uri } input WpPostFormatFilterInput { children: NodeFilterListInput contentNodes: WpPostFormatToContentNodeConnectionFilterInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput link: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput posts: WpPostFormatToPostConnectionFilterInput slug: StringQueryOperatorInput taxonomy: WpPostFormatToTaxonomyConnectionEdgeFilterInput taxonomyName: StringQueryOperatorInput termGroupId: IntQueryOperatorInput termTaxonomyId: IntQueryOperatorInput uri: StringQueryOperatorInput } input WpPostFormatFilterListInput { elemMatch: WpPostFormatFilterInput } type WpPostFormatGroupConnection { distinct(field: WpPostFormatFieldsEnum!): [String!]! edges: [WpPostFormatEdge!]! field: String! fieldValue: String group(field: WpPostFormatFieldsEnum!, limit: Int, skip: Int): [WpPostFormatGroupConnection!]! max(field: WpPostFormatFieldsEnum!): Float min(field: WpPostFormatFieldsEnum!): Float nodes: [WpPostFormat!]! pageInfo: PageInfo! sum(field: WpPostFormatFieldsEnum!): Float totalCount: Int! } input WpPostFormatSortInput { fields: [WpPostFormatFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the postFormat type and the ContentNode type """ type WpPostFormatToContentNodeConnection { """ The nodes of the connection, without the edges """ nodes: [WpContentNode] } input WpPostFormatToContentNodeConnectionFilterInput { nodes: WpContentNodeFilterListInput } """ Connection between the postFormat type and the post type """ type WpPostFormatToPostConnection { """ The nodes of the connection, without the edges """ nodes: [WpPost] } input WpPostFormatToPostConnectionFilterInput { nodes: WpPostFilterListInput } """ Connection between the postFormat type and the Taxonomy type """ type WpPostFormatToTaxonomyConnectionEdge { """ The node of the connection, without the edges """ node: WpTaxonomy } input WpPostFormatToTaxonomyConnectionEdgeFilterInput { node: WpTaxonomyFilterInput } type WpPostGroupConnection { distinct(field: WpPostFieldsEnum!): [String!]! edges: [WpPostEdge!]! field: String! fieldValue: String group(field: WpPostFieldsEnum!, limit: Int, skip: Int): [WpPostGroupConnection!]! max(field: WpPostFieldsEnum!): Float min(field: WpPostFieldsEnum!): Float nodes: [WpPost!]! pageInfo: PageInfo! sum(field: WpPostFieldsEnum!): Float totalCount: Int! } input WpPostSortInput { fields: [WpPostFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the post type and the category type """ type WpPostToCategoryConnection { """ The nodes of the connection, without the edges """ nodes: [WpCategory] } input WpPostToCategoryConnectionFilterInput { nodes: WpCategoryFilterListInput } """ Connection between the post type and the Comment type """ type WpPostToCommentConnection { """ The nodes of the connection, without the edges """ nodes: [WpComment] } input WpPostToCommentConnectionFilterInput { nodes: WpCommentFilterListInput } """ Connection between the post type and the postFormat type """ type WpPostToPostFormatConnection { """ The nodes of the connection, without the edges """ nodes: [WpPostFormat] } input WpPostToPostFormatConnectionFilterInput { nodes: WpPostFormatFilterListInput } """ Connection between the post type and the tag type """ type WpPostToTagConnection { """ The nodes of the connection, without the edges """ nodes: [WpTag] } input WpPostToTagConnectionFilterInput { nodes: WpTagFilterListInput } """ Connection between the post type and the TermNode type """ type WpPostToTermNodeConnection { """ The nodes of the connection, without the edges """ nodes: [WpTermNode] } input WpPostToTermNodeConnectionFilterInput { nodes: WpTermNodeFilterListInput } """ Details for labels of the PostType """ type WpPostTypeLabelDetails { """ Default is ‘Add New’ for both hierarchical and non-hierarchical types. """ addNew: String """ Label for adding a new singular item. """ addNewItem: String """ Label to signify all items in a submenu link. """ allItems: String """ Label for archives in nav menus """ archives: String """ Label for the attributes meta box. """ attributes: String """ Label for editing a singular item. """ editItem: String """ Label for the Featured Image meta box title. """ featuredImage: String """ Label for the table views hidden heading. """ filterItemsList: String """ Label for the media frame button. """ insertIntoItem: String """ Label for the table hidden heading. """ itemsList: String """ Label for the table pagination hidden heading. """ itemsListNavigation: String """ Label for the menu name. """ menuName: String """ General name for the post type, usually plural. """ name: String """ Label for the new item page title. """ newItem: String """ Label used when no items are found. """ notFound: String """ Label used when no items are in the trash. """ notFoundInTrash: String """ Label used to prefix parents of hierarchical items. """ parentItemColon: String """ Label for removing the featured image. """ removeFeaturedImage: String """ Label for searching plural items. """ searchItems: String """ Label for setting the featured image. """ setFeaturedImage: String """ Name for one object of this post type. """ singularName: String """ Label for the media frame filter. """ uploadedToThisItem: String """ Label in the media frame for using a featured image. """ useFeaturedImage: String """ Label for viewing a singular item. """ viewItem: String """ Label for viewing post type archives. """ viewItems: String } input WpPostTypeLabelDetailsFilterInput { addNew: StringQueryOperatorInput addNewItem: StringQueryOperatorInput allItems: StringQueryOperatorInput archives: StringQueryOperatorInput attributes: StringQueryOperatorInput editItem: StringQueryOperatorInput featuredImage: StringQueryOperatorInput filterItemsList: StringQueryOperatorInput insertIntoItem: StringQueryOperatorInput itemsList: StringQueryOperatorInput itemsListNavigation: StringQueryOperatorInput menuName: StringQueryOperatorInput name: StringQueryOperatorInput newItem: StringQueryOperatorInput notFound: StringQueryOperatorInput notFoundInTrash: StringQueryOperatorInput parentItemColon: StringQueryOperatorInput removeFeaturedImage: StringQueryOperatorInput searchItems: StringQueryOperatorInput setFeaturedImage: StringQueryOperatorInput singularName: StringQueryOperatorInput uploadedToThisItem: StringQueryOperatorInput useFeaturedImage: StringQueryOperatorInput viewItem: StringQueryOperatorInput viewItems: StringQueryOperatorInput } """ The reading setting type """ type WpReadingSettings { """ Maximal angezeigte Beiträge. """ postsPerPage: Int } input WpReadingSettingsFilterInput { postsPerPage: IntQueryOperatorInput } """ real-media-library/gallery block """ type WpRealMediaLibraryGalleryBlock implements WpBlock { attributes: WpRealMediaLibraryGalleryBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpRealMediaLibraryGalleryBlockAttributes { align: String captions: Boolean! className: String columns: Float! fid: Float! imageCrop: Boolean! lastEditReload: Float! linkTo: String! lock: JSON } """ The ReusableBlock type """ type WpReusableBlock implements Node & WpBlockEditorContentNode & WpContentNode & WpDatabaseIdentifier & WpNode & WpNodeWithContentEditor & WpNodeWithRevisions & WpNodeWithTemplate & WpNodeWithTitle & WpUniformResourceIdentifiable { """ Gutenberg blocks """ blocks: [WpBlock!] """ Gutenberg blocks as json string """ blocksJSON: String children: [Node!]! """ The content of the post. """ content: String """ Connection between the ContentNode type and the ContentType type """ contentType: WpContentNodeToContentTypeConnectionEdge """ The name of the Content Type the node belongs to """ contentTypeName: String! """ The unique identifier stored in the database """ databaseId: Int! """ Post publishing date. """ date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The publishing date set in GMT. """ dateGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The desired slug of the post """ desiredSlug: String """ The RSS enclosure for the object """ enclosure: String """ The global unique identifier for this post. This currently matches the value stored in WP_Post->guid and the guid column in the "post_objects" database table. """ guid: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ True if the node is a revision of another node """ isRevision: Boolean """ Whether the node is a Term """ isTermNode: Boolean! """ The user that most recently edited the node """ lastEditedBy: WpContentNodeToEditLastConnectionEdge """ The permalink of the post """ link: String """ The local modified time for a post. If a post was recently updated the modified field will change to match the corresponding time. """ modified( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date """ The GMT modified time for a post. If a post was recently updated the modified field will change to match the corresponding time in GMT. """ modifiedGmt( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date nodeType: String parent: Node """ Previewed gutenberg blocks """ previewBlocks: [WpBlock!] """ Previewed Gutenberg blocks as json string """ previewBlocksJSON: String """ The uri slug for the post. This is equivalent to the WP_Post->post_name field and the post_name column in the database for the "post_objects" table. """ slug: String """ The current status of the object """ status: String """ The template assigned to the node """ template: WpContentTemplate """ The title of the post. This is currently just the raw title. An amendment to support rendered title needs to be made. """ title: String """ The unique resource identifier path """ uri: String } type WpReusableBlockConnection { distinct(field: WpReusableBlockFieldsEnum!): [String!]! edges: [WpReusableBlockEdge!]! group(field: WpReusableBlockFieldsEnum!, limit: Int, skip: Int): [WpReusableBlockGroupConnection!]! max(field: WpReusableBlockFieldsEnum!): Float min(field: WpReusableBlockFieldsEnum!): Float nodes: [WpReusableBlock!]! pageInfo: PageInfo! sum(field: WpReusableBlockFieldsEnum!): Float totalCount: Int! } type WpReusableBlockEdge { next: WpReusableBlock node: WpReusableBlock! previous: WpReusableBlock } enum WpReusableBlockFieldsEnum { blocks blocksJSON blocks___attributesJSON blocks___dynamicContent blocks___innerBlocks blocks___innerBlocks___attributesJSON blocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___attributesJSON blocks___innerBlocks___innerBlocks___dynamicContent blocks___innerBlocks___innerBlocks___innerBlocks blocks___innerBlocks___innerBlocks___isDynamic blocks___innerBlocks___innerBlocks___name blocks___innerBlocks___innerBlocks___order blocks___innerBlocks___innerBlocks___originalContent blocks___innerBlocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___innerBlocks___saveContent blocks___innerBlocks___isDynamic blocks___innerBlocks___name blocks___innerBlocks___order blocks___innerBlocks___originalContent blocks___innerBlocks___parentNodeDatabaseId blocks___innerBlocks___parentNode___id blocks___innerBlocks___saveContent blocks___isDynamic blocks___name blocks___order blocks___originalContent blocks___parentNodeDatabaseId blocks___parentNode___id blocks___saveContent children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id content contentTypeName contentType___node___archivePath contentType___node___canExport contentType___node___children contentType___node___children___children contentType___node___children___id contentType___node___connectedTaxonomies___nodes contentType___node___contentNodes___nodes contentType___node___deleteWithUser contentType___node___description contentType___node___excludeFromSearch contentType___node___graphqlPluralName contentType___node___graphqlSingleName contentType___node___hasArchive contentType___node___hierarchical contentType___node___id contentType___node___internal___content contentType___node___internal___contentDigest contentType___node___internal___description contentType___node___internal___fieldOwners contentType___node___internal___ignoreType contentType___node___internal___mediaType contentType___node___internal___owner contentType___node___internal___type contentType___node___isContentNode contentType___node___isFrontPage contentType___node___isPostsPage contentType___node___isTermNode contentType___node___label contentType___node___labels___addNew contentType___node___labels___addNewItem contentType___node___labels___allItems contentType___node___labels___archives contentType___node___labels___attributes contentType___node___labels___editItem contentType___node___labels___featuredImage contentType___node___labels___filterItemsList contentType___node___labels___insertIntoItem contentType___node___labels___itemsList contentType___node___labels___itemsListNavigation contentType___node___labels___menuName contentType___node___labels___name contentType___node___labels___newItem contentType___node___labels___notFound contentType___node___labels___notFoundInTrash contentType___node___labels___parentItemColon contentType___node___labels___removeFeaturedImage contentType___node___labels___searchItems contentType___node___labels___setFeaturedImage contentType___node___labels___singularName contentType___node___labels___uploadedToThisItem contentType___node___labels___useFeaturedImage contentType___node___labels___viewItem contentType___node___labels___viewItems contentType___node___menuIcon contentType___node___menuPosition contentType___node___name contentType___node___nodeType contentType___node___parent___children contentType___node___parent___id contentType___node___public contentType___node___publiclyQueryable contentType___node___restBase contentType___node___restControllerClass contentType___node___showInAdminBar contentType___node___showInGraphql contentType___node___showInMenu contentType___node___showInNavMenus contentType___node___showInRest contentType___node___showUi contentType___node___uri databaseId date dateGmt desiredSlug enclosure guid id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isRevision isTermNode lastEditedBy___node___avatar___default lastEditedBy___node___avatar___extraAttr lastEditedBy___node___avatar___forceDefault lastEditedBy___node___avatar___foundAvatar lastEditedBy___node___avatar___height lastEditedBy___node___avatar___rating lastEditedBy___node___avatar___scheme lastEditedBy___node___avatar___size lastEditedBy___node___avatar___url lastEditedBy___node___avatar___width lastEditedBy___node___blockEditorPreviews___nodes lastEditedBy___node___capKey lastEditedBy___node___capabilities lastEditedBy___node___children lastEditedBy___node___children___children lastEditedBy___node___children___id lastEditedBy___node___comments___nodes lastEditedBy___node___databaseId lastEditedBy___node___description lastEditedBy___node___email lastEditedBy___node___extraCapabilities lastEditedBy___node___firstName lastEditedBy___node___id lastEditedBy___node___internal___content lastEditedBy___node___internal___contentDigest lastEditedBy___node___internal___description lastEditedBy___node___internal___fieldOwners lastEditedBy___node___internal___ignoreType lastEditedBy___node___internal___mediaType lastEditedBy___node___internal___owner lastEditedBy___node___internal___type lastEditedBy___node___isContentNode lastEditedBy___node___isTermNode lastEditedBy___node___lastName lastEditedBy___node___locale lastEditedBy___node___name lastEditedBy___node___nicename lastEditedBy___node___nickname lastEditedBy___node___nodeType lastEditedBy___node___pages___nodes lastEditedBy___node___parent___children lastEditedBy___node___parent___id lastEditedBy___node___posts___nodes lastEditedBy___node___registeredDate lastEditedBy___node___roles___nodes lastEditedBy___node___slug lastEditedBy___node___uri lastEditedBy___node___url lastEditedBy___node___username link modified modifiedGmt nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id previewBlocks previewBlocksJSON previewBlocks___attributesJSON previewBlocks___dynamicContent previewBlocks___innerBlocks previewBlocks___innerBlocks___attributesJSON previewBlocks___innerBlocks___dynamicContent previewBlocks___innerBlocks___innerBlocks previewBlocks___innerBlocks___innerBlocks___attributesJSON previewBlocks___innerBlocks___innerBlocks___dynamicContent previewBlocks___innerBlocks___innerBlocks___innerBlocks previewBlocks___innerBlocks___innerBlocks___isDynamic previewBlocks___innerBlocks___innerBlocks___name previewBlocks___innerBlocks___innerBlocks___order previewBlocks___innerBlocks___innerBlocks___originalContent previewBlocks___innerBlocks___innerBlocks___parentNodeDatabaseId previewBlocks___innerBlocks___innerBlocks___saveContent previewBlocks___innerBlocks___isDynamic previewBlocks___innerBlocks___name previewBlocks___innerBlocks___order previewBlocks___innerBlocks___originalContent previewBlocks___innerBlocks___parentNodeDatabaseId previewBlocks___innerBlocks___parentNode___id previewBlocks___innerBlocks___saveContent previewBlocks___isDynamic previewBlocks___name previewBlocks___order previewBlocks___originalContent previewBlocks___parentNodeDatabaseId previewBlocks___parentNode___id previewBlocks___saveContent slug status template___templateName title uri } input WpReusableBlockFilterInput { blocks: WpBlockFilterListInput blocksJSON: StringQueryOperatorInput children: NodeFilterListInput content: StringQueryOperatorInput contentType: WpContentNodeToContentTypeConnectionEdgeFilterInput contentTypeName: StringQueryOperatorInput databaseId: IntQueryOperatorInput date: DateQueryOperatorInput dateGmt: DateQueryOperatorInput desiredSlug: StringQueryOperatorInput enclosure: StringQueryOperatorInput guid: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isRevision: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastEditedBy: WpContentNodeToEditLastConnectionEdgeFilterInput link: StringQueryOperatorInput modified: DateQueryOperatorInput modifiedGmt: DateQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput previewBlocks: WpBlockFilterListInput previewBlocksJSON: StringQueryOperatorInput slug: StringQueryOperatorInput status: StringQueryOperatorInput template: WpContentTemplateFilterInput title: StringQueryOperatorInput uri: StringQueryOperatorInput } type WpReusableBlockGroupConnection { distinct(field: WpReusableBlockFieldsEnum!): [String!]! edges: [WpReusableBlockEdge!]! field: String! fieldValue: String group(field: WpReusableBlockFieldsEnum!, limit: Int, skip: Int): [WpReusableBlockGroupConnection!]! max(field: WpReusableBlockFieldsEnum!): Float min(field: WpReusableBlockFieldsEnum!): Float nodes: [WpReusableBlock!]! pageInfo: PageInfo! sum(field: WpReusableBlockFieldsEnum!): Float totalCount: Int! } input WpReusableBlockSortInput { fields: [WpReusableBlockFieldsEnum] order: [SortOrderEnum] = [ASC] } """ All of the registered settings """ type WpSettings { """ Settings of the the string Settings Group """ discussionSettingsDefaultCommentStatus: String """ Settings of the the string Settings Group """ discussionSettingsDefaultPingStatus: String """ Settings of the the string Settings Group """ generalSettingsDateFormat: String """ Settings of the the string Settings Group """ generalSettingsDescription: String """ Settings of the the string Settings Group """ generalSettingsEmail: String """ Settings of the the string Settings Group """ generalSettingsLanguage: String """ Settings of the the integer Settings Group """ generalSettingsStartOfWeek: Int """ Settings of the the string Settings Group """ generalSettingsTimeFormat: String """ Settings of the the string Settings Group """ generalSettingsTimezone: String """ Settings of the the string Settings Group """ generalSettingsTitle: String """ Settings of the the string Settings Group """ generalSettingsUrl: String """ Settings of the the integer Settings Group """ readingSettingsPostsPerPage: Int """ Settings of the the integer Settings Group """ writingSettingsDefaultCategory: Int """ Settings of the the string Settings Group """ writingSettingsDefaultPostFormat: String """ Settings of the the boolean Settings Group """ writingSettingsUseSmilies: Boolean } input WpSettingsFilterInput { discussionSettingsDefaultCommentStatus: StringQueryOperatorInput discussionSettingsDefaultPingStatus: StringQueryOperatorInput generalSettingsDateFormat: StringQueryOperatorInput generalSettingsDescription: StringQueryOperatorInput generalSettingsEmail: StringQueryOperatorInput generalSettingsLanguage: StringQueryOperatorInput generalSettingsStartOfWeek: IntQueryOperatorInput generalSettingsTimeFormat: StringQueryOperatorInput generalSettingsTimezone: StringQueryOperatorInput generalSettingsTitle: StringQueryOperatorInput generalSettingsUrl: StringQueryOperatorInput readingSettingsPostsPerPage: IntQueryOperatorInput writingSettingsDefaultCategory: IntQueryOperatorInput writingSettingsDefaultPostFormat: StringQueryOperatorInput writingSettingsUseSmilies: BooleanQueryOperatorInput } input WpSortInput { fields: [WpFieldsEnum] order: [SortOrderEnum] = [ASC] } """ tadv/classic-paragraph block """ type WpTadvClassicParagraphBlock implements WpBlock { attributes: WpTadvClassicParagraphBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpTadvClassicParagraphBlockAttributes { align: String content: String lock: JSON } """ The tag type """ type WpTag implements Node & WpDatabaseIdentifier & WpMenuItemLinkable & WpNode & WpTermNode & WpUniformResourceIdentifiable { children: [Node!]! """ Connection between the tag type and the ContentNode type """ contentNodes: WpTagToContentNodeConnection """ The number of objects connected to the object """ count: Int """ The unique resource identifier path """ databaseId: Int! """ The description of the object """ description: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The link to the term """ link: String """ The human friendly name of the object. """ name: String nodeType: String parent: Node """ Connection between the tag type and the post type """ posts: WpTagToPostConnection """ An alphanumeric identifier for the object unique to its type. """ slug: String """ Connection between the tag type and the Taxonomy type """ taxonomy: WpTagToTaxonomyConnectionEdge """ The name of the taxonomy that the object is associated with """ taxonomyName: String """ The ID of the term group that this term object belongs to """ termGroupId: Int """ The taxonomy ID that the object is associated with """ termTaxonomyId: Int """ The unique resource identifier path """ uri: String } type WpTagConnection { distinct(field: WpTagFieldsEnum!): [String!]! edges: [WpTagEdge!]! group(field: WpTagFieldsEnum!, limit: Int, skip: Int): [WpTagGroupConnection!]! max(field: WpTagFieldsEnum!): Float min(field: WpTagFieldsEnum!): Float nodes: [WpTag!]! pageInfo: PageInfo! sum(field: WpTagFieldsEnum!): Float totalCount: Int! } type WpTagEdge { next: WpTag node: WpTag! previous: WpTag } enum WpTagFieldsEnum { children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id contentNodes___nodes contentNodes___nodes___children contentNodes___nodes___children___children contentNodes___nodes___children___id contentNodes___nodes___contentTypeName contentNodes___nodes___databaseId contentNodes___nodes___date contentNodes___nodes___dateGmt contentNodes___nodes___desiredSlug contentNodes___nodes___enclosure contentNodes___nodes___guid contentNodes___nodes___id contentNodes___nodes___internal___content contentNodes___nodes___internal___contentDigest contentNodes___nodes___internal___description contentNodes___nodes___internal___fieldOwners contentNodes___nodes___internal___ignoreType contentNodes___nodes___internal___mediaType contentNodes___nodes___internal___owner contentNodes___nodes___internal___type contentNodes___nodes___isContentNode contentNodes___nodes___isTermNode contentNodes___nodes___link contentNodes___nodes___modified contentNodes___nodes___modifiedGmt contentNodes___nodes___nodeType contentNodes___nodes___parent___children contentNodes___nodes___parent___id contentNodes___nodes___slug contentNodes___nodes___status contentNodes___nodes___template___templateName contentNodes___nodes___uri count databaseId description id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isTermNode link name nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id posts___nodes posts___nodes___authorDatabaseId posts___nodes___authorId posts___nodes___blocks posts___nodes___blocksJSON posts___nodes___blocks___attributesJSON posts___nodes___blocks___dynamicContent posts___nodes___blocks___innerBlocks posts___nodes___blocks___isDynamic posts___nodes___blocks___name posts___nodes___blocks___order posts___nodes___blocks___originalContent posts___nodes___blocks___parentNodeDatabaseId posts___nodes___blocks___saveContent posts___nodes___categories___nodes posts___nodes___children posts___nodes___children___children posts___nodes___children___id posts___nodes___commentCount posts___nodes___commentStatus posts___nodes___comments___nodes posts___nodes___content posts___nodes___contentTypeName posts___nodes___databaseId posts___nodes___date posts___nodes___dateGmt posts___nodes___desiredSlug posts___nodes___enclosure posts___nodes___excerpt posts___nodes___featuredImageDatabaseId posts___nodes___featuredImageId posts___nodes___guid posts___nodes___id posts___nodes___internal___content posts___nodes___internal___contentDigest posts___nodes___internal___description posts___nodes___internal___fieldOwners posts___nodes___internal___ignoreType posts___nodes___internal___mediaType posts___nodes___internal___owner posts___nodes___internal___type posts___nodes___isContentNode posts___nodes___isRevision posts___nodes___isSticky posts___nodes___isTermNode posts___nodes___link posts___nodes___modified posts___nodes___modifiedGmt posts___nodes___nodeType posts___nodes___parent___children posts___nodes___parent___id posts___nodes___pingStatus posts___nodes___pinged posts___nodes___postFormats___nodes posts___nodes___previewBlocks posts___nodes___previewBlocksJSON posts___nodes___previewBlocks___attributesJSON posts___nodes___previewBlocks___dynamicContent posts___nodes___previewBlocks___innerBlocks posts___nodes___previewBlocks___isDynamic posts___nodes___previewBlocks___name posts___nodes___previewBlocks___order posts___nodes___previewBlocks___originalContent posts___nodes___previewBlocks___parentNodeDatabaseId posts___nodes___previewBlocks___saveContent posts___nodes___slug posts___nodes___status posts___nodes___tags___nodes posts___nodes___template___templateName posts___nodes___terms___nodes posts___nodes___title posts___nodes___toPing posts___nodes___uri slug taxonomyName taxonomy___node___archivePath taxonomy___node___children taxonomy___node___children___children taxonomy___node___children___id taxonomy___node___connectedContentTypes___nodes taxonomy___node___description taxonomy___node___graphqlPluralName taxonomy___node___graphqlSingleName taxonomy___node___hierarchical taxonomy___node___id taxonomy___node___internal___content taxonomy___node___internal___contentDigest taxonomy___node___internal___description taxonomy___node___internal___fieldOwners taxonomy___node___internal___ignoreType taxonomy___node___internal___mediaType taxonomy___node___internal___owner taxonomy___node___internal___type taxonomy___node___label taxonomy___node___name taxonomy___node___nodeType taxonomy___node___parent___children taxonomy___node___parent___id taxonomy___node___public taxonomy___node___restBase taxonomy___node___restControllerClass taxonomy___node___showCloud taxonomy___node___showInAdminColumn taxonomy___node___showInGraphql taxonomy___node___showInMenu taxonomy___node___showInNavMenus taxonomy___node___showInQuickEdit taxonomy___node___showInRest taxonomy___node___showUi termGroupId termTaxonomyId uri } input WpTagFilterInput { children: NodeFilterListInput contentNodes: WpTagToContentNodeConnectionFilterInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput link: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput posts: WpTagToPostConnectionFilterInput slug: StringQueryOperatorInput taxonomy: WpTagToTaxonomyConnectionEdgeFilterInput taxonomyName: StringQueryOperatorInput termGroupId: IntQueryOperatorInput termTaxonomyId: IntQueryOperatorInput uri: StringQueryOperatorInput } input WpTagFilterListInput { elemMatch: WpTagFilterInput } type WpTagGroupConnection { distinct(field: WpTagFieldsEnum!): [String!]! edges: [WpTagEdge!]! field: String! fieldValue: String group(field: WpTagFieldsEnum!, limit: Int, skip: Int): [WpTagGroupConnection!]! max(field: WpTagFieldsEnum!): Float min(field: WpTagFieldsEnum!): Float nodes: [WpTag!]! pageInfo: PageInfo! sum(field: WpTagFieldsEnum!): Float totalCount: Int! } input WpTagSortInput { fields: [WpTagFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the tag type and the ContentNode type """ type WpTagToContentNodeConnection { """ The nodes of the connection, without the edges """ nodes: [WpContentNode] } input WpTagToContentNodeConnectionFilterInput { nodes: WpContentNodeFilterListInput } """ Connection between the tag type and the post type """ type WpTagToPostConnection { """ The nodes of the connection, without the edges """ nodes: [WpPost] } input WpTagToPostConnectionFilterInput { nodes: WpPostFilterListInput } """ Connection between the tag type and the Taxonomy type """ type WpTagToTaxonomyConnectionEdge { """ The node of the connection, without the edges """ node: WpTaxonomy } input WpTagToTaxonomyConnectionEdgeFilterInput { node: WpTaxonomyFilterInput } """ A taxonomy object """ type WpTaxonomy implements Node & WpNode { """ The url path of the first page of the archive page for this content type. """ archivePath: String children: [Node!]! """ List of Content Types associated with the Taxonomy """ connectedContentTypes: WpTaxonomyToContentTypeConnection """ Description of the taxonomy. This field is equivalent to WP_Taxonomy->description """ description: String """ The plural name of the post type within the GraphQL Schema. """ graphqlPluralName: String """ The singular name of the post type within the GraphQL Schema. """ graphqlSingleName: String """ Whether the taxonomy is hierarchical """ hierarchical: Boolean id: ID! internal: Internal! """ Name of the taxonomy shown in the menu. Usually plural. """ label: String """ The display name of the taxonomy. This field is equivalent to WP_Taxonomy->label """ name: String nodeType: String parent: Node """ Whether the taxonomy is publicly queryable """ public: Boolean """ Name of content type to diplay in REST API "wp/v2" namespace. """ restBase: String """ The REST Controller class assigned to handling this content type. """ restControllerClass: String """ Whether to show the taxonomy as part of a tag cloud widget. This field is equivalent to WP_Taxonomy->show_tagcloud """ showCloud: Boolean """ Whether to display a column for the taxonomy on its post type listing screens. """ showInAdminColumn: Boolean """ Whether to add the post type to the GraphQL Schema. """ showInGraphql: Boolean """ Whether to show the taxonomy in the admin menu """ showInMenu: Boolean """ Whether the taxonomy is available for selection in navigation menus. """ showInNavMenus: Boolean """ Whether to show the taxonomy in the quick/bulk edit panel. """ showInQuickEdit: Boolean """ Whether to add the post type route in the REST API "wp/v2" namespace. """ showInRest: Boolean """ Whether to generate and allow a UI for managing terms in this taxonomy in the admin """ showUi: Boolean } type WpTaxonomyConnection { distinct(field: WpTaxonomyFieldsEnum!): [String!]! edges: [WpTaxonomyEdge!]! group(field: WpTaxonomyFieldsEnum!, limit: Int, skip: Int): [WpTaxonomyGroupConnection!]! max(field: WpTaxonomyFieldsEnum!): Float min(field: WpTaxonomyFieldsEnum!): Float nodes: [WpTaxonomy!]! pageInfo: PageInfo! sum(field: WpTaxonomyFieldsEnum!): Float totalCount: Int! } type WpTaxonomyEdge { next: WpTaxonomy node: WpTaxonomy! previous: WpTaxonomy } enum WpTaxonomyFieldsEnum { archivePath children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id connectedContentTypes___nodes connectedContentTypes___nodes___archivePath connectedContentTypes___nodes___canExport connectedContentTypes___nodes___children connectedContentTypes___nodes___children___children connectedContentTypes___nodes___children___id connectedContentTypes___nodes___connectedTaxonomies___nodes connectedContentTypes___nodes___contentNodes___nodes connectedContentTypes___nodes___deleteWithUser connectedContentTypes___nodes___description connectedContentTypes___nodes___excludeFromSearch connectedContentTypes___nodes___graphqlPluralName connectedContentTypes___nodes___graphqlSingleName connectedContentTypes___nodes___hasArchive connectedContentTypes___nodes___hierarchical connectedContentTypes___nodes___id connectedContentTypes___nodes___internal___content connectedContentTypes___nodes___internal___contentDigest connectedContentTypes___nodes___internal___description connectedContentTypes___nodes___internal___fieldOwners connectedContentTypes___nodes___internal___ignoreType connectedContentTypes___nodes___internal___mediaType connectedContentTypes___nodes___internal___owner connectedContentTypes___nodes___internal___type connectedContentTypes___nodes___isContentNode connectedContentTypes___nodes___isFrontPage connectedContentTypes___nodes___isPostsPage connectedContentTypes___nodes___isTermNode connectedContentTypes___nodes___label connectedContentTypes___nodes___labels___addNew connectedContentTypes___nodes___labels___addNewItem connectedContentTypes___nodes___labels___allItems connectedContentTypes___nodes___labels___archives connectedContentTypes___nodes___labels___attributes connectedContentTypes___nodes___labels___editItem connectedContentTypes___nodes___labels___featuredImage connectedContentTypes___nodes___labels___filterItemsList connectedContentTypes___nodes___labels___insertIntoItem connectedContentTypes___nodes___labels___itemsList connectedContentTypes___nodes___labels___itemsListNavigation connectedContentTypes___nodes___labels___menuName connectedContentTypes___nodes___labels___name connectedContentTypes___nodes___labels___newItem connectedContentTypes___nodes___labels___notFound connectedContentTypes___nodes___labels___notFoundInTrash connectedContentTypes___nodes___labels___parentItemColon connectedContentTypes___nodes___labels___removeFeaturedImage connectedContentTypes___nodes___labels___searchItems connectedContentTypes___nodes___labels___setFeaturedImage connectedContentTypes___nodes___labels___singularName connectedContentTypes___nodes___labels___uploadedToThisItem connectedContentTypes___nodes___labels___useFeaturedImage connectedContentTypes___nodes___labels___viewItem connectedContentTypes___nodes___labels___viewItems connectedContentTypes___nodes___menuIcon connectedContentTypes___nodes___menuPosition connectedContentTypes___nodes___name connectedContentTypes___nodes___nodeType connectedContentTypes___nodes___parent___children connectedContentTypes___nodes___parent___id connectedContentTypes___nodes___public connectedContentTypes___nodes___publiclyQueryable connectedContentTypes___nodes___restBase connectedContentTypes___nodes___restControllerClass connectedContentTypes___nodes___showInAdminBar connectedContentTypes___nodes___showInGraphql connectedContentTypes___nodes___showInMenu connectedContentTypes___nodes___showInNavMenus connectedContentTypes___nodes___showInRest connectedContentTypes___nodes___showUi connectedContentTypes___nodes___uri description graphqlPluralName graphqlSingleName hierarchical id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type label name nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id public restBase restControllerClass showCloud showInAdminColumn showInGraphql showInMenu showInNavMenus showInQuickEdit showInRest showUi } input WpTaxonomyFilterInput { archivePath: StringQueryOperatorInput children: NodeFilterListInput connectedContentTypes: WpTaxonomyToContentTypeConnectionFilterInput description: StringQueryOperatorInput graphqlPluralName: StringQueryOperatorInput graphqlSingleName: StringQueryOperatorInput hierarchical: BooleanQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput label: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput public: BooleanQueryOperatorInput restBase: StringQueryOperatorInput restControllerClass: StringQueryOperatorInput showCloud: BooleanQueryOperatorInput showInAdminColumn: BooleanQueryOperatorInput showInGraphql: BooleanQueryOperatorInput showInMenu: BooleanQueryOperatorInput showInNavMenus: BooleanQueryOperatorInput showInQuickEdit: BooleanQueryOperatorInput showInRest: BooleanQueryOperatorInput showUi: BooleanQueryOperatorInput } input WpTaxonomyFilterListInput { elemMatch: WpTaxonomyFilterInput } type WpTaxonomyGroupConnection { distinct(field: WpTaxonomyFieldsEnum!): [String!]! edges: [WpTaxonomyEdge!]! field: String! fieldValue: String group(field: WpTaxonomyFieldsEnum!, limit: Int, skip: Int): [WpTaxonomyGroupConnection!]! max(field: WpTaxonomyFieldsEnum!): Float min(field: WpTaxonomyFieldsEnum!): Float nodes: [WpTaxonomy!]! pageInfo: PageInfo! sum(field: WpTaxonomyFieldsEnum!): Float totalCount: Int! } input WpTaxonomySortInput { fields: [WpTaxonomyFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the Taxonomy type and the ContentType type """ type WpTaxonomyToContentTypeConnection { """ The nodes of the connection, without the edges """ nodes: [WpContentType] } input WpTaxonomyToContentTypeConnectionFilterInput { nodes: WpContentTypeFilterListInput } interface WpTermNode implements Node { children: [Node!]! """ The number of objects connected to the object """ count: Int """ Identifies the primary key from the database. """ databaseId: Int! """ The description of the object """ description: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The link to the term """ link: String """ The human friendly name of the object. """ name: String nodeType: String parent: Node """ An alphanumeric identifier for the object unique to its type. """ slug: String """ The name of the taxonomy that the object is associated with """ taxonomyName: String """ The ID of the term group that this term object belongs to """ termGroupId: Int """ The taxonomy ID that the object is associated with """ termTaxonomyId: Int """ The unique resource identifier path """ uri: String } type WpTermNodeConnection { distinct(field: WpTermNodeFieldsEnum!): [String!]! edges: [WpTermNodeEdge!]! group(field: WpTermNodeFieldsEnum!, limit: Int, skip: Int): [WpTermNodeGroupConnection!]! max(field: WpTermNodeFieldsEnum!): Float min(field: WpTermNodeFieldsEnum!): Float nodes: [WpTermNode!]! pageInfo: PageInfo! sum(field: WpTermNodeFieldsEnum!): Float totalCount: Int! } type WpTermNodeEdge { next: WpTermNode node: WpTermNode! previous: WpTermNode } enum WpTermNodeFieldsEnum { children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id count databaseId description id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isTermNode link name nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id slug taxonomyName termGroupId termTaxonomyId uri } input WpTermNodeFilterInput { children: NodeFilterListInput count: IntQueryOperatorInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput link: StringQueryOperatorInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput slug: StringQueryOperatorInput taxonomyName: StringQueryOperatorInput termGroupId: IntQueryOperatorInput termTaxonomyId: IntQueryOperatorInput uri: StringQueryOperatorInput } input WpTermNodeFilterListInput { elemMatch: WpTermNodeFilterInput } type WpTermNodeGroupConnection { distinct(field: WpTermNodeFieldsEnum!): [String!]! edges: [WpTermNodeEdge!]! field: String! fieldValue: String group(field: WpTermNodeFieldsEnum!, limit: Int, skip: Int): [WpTermNodeGroupConnection!]! max(field: WpTermNodeFieldsEnum!): Float min(field: WpTermNodeFieldsEnum!): Float nodes: [WpTermNode!]! pageInfo: PageInfo! sum(field: WpTermNodeFieldsEnum!): Float totalCount: Int! } input WpTermNodeSortInput { fields: [WpTermNodeFieldsEnum] order: [SortOrderEnum] = [ASC] } """ tribe/events-list block """ type WpTribeEventsListBlock implements WpBlock { attributes: WpTribeEventsListBlockAttributes """ Block attributes, JSON encoded """ attributesJSON: String """ Server side rendered content. """ dynamicContent: String """ Gutenberg blocks """ innerBlocks: [WpBlock!] """ Is block rendered server side. """ isDynamic: Boolean! """ Name of the block. """ name: String! order: Int! """ Original HTML content. """ originalContent: String """ Parent post. """ parentNode: WpNode! """ Parent post id. """ parentNodeDatabaseId: Int! """ Original HTML content with inner blocks. """ saveContent: String } type WpTribeEventsListBlockAttributes { className: String lock: JSON } interface WpUniformResourceIdentifiable { """ The unique resource identifier path """ id: ID! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ The unique resource identifier path """ uri: String } """ A User object """ type WpUser implements Node & WpCommenter & WpDatabaseIdentifier & WpNode & WpUniformResourceIdentifiable { """ Avatar object for user. The avatar object can be retrieved in different sizes by specifying the size argument. """ avatar: WpAvatar """ Connection between the User type and the BlockEditorPreview type """ blockEditorPreviews: WpUserToBlockEditorPreviewConnection """ User metadata option name. Usually it will be "wp_capabilities". """ capKey: String """ A list of capabilities (permissions) granted to the user """ capabilities: [String] children: [Node!]! """ Connection between the User type and the Comment type """ comments: WpUserToCommentConnection """ Identifies the primary key from the database. """ databaseId: Int! """ Description of the user. """ description: String """ Email address of the user. This is equivalent to the WP_User->user_email property. """ email: String """ A complete list of capabilities including capabilities inherited from a role. This is equivalent to the array keys of WP_User->allcaps. """ extraCapabilities: [String] """ First name of the user. This is equivalent to the WP_User->user_first_name property. """ firstName: String id: ID! internal: Internal! """ Whether the node is a Content Node """ isContentNode: Boolean! """ Whether the node is a Term """ isTermNode: Boolean! """ Last name of the user. This is equivalent to the WP_User->user_last_name property. """ lastName: String """ The preferred language locale set for the user. Value derived from get_user_locale(). """ locale: String """ Display name of the user. This is equivalent to the WP_User->dispaly_name property. """ name: String """ The nicename for the user. This field is equivalent to WP_User->user_nicename """ nicename: String """ Nickname of the user. """ nickname: String nodeType: String """ Connection between the User type and the page type """ pages: WpUserToPageConnection parent: Node """ Connection between the User type and the post type """ posts: WpUserToPostConnection """ The date the user registered or was created. The field follows a full ISO8601 date string format. """ registeredDate: String """ Connection between the User type and the UserRole type """ roles: WpUserToUserRoleConnection """ The slug for the user. This field is equivalent to WP_User->user_nicename """ slug: String """ The unique resource identifier path """ uri: String """ A website url that is associated with the user. """ url: String """ Username for the user. This field is equivalent to WP_User->user_login. """ username: String } type WpUserConnection { distinct(field: WpUserFieldsEnum!): [String!]! edges: [WpUserEdge!]! group(field: WpUserFieldsEnum!, limit: Int, skip: Int): [WpUserGroupConnection!]! max(field: WpUserFieldsEnum!): Float min(field: WpUserFieldsEnum!): Float nodes: [WpUser!]! pageInfo: PageInfo! sum(field: WpUserFieldsEnum!): Float totalCount: Int! } type WpUserEdge { next: WpUser node: WpUser! previous: WpUser } enum WpUserFieldsEnum { avatar___default avatar___extraAttr avatar___forceDefault avatar___foundAvatar avatar___height avatar___rating avatar___scheme avatar___size avatar___url avatar___width blockEditorPreviews___nodes blockEditorPreviews___nodes___authorDatabaseId blockEditorPreviews___nodes___authorId blockEditorPreviews___nodes___blocks blockEditorPreviews___nodes___blocksJSON blockEditorPreviews___nodes___blocks___attributesJSON blockEditorPreviews___nodes___blocks___dynamicContent blockEditorPreviews___nodes___blocks___innerBlocks blockEditorPreviews___nodes___blocks___isDynamic blockEditorPreviews___nodes___blocks___name blockEditorPreviews___nodes___blocks___order blockEditorPreviews___nodes___blocks___originalContent blockEditorPreviews___nodes___blocks___parentNodeDatabaseId blockEditorPreviews___nodes___blocks___saveContent blockEditorPreviews___nodes___children blockEditorPreviews___nodes___children___children blockEditorPreviews___nodes___children___id blockEditorPreviews___nodes___content blockEditorPreviews___nodes___contentTypeName blockEditorPreviews___nodes___databaseId blockEditorPreviews___nodes___date blockEditorPreviews___nodes___dateGmt blockEditorPreviews___nodes___desiredSlug blockEditorPreviews___nodes___enclosure blockEditorPreviews___nodes___guid blockEditorPreviews___nodes___id blockEditorPreviews___nodes___internal___content blockEditorPreviews___nodes___internal___contentDigest blockEditorPreviews___nodes___internal___description blockEditorPreviews___nodes___internal___fieldOwners blockEditorPreviews___nodes___internal___ignoreType blockEditorPreviews___nodes___internal___mediaType blockEditorPreviews___nodes___internal___owner blockEditorPreviews___nodes___internal___type blockEditorPreviews___nodes___isContentNode blockEditorPreviews___nodes___isTermNode blockEditorPreviews___nodes___lastUpdateTime blockEditorPreviews___nodes___link blockEditorPreviews___nodes___modified blockEditorPreviews___nodes___modifiedGmt blockEditorPreviews___nodes___nodeType blockEditorPreviews___nodes___parent___children blockEditorPreviews___nodes___parent___id blockEditorPreviews___nodes___previewedDatabaseId blockEditorPreviews___nodes___previewedParentDatabaseId blockEditorPreviews___nodes___previewed___blocks blockEditorPreviews___nodes___previewed___blocksJSON blockEditorPreviews___nodes___previewed___children blockEditorPreviews___nodes___previewed___id blockEditorPreviews___nodes___previewed___nodeType blockEditorPreviews___nodes___previewed___previewBlocks blockEditorPreviews___nodes___previewed___previewBlocksJSON blockEditorPreviews___nodes___slug blockEditorPreviews___nodes___status blockEditorPreviews___nodes___template___templateName blockEditorPreviews___nodes___title blockEditorPreviews___nodes___uri capKey capabilities children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id comments___nodes comments___nodes___agent comments___nodes___approved comments___nodes___authorIp comments___nodes___children comments___nodes___children___children comments___nodes___children___id comments___nodes___content comments___nodes___databaseId comments___nodes___date comments___nodes___dateGmt comments___nodes___id comments___nodes___internal___content comments___nodes___internal___contentDigest comments___nodes___internal___description comments___nodes___internal___fieldOwners comments___nodes___internal___ignoreType comments___nodes___internal___mediaType comments___nodes___internal___owner comments___nodes___internal___type comments___nodes___karma comments___nodes___nodeType comments___nodes___parentDatabaseId comments___nodes___parentId comments___nodes___parent___children comments___nodes___parent___id comments___nodes___replies___nodes comments___nodes___type databaseId description email extraCapabilities firstName id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type isContentNode isTermNode lastName locale name nicename nickname nodeType pages___nodes pages___nodes___ancestors___nodes pages___nodes___authorDatabaseId pages___nodes___authorId pages___nodes___blocks pages___nodes___blocksJSON pages___nodes___blocks___attributesJSON pages___nodes___blocks___dynamicContent pages___nodes___blocks___innerBlocks pages___nodes___blocks___isDynamic pages___nodes___blocks___name pages___nodes___blocks___order pages___nodes___blocks___originalContent pages___nodes___blocks___parentNodeDatabaseId pages___nodes___blocks___saveContent pages___nodes___children pages___nodes___children___children pages___nodes___children___id pages___nodes___commentCount pages___nodes___commentStatus pages___nodes___comments___nodes pages___nodes___content pages___nodes___contentTypeName pages___nodes___databaseId pages___nodes___date pages___nodes___dateGmt pages___nodes___desiredSlug pages___nodes___enclosure pages___nodes___featuredImageDatabaseId pages___nodes___featuredImageId pages___nodes___guid pages___nodes___id pages___nodes___internal___content pages___nodes___internal___contentDigest pages___nodes___internal___description pages___nodes___internal___fieldOwners pages___nodes___internal___ignoreType pages___nodes___internal___mediaType pages___nodes___internal___owner pages___nodes___internal___type pages___nodes___isContentNode pages___nodes___isFrontPage pages___nodes___isPostsPage pages___nodes___isPrivacyPage pages___nodes___isRevision pages___nodes___isTermNode pages___nodes___link pages___nodes___menuOrder pages___nodes___modified pages___nodes___modifiedGmt pages___nodes___nodeType pages___nodes___parentDatabaseId pages___nodes___parentId pages___nodes___parent___children pages___nodes___parent___id pages___nodes___previewBlocks pages___nodes___previewBlocksJSON pages___nodes___previewBlocks___attributesJSON pages___nodes___previewBlocks___dynamicContent pages___nodes___previewBlocks___innerBlocks pages___nodes___previewBlocks___isDynamic pages___nodes___previewBlocks___name pages___nodes___previewBlocks___order pages___nodes___previewBlocks___originalContent pages___nodes___previewBlocks___parentNodeDatabaseId pages___nodes___previewBlocks___saveContent pages___nodes___slug pages___nodes___status pages___nodes___template___templateName pages___nodes___title pages___nodes___uri pages___nodes___wpChildren___nodes parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id posts___nodes posts___nodes___authorDatabaseId posts___nodes___authorId posts___nodes___blocks posts___nodes___blocksJSON posts___nodes___blocks___attributesJSON posts___nodes___blocks___dynamicContent posts___nodes___blocks___innerBlocks posts___nodes___blocks___isDynamic posts___nodes___blocks___name posts___nodes___blocks___order posts___nodes___blocks___originalContent posts___nodes___blocks___parentNodeDatabaseId posts___nodes___blocks___saveContent posts___nodes___categories___nodes posts___nodes___children posts___nodes___children___children posts___nodes___children___id posts___nodes___commentCount posts___nodes___commentStatus posts___nodes___comments___nodes posts___nodes___content posts___nodes___contentTypeName posts___nodes___databaseId posts___nodes___date posts___nodes___dateGmt posts___nodes___desiredSlug posts___nodes___enclosure posts___nodes___excerpt posts___nodes___featuredImageDatabaseId posts___nodes___featuredImageId posts___nodes___guid posts___nodes___id posts___nodes___internal___content posts___nodes___internal___contentDigest posts___nodes___internal___description posts___nodes___internal___fieldOwners posts___nodes___internal___ignoreType posts___nodes___internal___mediaType posts___nodes___internal___owner posts___nodes___internal___type posts___nodes___isContentNode posts___nodes___isRevision posts___nodes___isSticky posts___nodes___isTermNode posts___nodes___link posts___nodes___modified posts___nodes___modifiedGmt posts___nodes___nodeType posts___nodes___parent___children posts___nodes___parent___id posts___nodes___pingStatus posts___nodes___pinged posts___nodes___postFormats___nodes posts___nodes___previewBlocks posts___nodes___previewBlocksJSON posts___nodes___previewBlocks___attributesJSON posts___nodes___previewBlocks___dynamicContent posts___nodes___previewBlocks___innerBlocks posts___nodes___previewBlocks___isDynamic posts___nodes___previewBlocks___name posts___nodes___previewBlocks___order posts___nodes___previewBlocks___originalContent posts___nodes___previewBlocks___parentNodeDatabaseId posts___nodes___previewBlocks___saveContent posts___nodes___slug posts___nodes___status posts___nodes___tags___nodes posts___nodes___template___templateName posts___nodes___terms___nodes posts___nodes___title posts___nodes___toPing posts___nodes___uri registeredDate roles___nodes roles___nodes___capabilities roles___nodes___children roles___nodes___children___children roles___nodes___children___id roles___nodes___displayName roles___nodes___id roles___nodes___internal___content roles___nodes___internal___contentDigest roles___nodes___internal___description roles___nodes___internal___fieldOwners roles___nodes___internal___ignoreType roles___nodes___internal___mediaType roles___nodes___internal___owner roles___nodes___internal___type roles___nodes___name roles___nodes___nodeType roles___nodes___parent___children roles___nodes___parent___id slug uri url username } input WpUserFilterInput { avatar: WpAvatarFilterInput blockEditorPreviews: WpUserToBlockEditorPreviewConnectionFilterInput capKey: StringQueryOperatorInput capabilities: StringQueryOperatorInput children: NodeFilterListInput comments: WpUserToCommentConnectionFilterInput databaseId: IntQueryOperatorInput description: StringQueryOperatorInput email: StringQueryOperatorInput extraCapabilities: StringQueryOperatorInput firstName: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput isContentNode: BooleanQueryOperatorInput isTermNode: BooleanQueryOperatorInput lastName: StringQueryOperatorInput locale: StringQueryOperatorInput name: StringQueryOperatorInput nicename: StringQueryOperatorInput nickname: StringQueryOperatorInput nodeType: StringQueryOperatorInput pages: WpUserToPageConnectionFilterInput parent: NodeFilterInput posts: WpUserToPostConnectionFilterInput registeredDate: StringQueryOperatorInput roles: WpUserToUserRoleConnectionFilterInput slug: StringQueryOperatorInput uri: StringQueryOperatorInput url: StringQueryOperatorInput username: StringQueryOperatorInput } type WpUserGroupConnection { distinct(field: WpUserFieldsEnum!): [String!]! edges: [WpUserEdge!]! field: String! fieldValue: String group(field: WpUserFieldsEnum!, limit: Int, skip: Int): [WpUserGroupConnection!]! max(field: WpUserFieldsEnum!): Float min(field: WpUserFieldsEnum!): Float nodes: [WpUser!]! pageInfo: PageInfo! sum(field: WpUserFieldsEnum!): Float totalCount: Int! } """ A user role object """ type WpUserRole implements Node & WpNode { """ The capabilities that belong to this role """ capabilities: [String] children: [Node!]! """ The display name of the role """ displayName: String id: ID! internal: Internal! """ The registered name of the role """ name: String nodeType: String parent: Node } type WpUserRoleConnection { distinct(field: WpUserRoleFieldsEnum!): [String!]! edges: [WpUserRoleEdge!]! group(field: WpUserRoleFieldsEnum!, limit: Int, skip: Int): [WpUserRoleGroupConnection!]! max(field: WpUserRoleFieldsEnum!): Float min(field: WpUserRoleFieldsEnum!): Float nodes: [WpUserRole!]! pageInfo: PageInfo! sum(field: WpUserRoleFieldsEnum!): Float totalCount: Int! } type WpUserRoleEdge { next: WpUserRole node: WpUserRole! previous: WpUserRole } enum WpUserRoleFieldsEnum { capabilities children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id displayName id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type name nodeType parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id } input WpUserRoleFilterInput { capabilities: StringQueryOperatorInput children: NodeFilterListInput displayName: StringQueryOperatorInput id: StringQueryOperatorInput internal: InternalFilterInput name: StringQueryOperatorInput nodeType: StringQueryOperatorInput parent: NodeFilterInput } input WpUserRoleFilterListInput { elemMatch: WpUserRoleFilterInput } type WpUserRoleGroupConnection { distinct(field: WpUserRoleFieldsEnum!): [String!]! edges: [WpUserRoleEdge!]! field: String! fieldValue: String group(field: WpUserRoleFieldsEnum!, limit: Int, skip: Int): [WpUserRoleGroupConnection!]! max(field: WpUserRoleFieldsEnum!): Float min(field: WpUserRoleFieldsEnum!): Float nodes: [WpUserRole!]! pageInfo: PageInfo! sum(field: WpUserRoleFieldsEnum!): Float totalCount: Int! } input WpUserRoleSortInput { fields: [WpUserRoleFieldsEnum] order: [SortOrderEnum] = [ASC] } input WpUserSortInput { fields: [WpUserFieldsEnum] order: [SortOrderEnum] = [ASC] } """ Connection between the User type and the BlockEditorPreview type """ type WpUserToBlockEditorPreviewConnection { """ The nodes of the connection, without the edges """ nodes: [WpBlockEditorPreview] } input WpUserToBlockEditorPreviewConnectionFilterInput { nodes: WpBlockEditorPreviewFilterListInput } """ Connection between the User type and the Comment type """ type WpUserToCommentConnection { """ The nodes of the connection, without the edges """ nodes: [WpComment] } input WpUserToCommentConnectionFilterInput { nodes: WpCommentFilterListInput } """ Connection between the User type and the page type """ type WpUserToPageConnection { """ The nodes of the connection, without the edges """ nodes: [WpPage] } input WpUserToPageConnectionFilterInput { nodes: WpPageFilterListInput } """ Connection between the User type and the post type """ type WpUserToPostConnection { """ The nodes of the connection, without the edges """ nodes: [WpPost] } input WpUserToPostConnectionFilterInput { nodes: WpPostFilterListInput } """ Connection between the User type and the UserRole type """ type WpUserToUserRoleConnection { """ The nodes of the connection, without the edges """ nodes: [WpUserRole] } input WpUserToUserRoleConnectionFilterInput { nodes: WpUserRoleFilterListInput } """ Information needed by gatsby-source-wordpress. """ type WpWPGatsby { """ Returns wether or not pretty permalinks are enabled. """ arePrettyPermalinksEnabled: Boolean """ Wether or not the Preview frontend URL is online. """ isPreviewFrontendOnline: Boolean } input WpWPGatsbyFilterInput { arePrettyPermalinksEnabled: BooleanQueryOperatorInput isPreviewFrontendOnline: BooleanQueryOperatorInput } """ The writing setting type """ type WpWritingSettings { """ Standard-Beitragskategorie. """ defaultCategory: Int """ Standard-Beitragsformat. """ defaultPostFormat: String """ Emoticons wie :-) und :-P als Grafiken anzeigen. """ useSmilies: Boolean } input WpWritingSettingsFilterInput { defaultCategory: IntQueryOperatorInput defaultPostFormat: StringQueryOperatorInput useSmilies: BooleanQueryOperatorInput } type internal__events implements Node { children: [Node!]! events: [internal__eventsEvents] id: ID! internal: Internal! next_rest_url: String parent: Node previous_rest_url: String rest_url: String total: Int total_pages: Int } type internal__eventsConnection { distinct(field: internal__eventsFieldsEnum!): [String!]! edges: [internal__eventsEdge!]! group(field: internal__eventsFieldsEnum!, limit: Int, skip: Int): [internal__eventsGroupConnection!]! max(field: internal__eventsFieldsEnum!): Float min(field: internal__eventsFieldsEnum!): Float nodes: [internal__events!]! pageInfo: PageInfo! sum(field: internal__eventsFieldsEnum!): Float totalCount: Int! } type internal__eventsEdge { next: internal__events node: internal__events! previous: internal__events } type internal__eventsEvents { all_day: Boolean alternative_id: Int author: String categories: [internal__eventsEventsCategories] cost: String cost_details: internal__eventsEventsCost_details date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date date_utc( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date description: String end_date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date end_date_details: internal__eventsEventsEnd_date_details excerpt: String featured: Boolean global_id: String global_id_lineage: [String] hide_from_listings: Boolean image: Boolean modified( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date modified_utc( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date rest_url: String show_map: Boolean show_map_link: Boolean slug: String start_date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date start_date_details: internal__eventsEventsStart_date_details status: String sticky: Boolean timezone: String timezone_abbr: String title: String url: String utc_end_date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date utc_end_date_details: internal__eventsEventsUtc_end_date_details utc_start_date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date utc_start_date_details: internal__eventsEventsUtc_start_date_details venue: internal__eventsEventsVenue website: String } type internal__eventsEventsCategories { alternative_id: Int alternative_parent: Int count: Int description: String filter: String name: String slug: String taxonomy: String term_group: Int term_taxonomy_id: Int urls: internal__eventsEventsCategoriesUrls } input internal__eventsEventsCategoriesFilterInput { alternative_id: IntQueryOperatorInput alternative_parent: IntQueryOperatorInput count: IntQueryOperatorInput description: StringQueryOperatorInput filter: StringQueryOperatorInput name: StringQueryOperatorInput slug: StringQueryOperatorInput taxonomy: StringQueryOperatorInput term_group: IntQueryOperatorInput term_taxonomy_id: IntQueryOperatorInput urls: internal__eventsEventsCategoriesUrlsFilterInput } input internal__eventsEventsCategoriesFilterListInput { elemMatch: internal__eventsEventsCategoriesFilterInput } type internal__eventsEventsCategoriesUrls { collection: String self: String up: String } input internal__eventsEventsCategoriesUrlsFilterInput { collection: StringQueryOperatorInput self: StringQueryOperatorInput up: StringQueryOperatorInput } type internal__eventsEventsCost_details { currency_code: String currency_position: String currency_symbol: String } input internal__eventsEventsCost_detailsFilterInput { currency_code: StringQueryOperatorInput currency_position: StringQueryOperatorInput currency_symbol: StringQueryOperatorInput } type internal__eventsEventsEnd_date_details { day: String hour: String minutes: String month: String seconds: String year( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date } input internal__eventsEventsEnd_date_detailsFilterInput { day: StringQueryOperatorInput hour: StringQueryOperatorInput minutes: StringQueryOperatorInput month: StringQueryOperatorInput seconds: StringQueryOperatorInput year: DateQueryOperatorInput } input internal__eventsEventsFilterInput { all_day: BooleanQueryOperatorInput alternative_id: IntQueryOperatorInput author: StringQueryOperatorInput categories: internal__eventsEventsCategoriesFilterListInput cost: StringQueryOperatorInput cost_details: internal__eventsEventsCost_detailsFilterInput date: DateQueryOperatorInput date_utc: DateQueryOperatorInput description: StringQueryOperatorInput end_date: DateQueryOperatorInput end_date_details: internal__eventsEventsEnd_date_detailsFilterInput excerpt: StringQueryOperatorInput featured: BooleanQueryOperatorInput global_id: StringQueryOperatorInput global_id_lineage: StringQueryOperatorInput hide_from_listings: BooleanQueryOperatorInput image: BooleanQueryOperatorInput modified: DateQueryOperatorInput modified_utc: DateQueryOperatorInput rest_url: StringQueryOperatorInput show_map: BooleanQueryOperatorInput show_map_link: BooleanQueryOperatorInput slug: StringQueryOperatorInput start_date: DateQueryOperatorInput start_date_details: internal__eventsEventsStart_date_detailsFilterInput status: StringQueryOperatorInput sticky: BooleanQueryOperatorInput timezone: StringQueryOperatorInput timezone_abbr: StringQueryOperatorInput title: StringQueryOperatorInput url: StringQueryOperatorInput utc_end_date: DateQueryOperatorInput utc_end_date_details: internal__eventsEventsUtc_end_date_detailsFilterInput utc_start_date: DateQueryOperatorInput utc_start_date_details: internal__eventsEventsUtc_start_date_detailsFilterInput venue: internal__eventsEventsVenueFilterInput website: StringQueryOperatorInput } input internal__eventsEventsFilterListInput { elemMatch: internal__eventsEventsFilterInput } type internal__eventsEventsStart_date_details { day: String hour: String minutes: String month: String seconds: String year( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date } input internal__eventsEventsStart_date_detailsFilterInput { day: StringQueryOperatorInput hour: StringQueryOperatorInput minutes: StringQueryOperatorInput month: StringQueryOperatorInput seconds: StringQueryOperatorInput year: DateQueryOperatorInput } type internal__eventsEventsUtc_end_date_details { day: String hour: String minutes: String month: String seconds: String year( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date } input internal__eventsEventsUtc_end_date_detailsFilterInput { day: StringQueryOperatorInput hour: StringQueryOperatorInput minutes: StringQueryOperatorInput month: StringQueryOperatorInput seconds: StringQueryOperatorInput year: DateQueryOperatorInput } type internal__eventsEventsUtc_start_date_details { day: String hour: String minutes: String month: String seconds: String year( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date } input internal__eventsEventsUtc_start_date_detailsFilterInput { day: StringQueryOperatorInput hour: StringQueryOperatorInput minutes: StringQueryOperatorInput month: StringQueryOperatorInput seconds: StringQueryOperatorInput year: DateQueryOperatorInput } type internal__eventsEventsVenue { alternative_id: Int author: String country: String date( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date date_utc( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date global_id: String global_id_lineage: [String] modified( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date modified_utc( """ Returns the difference between this date and the current time. Defaults to "milliseconds" but you can also pass in as the measurement "years", "months", "weeks", "days", "hours", "minutes", and "seconds". """ difference: String """ Format the date using Moment.js' date tokens, e.g. `date(formatString: "YYYY MMMM DD")`. See https://momentjs.com/docs/#/displaying/format/ for documentation for different tokens. """ formatString: String """ Returns a string generated with Moment.js' `fromNow` function """ fromNow: Boolean """ Configures the locale Moment.js will use to format the date. """ locale: String ): Date show_map: Boolean show_map_link: Boolean slug: String status: String url: String venue: String } input internal__eventsEventsVenueFilterInput { alternative_id: IntQueryOperatorInput author: StringQueryOperatorInput country: StringQueryOperatorInput date: DateQueryOperatorInput date_utc: DateQueryOperatorInput global_id: StringQueryOperatorInput global_id_lineage: StringQueryOperatorInput modified: DateQueryOperatorInput modified_utc: DateQueryOperatorInput show_map: BooleanQueryOperatorInput show_map_link: BooleanQueryOperatorInput slug: StringQueryOperatorInput status: StringQueryOperatorInput url: StringQueryOperatorInput venue: StringQueryOperatorInput } enum internal__eventsFieldsEnum { children children___children children___children___children children___children___children___children children___children___children___id children___children___id children___children___internal___content children___children___internal___contentDigest children___children___internal___description children___children___internal___fieldOwners children___children___internal___ignoreType children___children___internal___mediaType children___children___internal___owner children___children___internal___type children___children___parent___children children___children___parent___id children___id children___internal___content children___internal___contentDigest children___internal___description children___internal___fieldOwners children___internal___ignoreType children___internal___mediaType children___internal___owner children___internal___type children___parent___children children___parent___children___children children___parent___children___id children___parent___id children___parent___internal___content children___parent___internal___contentDigest children___parent___internal___description children___parent___internal___fieldOwners children___parent___internal___ignoreType children___parent___internal___mediaType children___parent___internal___owner children___parent___internal___type children___parent___parent___children children___parent___parent___id events events___all_day events___alternative_id events___author events___categories events___categories___alternative_id events___categories___alternative_parent events___categories___count events___categories___description events___categories___filter events___categories___name events___categories___slug events___categories___taxonomy events___categories___term_group events___categories___term_taxonomy_id events___categories___urls___collection events___categories___urls___self events___categories___urls___up events___cost events___cost_details___currency_code events___cost_details___currency_position events___cost_details___currency_symbol events___date events___date_utc events___description events___end_date events___end_date_details___day events___end_date_details___hour events___end_date_details___minutes events___end_date_details___month events___end_date_details___seconds events___end_date_details___year events___excerpt events___featured events___global_id events___global_id_lineage events___hide_from_listings events___image events___modified events___modified_utc events___rest_url events___show_map events___show_map_link events___slug events___start_date events___start_date_details___day events___start_date_details___hour events___start_date_details___minutes events___start_date_details___month events___start_date_details___seconds events___start_date_details___year events___status events___sticky events___timezone events___timezone_abbr events___title events___url events___utc_end_date events___utc_end_date_details___day events___utc_end_date_details___hour events___utc_end_date_details___minutes events___utc_end_date_details___month events___utc_end_date_details___seconds events___utc_end_date_details___year events___utc_start_date events___utc_start_date_details___day events___utc_start_date_details___hour events___utc_start_date_details___minutes events___utc_start_date_details___month events___utc_start_date_details___seconds events___utc_start_date_details___year events___venue___alternative_id events___venue___author events___venue___country events___venue___date events___venue___date_utc events___venue___global_id events___venue___global_id_lineage events___venue___modified events___venue___modified_utc events___venue___show_map events___venue___show_map_link events___venue___slug events___venue___status events___venue___url events___venue___venue events___website id internal___content internal___contentDigest internal___description internal___fieldOwners internal___ignoreType internal___mediaType internal___owner internal___type next_rest_url parent___children parent___children___children parent___children___children___children parent___children___children___id parent___children___id parent___children___internal___content parent___children___internal___contentDigest parent___children___internal___description parent___children___internal___fieldOwners parent___children___internal___ignoreType parent___children___internal___mediaType parent___children___internal___owner parent___children___internal___type parent___children___parent___children parent___children___parent___id parent___id parent___internal___content parent___internal___contentDigest parent___internal___description parent___internal___fieldOwners parent___internal___ignoreType parent___internal___mediaType parent___internal___owner parent___internal___type parent___parent___children parent___parent___children___children parent___parent___children___id parent___parent___id parent___parent___internal___content parent___parent___internal___contentDigest parent___parent___internal___description parent___parent___internal___fieldOwners parent___parent___internal___ignoreType parent___parent___internal___mediaType parent___parent___internal___owner parent___parent___internal___type parent___parent___parent___children parent___parent___parent___id previous_rest_url rest_url total total_pages } input internal__eventsFilterInput { children: NodeFilterListInput events: internal__eventsEventsFilterListInput id: StringQueryOperatorInput internal: InternalFilterInput next_rest_url: StringQueryOperatorInput parent: NodeFilterInput previous_rest_url: StringQueryOperatorInput rest_url: StringQueryOperatorInput total: IntQueryOperatorInput total_pages: IntQueryOperatorInput } type internal__eventsGroupConnection { distinct(field: internal__eventsFieldsEnum!): [String!]! edges: [internal__eventsEdge!]! field: String! fieldValue: String group(field: internal__eventsFieldsEnum!, limit: Int, skip: Int): [internal__eventsGroupConnection!]! max(field: internal__eventsFieldsEnum!): Float min(field: internal__eventsFieldsEnum!): Float nodes: [internal__events!]! pageInfo: PageInfo! sum(field: internal__eventsFieldsEnum!): Float totalCount: Int! } input internal__eventsSortInput { fields: [internal__eventsFieldsEnum] order: [SortOrderEnum] = [ASC] } ================================================ FILE: dev-test/githunt/comment-added.subscription.graphql ================================================ subscription onCommentAdded($repoFullName: String!) { commentAdded(repoFullName: $repoFullName) { id postedBy { login html_url } createdAt content } } ================================================ FILE: dev-test/githunt/comment.query.graphql ================================================ # import './comments-page-comment.fragment.graphql' query Comment($repoFullName: String!, $limit: Int, $offset: Int) { # Eventually move this into a no fetch query right on the entry # since we literally just need this info to determine whether to # show upvote/downvote buttons currentUser { login html_url } entry(repoFullName: $repoFullName) { id postedBy { login html_url } createdAt comments(limit: $limit, offset: $offset) { ...CommentsPageComment } commentCount repository { full_name html_url ... on Repository { description open_issues_count stargazers_count } } } } ================================================ FILE: dev-test/githunt/comments-page-comment.fragment.graphql ================================================ fragment CommentsPageComment on Comment { id postedBy { login html_url } createdAt content } ================================================ FILE: dev-test/githunt/current-user.query.graphql ================================================ query CurrentUserForProfile { currentUser { login avatar_url } } ================================================ FILE: dev-test/githunt/feed-entry.fragment.graphql ================================================ fragment FeedEntry on Entry { id commentCount repository { full_name html_url owner { avatar_url } } ...VoteButtons ...RepoInfo } ================================================ FILE: dev-test/githunt/feed.query.graphql ================================================ query Feed($type: FeedType!, $offset: Int, $limit: Int) { currentUser { login } feed(type: $type, offset: $offset, limit: $limit) { ...FeedEntry } } ================================================ FILE: dev-test/githunt/graphql-declared-modules.d.ts ================================================ declare module '*/current-user.query.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const CurrentUserForProfileFromOutsideDirectory: DocumentNode; export const CurrentUserForProfile: DocumentNode; export default defaultDocument; } declare module '*/comment-added.subscription.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const onCommentAdded: DocumentNode; export default defaultDocument; } declare module '*/comment.query.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const Comment: DocumentNode; export default defaultDocument; } declare module '*/comments-page-comment.fragment.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const CommentsPageComment: DocumentNode; export default defaultDocument; } declare module '*/feed-entry.fragment.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const FeedEntry: DocumentNode; export default defaultDocument; } declare module '*/feed.query.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const Feed: DocumentNode; export default defaultDocument; } declare module '*/new-entry.mutation.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const submitRepository: DocumentNode; export default defaultDocument; } declare module '*/repo-info.fragment.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const RepoInfo: DocumentNode; export default defaultDocument; } declare module '*/submit-comment.mutation.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const submitComment: DocumentNode; export default defaultDocument; } declare module '*/vote-buttons.fragment.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const VoteButtons: DocumentNode; export default defaultDocument; } declare module '*/vote.mutation.graphql' { import { DocumentNode } from 'graphql'; const defaultDocument: DocumentNode; export const vote: DocumentNode; export default defaultDocument; } ================================================ FILE: dev-test/githunt/new-entry.mutation.graphql ================================================ mutation submitRepository($repoFullName: String!) { submitRepository(repoFullName: $repoFullName) { createdAt } } ================================================ FILE: dev-test/githunt/repo-info.fragment.graphql ================================================ fragment RepoInfo on Entry { createdAt repository { description stargazers_count open_issues_count } postedBy { html_url login } } ================================================ FILE: dev-test/githunt/schema.json ================================================ { "__schema": { "queryType": { "name": "Query" }, "mutationType": { "name": "Mutation" }, "subscriptionType": { "name": "Subscription" }, "types": [ { "kind": "OBJECT", "name": "Query", "description": "", "fields": [ { "name": "feed", "description": "A feed of repository submissions", "args": [ { "name": "type", "description": "The sort order for the feed", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "FeedType", "ofType": null } }, "defaultValue": null }, { "name": "offset", "description": "The number of items to skip, for pagination", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "limit", "description": "The number of items to fetch starting from the offset, for pagination", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Entry", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "entry", "description": "A single entry", "args": [ { "name": "repoFullName", "description": "The full repository name from GitHub, e.g. \"apollostack/GitHunt-API\"", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Entry", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "currentUser", "description": "Return the currently logged in user, or null if nobody is logged in", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "FeedType", "description": "A list of options for the sort order of the feed", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "HOT", "description": "Sort by a combination of freshness and score, using Reddit's algorithm", "isDeprecated": false, "deprecationReason": null }, { "name": "NEW", "description": "Newest entries first", "isDeprecated": false, "deprecationReason": null }, { "name": "TOP", "description": "Highest score entries first", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "SCALAR", "name": "Int", "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Entry", "description": "Information about a GitHub repository submitted to GitHunt", "fields": [ { "name": "repository", "description": "Information about the repository from GitHub", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "postedBy", "description": "The GitHub user who submitted this entry", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "A timestamp of when the entry was submitted", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "score", "description": "The score of this repository, upvotes - downvotes", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hotScore", "description": "The hot score of this repository", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "comments", "description": "Comments posted about this repository", "args": [ { "name": "limit", "description": "", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "offset", "description": "", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Comment", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commentCount", "description": "The number of comments posted about this repository", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": "The SQL ID of this entry", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "vote", "description": "XXX to be changed", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Vote", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Repository", "description": "A repository object from the GitHub API. This uses the exact field names returned by the\nGitHub API for simplicity, even though the convention for GraphQL is usually to camel case.", "fields": [ { "name": "name", "description": "Just the name of the repository, e.g. GitHunt-API", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "full_name", "description": "The full name of the repository with the username, e.g. apollostack/GitHunt-API", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "The description of the repository", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "html_url", "description": "The link to the repository on GitHub", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "stargazers_count", "description": "The number of people who have starred this repository on GitHub", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "open_issues_count", "description": "The number of open issues on this repository on GitHub", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "owner", "description": "The owner of this repository on GitHub, e.g. apollostack", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "String", "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "User", "description": "A user object from the GitHub API. This uses the exact field names returned from the GitHub API.", "fields": [ { "name": "login", "description": "The name of the user, e.g. apollostack", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "avatar_url", "description": "The URL to a directly embeddable image for this user's avatar", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "html_url", "description": "The URL of this user's GitHub page", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "Float", "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Comment", "description": "A comment about an entry, submitted by a user", "fields": [ { "name": "id", "description": "The SQL ID of this entry", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "postedBy", "description": "The GitHub user who posted the comment", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "A timestamp of when the comment was posted", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "content", "description": "The text of the comment", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repoName", "description": "The repository which this comment is about", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Vote", "description": "XXX to be removed", "fields": [ { "name": "vote_value", "description": "", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Mutation", "description": "", "fields": [ { "name": "submitRepository", "description": "Submit a new repository, returns the new submission", "args": [ { "name": "repoFullName", "description": "The full repository name from GitHub, e.g. \"apollostack/GitHunt-API\"", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Entry", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "vote", "description": "Vote on a repository submission, returns the submission that was voted on", "args": [ { "name": "repoFullName", "description": "The full repository name from GitHub, e.g. \"apollostack/GitHunt-API\"", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "type", "description": "The type of vote - UP, DOWN, or CANCEL", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "VoteType", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Entry", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "submitComment", "description": "Comment on a repository, returns the new comment", "args": [ { "name": "repoFullName", "description": "The full repository name from GitHub, e.g. \"apollostack/GitHunt-API\"", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "commentContent", "description": "The text content for the new comment", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Comment", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "VoteType", "description": "The type of vote to record, when submitting a vote", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "UP", "description": "", "isDeprecated": false, "deprecationReason": null }, { "name": "DOWN", "description": "", "isDeprecated": false, "deprecationReason": null }, { "name": "CANCEL", "description": "", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "Subscription", "description": "", "fields": [ { "name": "commentAdded", "description": "Subscription fires on every comment added", "args": [ { "name": "repoFullName", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Comment", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Schema", "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", "fields": [ { "name": "types", "description": "A list of all types supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "queryType", "description": "The type that query operations will be rooted at.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mutationType", "description": "If this server supports mutation, the type that mutation operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "subscriptionType", "description": "If this server support subscription, the type that subscription operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "directives", "description": "A list of all directives supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Type", "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", "fields": [ { "name": "kind", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "fields", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "interfaces", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "possibleTypes", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "enumValues", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "inputFields", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ofType", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__TypeKind", "description": "An enum describing what kind of type a given `__Type` is.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "SCALAR", "description": "Indicates this type is a scalar.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Indicates this type is a union. `possibleTypes` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Indicates this type is an enum. `enumValues` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Indicates this type is an input object. `inputFields` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "LIST", "description": "Indicates this type is a list. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "NON_NULL", "description": "Indicates this type is a non-null. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "SCALAR", "name": "Boolean", "description": "The `Boolean` scalar type represents `true` or `false`.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Field", "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__InputValue", "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "defaultValue", "description": "A GraphQL-formatted string representing the default value for this input value.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__EnumValue", "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Directive", "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "locations", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "onOperation", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onFragment", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onField", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__DirectiveLocation", "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "QUERY", "description": "Location adjacent to a query operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "MUTATION", "description": "Location adjacent to a mutation operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "SUBSCRIPTION", "description": "Location adjacent to a subscription operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD", "description": "Location adjacent to a field.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_DEFINITION", "description": "Location adjacent to a fragment definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_SPREAD", "description": "Location adjacent to a fragment spread.", "isDeprecated": false, "deprecationReason": null }, { "name": "INLINE_FRAGMENT", "description": "Location adjacent to an inline fragment.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCHEMA", "description": "Location adjacent to a schema definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCALAR", "description": "Location adjacent to a scalar definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Location adjacent to an object type definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD_DEFINITION", "description": "Location adjacent to a field definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ARGUMENT_DEFINITION", "description": "Location adjacent to an argument definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Location adjacent to an interface definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Location adjacent to a union definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Location adjacent to an enum definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM_VALUE", "description": "Location adjacent to an enum value definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Location adjacent to an input object type definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_FIELD_DEFINITION", "description": "Location adjacent to an input object field definition.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null } ], "directives": [ { "name": "skip", "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Skipped when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ] }, { "name": "include", "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Included when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ] }, { "name": "deprecated", "description": "Marks an element of a GraphQL schema as no longer supported.", "locations": ["FIELD_DEFINITION", "ENUM_VALUE"], "args": [ { "name": "reason", "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": "\"No longer supported\"" } ] } ] } } ================================================ FILE: dev-test/githunt/submit-comment.mutation.graphql ================================================ mutation submitComment($repoFullName: String!, $commentContent: String!) { submitComment(repoFullName: $repoFullName, commentContent: $commentContent) { ...CommentsPageComment } } ================================================ FILE: dev-test/githunt/typed-document-nodes.ts ================================================ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A comment about an entry, submitted by a user */ export type Comment = { __typename?: 'Comment'; /** The text of the comment */ content: Scalars['String']['output']; /** A timestamp of when the comment was posted */ createdAt: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who posted the comment */ postedBy: User; /** The repository which this comment is about */ repoName: Scalars['String']['output']; }; /** Information about a GitHub repository submitted to GitHunt */ export type Entry = { __typename?: 'Entry'; /** The number of comments posted about this repository */ commentCount: Scalars['Int']['output']; /** Comments posted about this repository */ comments: Array>; /** A timestamp of when the entry was submitted */ createdAt: Scalars['Float']['output']; /** The hot score of this repository */ hotScore: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who submitted this entry */ postedBy: User; /** Information about the repository from GitHub */ repository: Repository; /** The score of this repository, upvotes - downvotes */ score: Scalars['Int']['output']; /** XXX to be changed */ vote: Vote; }; /** Information about a GitHub repository submitted to GitHunt */ export type EntryCommentsArgs = { limit?: InputMaybe; offset?: InputMaybe; }; /** A list of options for the sort order of the feed */ export enum FeedType { /** Sort by a combination of freshness and score, using Reddit's algorithm */ Hot = 'HOT', /** Newest entries first */ New = 'NEW', /** Highest score entries first */ Top = 'TOP', } export type Mutation = { __typename?: 'Mutation'; /** Comment on a repository, returns the new comment */ submitComment?: Maybe; /** Submit a new repository, returns the new submission */ submitRepository?: Maybe; /** Vote on a repository submission, returns the submission that was voted on */ vote?: Maybe; }; export type MutationSubmitCommentArgs = { commentContent: Scalars['String']['input']; repoFullName: Scalars['String']['input']; }; export type MutationSubmitRepositoryArgs = { repoFullName: Scalars['String']['input']; }; export type MutationVoteArgs = { repoFullName: Scalars['String']['input']; type: VoteType; }; export type Query = { __typename?: 'Query'; /** Return the currently logged in user, or null if nobody is logged in */ currentUser?: Maybe; /** A single entry */ entry?: Maybe; /** A feed of repository submissions */ feed?: Maybe>>; }; export type QueryEntryArgs = { repoFullName: Scalars['String']['input']; }; export type QueryFeedArgs = { limit?: InputMaybe; offset?: InputMaybe; type: FeedType; }; /** * A repository object from the GitHub API. This uses the exact field names returned by the * GitHub API for simplicity, even though the convention for GraphQL is usually to camel case. */ export type Repository = { __typename?: 'Repository'; /** The description of the repository */ description?: Maybe; /** The full name of the repository with the username, e.g. apollostack/GitHunt-API */ full_name: Scalars['String']['output']; /** The link to the repository on GitHub */ html_url: Scalars['String']['output']; /** Just the name of the repository, e.g. GitHunt-API */ name: Scalars['String']['output']; /** The number of open issues on this repository on GitHub */ open_issues_count?: Maybe; /** The owner of this repository on GitHub, e.g. apollostack */ owner?: Maybe; /** The number of people who have starred this repository on GitHub */ stargazers_count: Scalars['Int']['output']; }; export type Subscription = { __typename?: 'Subscription'; /** Subscription fires on every comment added */ commentAdded?: Maybe; }; export type SubscriptionCommentAddedArgs = { repoFullName: Scalars['String']['input']; }; /** A user object from the GitHub API. This uses the exact field names returned from the GitHub API. */ export type User = { __typename?: 'User'; /** The URL to a directly embeddable image for this user's avatar */ avatar_url: Scalars['String']['output']; /** The URL of this user's GitHub page */ html_url: Scalars['String']['output']; /** The name of the user, e.g. apollostack */ login: Scalars['String']['output']; }; /** XXX to be removed */ export type Vote = { __typename?: 'Vote'; vote_value: Scalars['Int']['output']; }; /** The type of vote to record, when submitting a vote */ export enum VoteType { Cancel = 'CANCEL', Down = 'DOWN', Up = 'UP', } export type OnCommentAddedSubscriptionVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type OnCommentAddedSubscription = { __typename?: 'Subscription'; commentAdded?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type CommentQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; limit?: InputMaybe; offset?: InputMaybe; }>; export type CommentQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; html_url: string } | null; entry?: { __typename?: 'Entry'; id: number; createdAt: number; commentCount: number; postedBy: { __typename?: 'User'; login: string; html_url: string }; comments: Array<{ __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null>; repository: { __typename?: 'Repository'; description?: string | null; open_issues_count?: number | null; stargazers_count: number; full_name: string; html_url: string; }; } | null; }; export type CommentsPageCommentFragment = { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; }; export type CurrentUserForProfileQueryVariables = Exact<{ [key: string]: never }>; export type CurrentUserForProfileQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; avatar_url: string } | null; }; export type FeedEntryFragment = { __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type FeedQueryVariables = Exact<{ type: FeedType; offset?: InputMaybe; limit?: InputMaybe; }>; export type FeedQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string } | null; feed?: Array<{ __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; } | null> | null; }; export type SubmitRepositoryMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type SubmitRepositoryMutation = { __typename?: 'Mutation'; submitRepository?: { __typename?: 'Entry'; createdAt: number } | null; }; export type RepoInfoFragment = { __typename?: 'Entry'; createdAt: number; repository: { __typename?: 'Repository'; description?: string | null; stargazers_count: number; open_issues_count?: number | null; }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type SubmitCommentMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; commentContent: Scalars['String']['input']; }>; export type SubmitCommentMutation = { __typename?: 'Mutation'; submitComment?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type VoteButtonsFragment = { __typename?: 'Entry'; score: number; vote: { __typename?: 'Vote'; vote_value: number }; }; export type VoteMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; type: VoteType; }>; export type VoteMutation = { __typename?: 'Mutation'; vote?: { __typename?: 'Entry'; score: number; id: number; vote: { __typename?: 'Vote'; vote_value: number } } | null; }; export const CommentsPageCommentFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'CommentsPageComment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Comment' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'postedBy' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'login' } }, { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, ], }, }, { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } }, { kind: 'Field', name: { kind: 'Name', value: 'content' } }, ], }, }, ], } as unknown as DocumentNode; export const VoteButtonsFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'VoteButtons' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Entry' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'score' } }, { kind: 'Field', name: { kind: 'Name', value: 'vote' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'vote_value' } }], }, }, ], }, }, ], } as unknown as DocumentNode; export const RepoInfoFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'RepoInfo' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Entry' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } }, { kind: 'Field', name: { kind: 'Name', value: 'repository' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'description' } }, { kind: 'Field', name: { kind: 'Name', value: 'stargazers_count' } }, { kind: 'Field', name: { kind: 'Name', value: 'open_issues_count' } }, ], }, }, { kind: 'Field', name: { kind: 'Name', value: 'postedBy' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, { kind: 'Field', name: { kind: 'Name', value: 'login' } }, ], }, }, ], }, }, ], } as unknown as DocumentNode; export const FeedEntryFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FeedEntry' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Entry' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'commentCount' } }, { kind: 'Field', name: { kind: 'Name', value: 'repository' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'full_name' } }, { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, { kind: 'Field', name: { kind: 'Name', value: 'owner' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'avatar_url' } }], }, }, ], }, }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'VoteButtons' } }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'RepoInfo' } }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'VoteButtons' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Entry' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'score' } }, { kind: 'Field', name: { kind: 'Name', value: 'vote' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'vote_value' } }], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'RepoInfo' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Entry' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } }, { kind: 'Field', name: { kind: 'Name', value: 'repository' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'description' } }, { kind: 'Field', name: { kind: 'Name', value: 'stargazers_count' } }, { kind: 'Field', name: { kind: 'Name', value: 'open_issues_count' } }, ], }, }, { kind: 'Field', name: { kind: 'Name', value: 'postedBy' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, { kind: 'Field', name: { kind: 'Name', value: 'login' } }, ], }, }, ], }, }, ], } as unknown as DocumentNode; export const OnCommentAddedDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'subscription', name: { kind: 'Name', value: 'onCommentAdded' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'commentAdded' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'repoFullName' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'postedBy' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'login' } }, { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, ], }, }, { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } }, { kind: 'Field', name: { kind: 'Name', value: 'content' } }, ], }, }, ], }, }, ], } as unknown as DocumentNode; export const CommentDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'Comment' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } } }, }, { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'limit' } }, type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } }, }, { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'offset' } }, type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'currentUser' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'login' } }, { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, ], }, }, { kind: 'Field', name: { kind: 'Name', value: 'entry' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'repoFullName' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'postedBy' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'login' } }, { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, ], }, }, { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } }, { kind: 'Field', name: { kind: 'Name', value: 'comments' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'limit' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'limit' } }, }, { kind: 'Argument', name: { kind: 'Name', value: 'offset' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'offset' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'CommentsPageComment' } }], }, }, { kind: 'Field', name: { kind: 'Name', value: 'commentCount' } }, { kind: 'Field', name: { kind: 'Name', value: 'repository' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'full_name' } }, { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, { kind: 'InlineFragment', typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Repository' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'description' } }, { kind: 'Field', name: { kind: 'Name', value: 'open_issues_count' } }, { kind: 'Field', name: { kind: 'Name', value: 'stargazers_count' } }, ], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'CommentsPageComment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Comment' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'postedBy' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'login' } }, { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, ], }, }, { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } }, { kind: 'Field', name: { kind: 'Name', value: 'content' } }, ], }, }, ], } as unknown as DocumentNode; export const CurrentUserForProfileDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'CurrentUserForProfile' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'currentUser' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'login' } }, { kind: 'Field', name: { kind: 'Name', value: 'avatar_url' } }, ], }, }, ], }, }, ], } as unknown as DocumentNode; export const FeedDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'Feed' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'type' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'FeedType' } } }, }, { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'offset' } }, type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } }, }, { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'limit' } }, type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'currentUser' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'login' } }], }, }, { kind: 'Field', name: { kind: 'Name', value: 'feed' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'type' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'type' } }, }, { kind: 'Argument', name: { kind: 'Name', value: 'offset' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'offset' } }, }, { kind: 'Argument', name: { kind: 'Name', value: 'limit' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'limit' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FeedEntry' } }], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'VoteButtons' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Entry' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'score' } }, { kind: 'Field', name: { kind: 'Name', value: 'vote' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'vote_value' } }], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'RepoInfo' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Entry' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } }, { kind: 'Field', name: { kind: 'Name', value: 'repository' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'description' } }, { kind: 'Field', name: { kind: 'Name', value: 'stargazers_count' } }, { kind: 'Field', name: { kind: 'Name', value: 'open_issues_count' } }, ], }, }, { kind: 'Field', name: { kind: 'Name', value: 'postedBy' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, { kind: 'Field', name: { kind: 'Name', value: 'login' } }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FeedEntry' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Entry' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'commentCount' } }, { kind: 'Field', name: { kind: 'Name', value: 'repository' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'full_name' } }, { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, { kind: 'Field', name: { kind: 'Name', value: 'owner' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'avatar_url' } }], }, }, ], }, }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'VoteButtons' } }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'RepoInfo' } }, ], }, }, ], } as unknown as DocumentNode; export const SubmitRepositoryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'mutation', name: { kind: 'Name', value: 'submitRepository' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'submitRepository' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'repoFullName' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'createdAt' } }], }, }, ], }, }, ], } as unknown as DocumentNode; export const SubmitCommentDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'mutation', name: { kind: 'Name', value: 'submitComment' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } } }, }, { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'commentContent' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'submitComment' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'repoFullName' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, }, { kind: 'Argument', name: { kind: 'Name', value: 'commentContent' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'commentContent' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'CommentsPageComment' } }], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'CommentsPageComment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Comment' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'postedBy' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'login' } }, { kind: 'Field', name: { kind: 'Name', value: 'html_url' } }, ], }, }, { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } }, { kind: 'Field', name: { kind: 'Name', value: 'content' } }, ], }, }, ], } as unknown as DocumentNode; export const VoteDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'mutation', name: { kind: 'Name', value: 'vote' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } } }, }, { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'type' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'VoteType' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'vote' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'repoFullName' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'repoFullName' } }, }, { kind: 'Argument', name: { kind: 'Name', value: 'type' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'type' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'score' } }, { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'vote' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'vote_value' } }], }, }, ], }, }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: dev-test/githunt/types.avoidOptionals.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A comment about an entry, submitted by a user */ export type Comment = { __typename?: 'Comment'; /** The text of the comment */ content: Scalars['String']['output']; /** A timestamp of when the comment was posted */ createdAt: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who posted the comment */ postedBy: User; /** The repository which this comment is about */ repoName: Scalars['String']['output']; }; /** Information about a GitHub repository submitted to GitHunt */ export type Entry = { __typename?: 'Entry'; /** The number of comments posted about this repository */ commentCount: Scalars['Int']['output']; /** Comments posted about this repository */ comments: Array>; /** A timestamp of when the entry was submitted */ createdAt: Scalars['Float']['output']; /** The hot score of this repository */ hotScore: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who submitted this entry */ postedBy: User; /** Information about the repository from GitHub */ repository: Repository; /** The score of this repository, upvotes - downvotes */ score: Scalars['Int']['output']; /** XXX to be changed */ vote: Vote; }; /** Information about a GitHub repository submitted to GitHunt */ export type EntryCommentsArgs = { limit: InputMaybe; offset: InputMaybe; }; /** A list of options for the sort order of the feed */ export enum FeedType { /** Sort by a combination of freshness and score, using Reddit's algorithm */ Hot = 'HOT', /** Newest entries first */ New = 'NEW', /** Highest score entries first */ Top = 'TOP', } export type Mutation = { __typename?: 'Mutation'; /** Comment on a repository, returns the new comment */ submitComment: Maybe; /** Submit a new repository, returns the new submission */ submitRepository: Maybe; /** Vote on a repository submission, returns the submission that was voted on */ vote: Maybe; }; export type MutationSubmitCommentArgs = { commentContent: Scalars['String']['input']; repoFullName: Scalars['String']['input']; }; export type MutationSubmitRepositoryArgs = { repoFullName: Scalars['String']['input']; }; export type MutationVoteArgs = { repoFullName: Scalars['String']['input']; type: VoteType; }; export type Query = { __typename?: 'Query'; /** Return the currently logged in user, or null if nobody is logged in */ currentUser: Maybe; /** A single entry */ entry: Maybe; /** A feed of repository submissions */ feed: Maybe>>; }; export type QueryEntryArgs = { repoFullName: Scalars['String']['input']; }; export type QueryFeedArgs = { limit: InputMaybe; offset: InputMaybe; type: FeedType; }; /** * A repository object from the GitHub API. This uses the exact field names returned by the * GitHub API for simplicity, even though the convention for GraphQL is usually to camel case. */ export type Repository = { __typename?: 'Repository'; /** The description of the repository */ description: Maybe; /** The full name of the repository with the username, e.g. apollostack/GitHunt-API */ full_name: Scalars['String']['output']; /** The link to the repository on GitHub */ html_url: Scalars['String']['output']; /** Just the name of the repository, e.g. GitHunt-API */ name: Scalars['String']['output']; /** The number of open issues on this repository on GitHub */ open_issues_count: Maybe; /** The owner of this repository on GitHub, e.g. apollostack */ owner: Maybe; /** The number of people who have starred this repository on GitHub */ stargazers_count: Scalars['Int']['output']; }; export type Subscription = { __typename?: 'Subscription'; /** Subscription fires on every comment added */ commentAdded: Maybe; }; export type SubscriptionCommentAddedArgs = { repoFullName: Scalars['String']['input']; }; /** A user object from the GitHub API. This uses the exact field names returned from the GitHub API. */ export type User = { __typename?: 'User'; /** The URL to a directly embeddable image for this user's avatar */ avatar_url: Scalars['String']['output']; /** The URL of this user's GitHub page */ html_url: Scalars['String']['output']; /** The name of the user, e.g. apollostack */ login: Scalars['String']['output']; }; /** XXX to be removed */ export type Vote = { __typename?: 'Vote'; vote_value: Scalars['Int']['output']; }; /** The type of vote to record, when submitting a vote */ export enum VoteType { Cancel = 'CANCEL', Down = 'DOWN', Up = 'UP', } export type OnCommentAddedSubscriptionVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type OnCommentAddedSubscription = { __typename?: 'Subscription'; commentAdded: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type CommentQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; limit: InputMaybe; offset: InputMaybe; }>; export type CommentQuery = { __typename?: 'Query'; currentUser: { __typename?: 'User'; login: string; html_url: string } | null; entry: { __typename?: 'Entry'; id: number; createdAt: number; commentCount: number; postedBy: { __typename?: 'User'; login: string; html_url: string }; comments: Array<{ __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null>; repository: { __typename?: 'Repository'; description: string | null; open_issues_count: number | null; stargazers_count: number; full_name: string; html_url: string; }; } | null; }; export type CommentsPageCommentFragment = { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; }; export type CurrentUserForProfileQueryVariables = Exact<{ [key: string]: never }>; export type CurrentUserForProfileQuery = { __typename?: 'Query'; currentUser: { __typename?: 'User'; login: string; avatar_url: string } | null; }; export type FeedEntryFragment = { __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description: string | null; stargazers_count: number; open_issues_count: number | null; owner: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type FeedQueryVariables = Exact<{ type: FeedType; offset: InputMaybe; limit: InputMaybe; }>; export type FeedQuery = { __typename?: 'Query'; currentUser: { __typename?: 'User'; login: string } | null; feed: Array<{ __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description: string | null; stargazers_count: number; open_issues_count: number | null; owner: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; } | null> | null; }; export type SubmitRepositoryMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type SubmitRepositoryMutation = { __typename?: 'Mutation'; submitRepository: { __typename?: 'Entry'; createdAt: number } | null; }; export type RepoInfoFragment = { __typename?: 'Entry'; createdAt: number; repository: { __typename?: 'Repository'; description: string | null; stargazers_count: number; open_issues_count: number | null; }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type SubmitCommentMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; commentContent: Scalars['String']['input']; }>; export type SubmitCommentMutation = { __typename?: 'Mutation'; submitComment: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type VoteButtonsFragment = { __typename?: 'Entry'; score: number; vote: { __typename?: 'Vote'; vote_value: number }; }; export type VoteMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; type: VoteType; }>; export type VoteMutation = { __typename?: 'Mutation'; vote: { __typename?: 'Entry'; score: number; id: number; vote: { __typename?: 'Vote'; vote_value: number } } | null; }; ================================================ FILE: dev-test/githunt/types.d.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A comment about an entry, submitted by a user */ export type Comment = { __typename?: 'Comment'; /** The text of the comment */ content: Scalars['String']['output']; /** A timestamp of when the comment was posted */ createdAt: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who posted the comment */ postedBy: User; /** The repository which this comment is about */ repoName: Scalars['String']['output']; }; /** Information about a GitHub repository submitted to GitHunt */ export type Entry = { __typename?: 'Entry'; /** The number of comments posted about this repository */ commentCount: Scalars['Int']['output']; /** Comments posted about this repository */ comments: Array>; /** A timestamp of when the entry was submitted */ createdAt: Scalars['Float']['output']; /** The hot score of this repository */ hotScore: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who submitted this entry */ postedBy: User; /** Information about the repository from GitHub */ repository: Repository; /** The score of this repository, upvotes - downvotes */ score: Scalars['Int']['output']; /** XXX to be changed */ vote: Vote; }; /** Information about a GitHub repository submitted to GitHunt */ export type EntryCommentsArgs = { limit?: InputMaybe; offset?: InputMaybe; }; /** A list of options for the sort order of the feed */ export type FeedType = /** Sort by a combination of freshness and score, using Reddit's algorithm */ | 'HOT' /** Newest entries first */ | 'NEW' /** Highest score entries first */ | 'TOP'; export type Mutation = { __typename?: 'Mutation'; /** Comment on a repository, returns the new comment */ submitComment?: Maybe; /** Submit a new repository, returns the new submission */ submitRepository?: Maybe; /** Vote on a repository submission, returns the submission that was voted on */ vote?: Maybe; }; export type MutationSubmitCommentArgs = { commentContent: Scalars['String']['input']; repoFullName: Scalars['String']['input']; }; export type MutationSubmitRepositoryArgs = { repoFullName: Scalars['String']['input']; }; export type MutationVoteArgs = { repoFullName: Scalars['String']['input']; type: VoteType; }; export type Query = { __typename?: 'Query'; /** Return the currently logged in user, or null if nobody is logged in */ currentUser?: Maybe; /** A single entry */ entry?: Maybe; /** A feed of repository submissions */ feed?: Maybe>>; }; export type QueryEntryArgs = { repoFullName: Scalars['String']['input']; }; export type QueryFeedArgs = { limit?: InputMaybe; offset?: InputMaybe; type: FeedType; }; /** * A repository object from the GitHub API. This uses the exact field names returned by the * GitHub API for simplicity, even though the convention for GraphQL is usually to camel case. */ export type Repository = { __typename?: 'Repository'; /** The description of the repository */ description?: Maybe; /** The full name of the repository with the username, e.g. apollostack/GitHunt-API */ full_name: Scalars['String']['output']; /** The link to the repository on GitHub */ html_url: Scalars['String']['output']; /** Just the name of the repository, e.g. GitHunt-API */ name: Scalars['String']['output']; /** The number of open issues on this repository on GitHub */ open_issues_count?: Maybe; /** The owner of this repository on GitHub, e.g. apollostack */ owner?: Maybe; /** The number of people who have starred this repository on GitHub */ stargazers_count: Scalars['Int']['output']; }; export type Subscription = { __typename?: 'Subscription'; /** Subscription fires on every comment added */ commentAdded?: Maybe; }; export type SubscriptionCommentAddedArgs = { repoFullName: Scalars['String']['input']; }; /** A user object from the GitHub API. This uses the exact field names returned from the GitHub API. */ export type User = { __typename?: 'User'; /** The URL to a directly embeddable image for this user's avatar */ avatar_url: Scalars['String']['output']; /** The URL of this user's GitHub page */ html_url: Scalars['String']['output']; /** The name of the user, e.g. apollostack */ login: Scalars['String']['output']; }; /** XXX to be removed */ export type Vote = { __typename?: 'Vote'; vote_value: Scalars['Int']['output']; }; /** The type of vote to record, when submitting a vote */ export type VoteType = 'CANCEL' | 'DOWN' | 'UP'; export type OnCommentAddedSubscriptionVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type OnCommentAddedSubscription = { __typename?: 'Subscription'; commentAdded?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type CommentQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; limit?: InputMaybe; offset?: InputMaybe; }>; export type CommentQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; html_url: string } | null; entry?: { __typename?: 'Entry'; id: number; createdAt: number; commentCount: number; postedBy: { __typename?: 'User'; login: string; html_url: string }; comments: Array<{ __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null>; repository: { __typename?: 'Repository'; description?: string | null; open_issues_count?: number | null; stargazers_count: number; full_name: string; html_url: string; }; } | null; }; export type CommentsPageCommentFragment = { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; }; export type CurrentUserForProfileQueryVariables = Exact<{ [key: string]: never }>; export type CurrentUserForProfileQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; avatar_url: string } | null; }; export type FeedEntryFragment = { __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type FeedQueryVariables = Exact<{ type: FeedType; offset?: InputMaybe; limit?: InputMaybe; }>; export type FeedQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string } | null; feed?: Array<{ __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; } | null> | null; }; export type SubmitRepositoryMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type SubmitRepositoryMutation = { __typename?: 'Mutation'; submitRepository?: { __typename?: 'Entry'; createdAt: number } | null; }; export type RepoInfoFragment = { __typename?: 'Entry'; createdAt: number; repository: { __typename?: 'Repository'; description?: string | null; stargazers_count: number; open_issues_count?: number | null; }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type SubmitCommentMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; commentContent: Scalars['String']['input']; }>; export type SubmitCommentMutation = { __typename?: 'Mutation'; submitComment?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type VoteButtonsFragment = { __typename?: 'Entry'; score: number; vote: { __typename?: 'Vote'; vote_value: number }; }; export type VoteMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; type: VoteType; }>; export type VoteMutation = { __typename?: 'Mutation'; vote?: { __typename?: 'Entry'; score: number; id: number; vote: { __typename?: 'Vote'; vote_value: number } } | null; }; ================================================ FILE: dev-test/githunt/types.enumsAsTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A comment about an entry, submitted by a user */ export type Comment = { __typename?: 'Comment'; /** The text of the comment */ content: Scalars['String']['output']; /** A timestamp of when the comment was posted */ createdAt: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who posted the comment */ postedBy: User; /** The repository which this comment is about */ repoName: Scalars['String']['output']; }; /** Information about a GitHub repository submitted to GitHunt */ export type Entry = { __typename?: 'Entry'; /** The number of comments posted about this repository */ commentCount: Scalars['Int']['output']; /** Comments posted about this repository */ comments: Array>; /** A timestamp of when the entry was submitted */ createdAt: Scalars['Float']['output']; /** The hot score of this repository */ hotScore: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who submitted this entry */ postedBy: User; /** Information about the repository from GitHub */ repository: Repository; /** The score of this repository, upvotes - downvotes */ score: Scalars['Int']['output']; /** XXX to be changed */ vote: Vote; }; /** Information about a GitHub repository submitted to GitHunt */ export type EntryCommentsArgs = { limit?: InputMaybe; offset?: InputMaybe; }; /** A list of options for the sort order of the feed */ export type FeedType = /** Sort by a combination of freshness and score, using Reddit's algorithm */ | 'HOT' /** Newest entries first */ | 'NEW' /** Highest score entries first */ | 'TOP'; export type Mutation = { __typename?: 'Mutation'; /** Comment on a repository, returns the new comment */ submitComment?: Maybe; /** Submit a new repository, returns the new submission */ submitRepository?: Maybe; /** Vote on a repository submission, returns the submission that was voted on */ vote?: Maybe; }; export type MutationSubmitCommentArgs = { commentContent: Scalars['String']['input']; repoFullName: Scalars['String']['input']; }; export type MutationSubmitRepositoryArgs = { repoFullName: Scalars['String']['input']; }; export type MutationVoteArgs = { repoFullName: Scalars['String']['input']; type: VoteType; }; export type Query = { __typename?: 'Query'; /** Return the currently logged in user, or null if nobody is logged in */ currentUser?: Maybe; /** A single entry */ entry?: Maybe; /** A feed of repository submissions */ feed?: Maybe>>; }; export type QueryEntryArgs = { repoFullName: Scalars['String']['input']; }; export type QueryFeedArgs = { limit?: InputMaybe; offset?: InputMaybe; type: FeedType; }; /** * A repository object from the GitHub API. This uses the exact field names returned by the * GitHub API for simplicity, even though the convention for GraphQL is usually to camel case. */ export type Repository = { __typename?: 'Repository'; /** The description of the repository */ description?: Maybe; /** The full name of the repository with the username, e.g. apollostack/GitHunt-API */ full_name: Scalars['String']['output']; /** The link to the repository on GitHub */ html_url: Scalars['String']['output']; /** Just the name of the repository, e.g. GitHunt-API */ name: Scalars['String']['output']; /** The number of open issues on this repository on GitHub */ open_issues_count?: Maybe; /** The owner of this repository on GitHub, e.g. apollostack */ owner?: Maybe; /** The number of people who have starred this repository on GitHub */ stargazers_count: Scalars['Int']['output']; }; export type Subscription = { __typename?: 'Subscription'; /** Subscription fires on every comment added */ commentAdded?: Maybe; }; export type SubscriptionCommentAddedArgs = { repoFullName: Scalars['String']['input']; }; /** A user object from the GitHub API. This uses the exact field names returned from the GitHub API. */ export type User = { __typename?: 'User'; /** The URL to a directly embeddable image for this user's avatar */ avatar_url: Scalars['String']['output']; /** The URL of this user's GitHub page */ html_url: Scalars['String']['output']; /** The name of the user, e.g. apollostack */ login: Scalars['String']['output']; }; /** XXX to be removed */ export type Vote = { __typename?: 'Vote'; vote_value: Scalars['Int']['output']; }; /** The type of vote to record, when submitting a vote */ export type VoteType = 'CANCEL' | 'DOWN' | 'UP'; export type OnCommentAddedSubscriptionVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type OnCommentAddedSubscription = { __typename?: 'Subscription'; commentAdded?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type CommentQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; limit?: InputMaybe; offset?: InputMaybe; }>; export type CommentQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; html_url: string } | null; entry?: { __typename?: 'Entry'; id: number; createdAt: number; commentCount: number; postedBy: { __typename?: 'User'; login: string; html_url: string }; comments: Array<{ __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null>; repository: { __typename?: 'Repository'; description?: string | null; open_issues_count?: number | null; stargazers_count: number; full_name: string; html_url: string; }; } | null; }; export type CommentsPageCommentFragment = { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; }; export type CurrentUserForProfileQueryVariables = Exact<{ [key: string]: never }>; export type CurrentUserForProfileQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; avatar_url: string } | null; }; export type FeedEntryFragment = { __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type FeedQueryVariables = Exact<{ type: FeedType; offset?: InputMaybe; limit?: InputMaybe; }>; export type FeedQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string } | null; feed?: Array<{ __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; } | null> | null; }; export type SubmitRepositoryMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type SubmitRepositoryMutation = { __typename?: 'Mutation'; submitRepository?: { __typename?: 'Entry'; createdAt: number } | null; }; export type RepoInfoFragment = { __typename?: 'Entry'; createdAt: number; repository: { __typename?: 'Repository'; description?: string | null; stargazers_count: number; open_issues_count?: number | null; }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type SubmitCommentMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; commentContent: Scalars['String']['input']; }>; export type SubmitCommentMutation = { __typename?: 'Mutation'; submitComment?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type VoteButtonsFragment = { __typename?: 'Entry'; score: number; vote: { __typename?: 'Vote'; vote_value: number }; }; export type VoteMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; type: VoteType; }>; export type VoteMutation = { __typename?: 'Mutation'; vote?: { __typename?: 'Entry'; score: number; id: number; vote: { __typename?: 'Vote'; vote_value: number } } | null; }; ================================================ FILE: dev-test/githunt/types.flatten.preResolveTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A comment about an entry, submitted by a user */ export type Comment = { __typename?: 'Comment'; /** The text of the comment */ content: Scalars['String']['output']; /** A timestamp of when the comment was posted */ createdAt: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who posted the comment */ postedBy: User; /** The repository which this comment is about */ repoName: Scalars['String']['output']; }; /** Information about a GitHub repository submitted to GitHunt */ export type Entry = { __typename?: 'Entry'; /** The number of comments posted about this repository */ commentCount: Scalars['Int']['output']; /** Comments posted about this repository */ comments: Array>; /** A timestamp of when the entry was submitted */ createdAt: Scalars['Float']['output']; /** The hot score of this repository */ hotScore: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who submitted this entry */ postedBy: User; /** Information about the repository from GitHub */ repository: Repository; /** The score of this repository, upvotes - downvotes */ score: Scalars['Int']['output']; /** XXX to be changed */ vote: Vote; }; /** Information about a GitHub repository submitted to GitHunt */ export type EntryCommentsArgs = { limit?: InputMaybe; offset?: InputMaybe; }; /** A list of options for the sort order of the feed */ export enum FeedType { /** Sort by a combination of freshness and score, using Reddit's algorithm */ Hot = 'HOT', /** Newest entries first */ New = 'NEW', /** Highest score entries first */ Top = 'TOP', } export type Mutation = { __typename?: 'Mutation'; /** Comment on a repository, returns the new comment */ submitComment?: Maybe; /** Submit a new repository, returns the new submission */ submitRepository?: Maybe; /** Vote on a repository submission, returns the submission that was voted on */ vote?: Maybe; }; export type MutationSubmitCommentArgs = { commentContent: Scalars['String']['input']; repoFullName: Scalars['String']['input']; }; export type MutationSubmitRepositoryArgs = { repoFullName: Scalars['String']['input']; }; export type MutationVoteArgs = { repoFullName: Scalars['String']['input']; type: VoteType; }; export type Query = { __typename?: 'Query'; /** Return the currently logged in user, or null if nobody is logged in */ currentUser?: Maybe; /** A single entry */ entry?: Maybe; /** A feed of repository submissions */ feed?: Maybe>>; }; export type QueryEntryArgs = { repoFullName: Scalars['String']['input']; }; export type QueryFeedArgs = { limit?: InputMaybe; offset?: InputMaybe; type: FeedType; }; /** * A repository object from the GitHub API. This uses the exact field names returned by the * GitHub API for simplicity, even though the convention for GraphQL is usually to camel case. */ export type Repository = { __typename?: 'Repository'; /** The description of the repository */ description?: Maybe; /** The full name of the repository with the username, e.g. apollostack/GitHunt-API */ full_name: Scalars['String']['output']; /** The link to the repository on GitHub */ html_url: Scalars['String']['output']; /** Just the name of the repository, e.g. GitHunt-API */ name: Scalars['String']['output']; /** The number of open issues on this repository on GitHub */ open_issues_count?: Maybe; /** The owner of this repository on GitHub, e.g. apollostack */ owner?: Maybe; /** The number of people who have starred this repository on GitHub */ stargazers_count: Scalars['Int']['output']; }; export type Subscription = { __typename?: 'Subscription'; /** Subscription fires on every comment added */ commentAdded?: Maybe; }; export type SubscriptionCommentAddedArgs = { repoFullName: Scalars['String']['input']; }; /** A user object from the GitHub API. This uses the exact field names returned from the GitHub API. */ export type User = { __typename?: 'User'; /** The URL to a directly embeddable image for this user's avatar */ avatar_url: Scalars['String']['output']; /** The URL of this user's GitHub page */ html_url: Scalars['String']['output']; /** The name of the user, e.g. apollostack */ login: Scalars['String']['output']; }; /** XXX to be removed */ export type Vote = { __typename?: 'Vote'; vote_value: Scalars['Int']['output']; }; /** The type of vote to record, when submitting a vote */ export enum VoteType { Cancel = 'CANCEL', Down = 'DOWN', Up = 'UP', } export type OnCommentAddedSubscriptionVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type OnCommentAddedSubscription = { __typename?: 'Subscription'; commentAdded?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type CommentQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; limit?: InputMaybe; offset?: InputMaybe; }>; export type CommentQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; html_url: string } | null; entry?: { __typename?: 'Entry'; id: number; createdAt: number; commentCount: number; postedBy: { __typename?: 'User'; login: string; html_url: string }; comments: Array<{ __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null>; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; open_issues_count?: number | null; stargazers_count: number; }; } | null; }; export type CurrentUserForProfileQueryVariables = Exact<{ [key: string]: never }>; export type CurrentUserForProfileQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; avatar_url: string } | null; }; export type FeedQueryVariables = Exact<{ type: FeedType; offset?: InputMaybe; limit?: InputMaybe; }>; export type FeedQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string } | null; feed?: Array<{ __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null> | null; }; export type SubmitRepositoryMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type SubmitRepositoryMutation = { __typename?: 'Mutation'; submitRepository?: { __typename?: 'Entry'; createdAt: number } | null; }; export type SubmitCommentMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; commentContent: Scalars['String']['input']; }>; export type SubmitCommentMutation = { __typename?: 'Mutation'; submitComment?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type VoteMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; type: VoteType; }>; export type VoteMutation = { __typename?: 'Mutation'; vote?: { __typename?: 'Entry'; score: number; id: number; vote: { __typename?: 'Vote'; vote_value: number } } | null; }; ================================================ FILE: dev-test/githunt/types.immutableTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A comment about an entry, submitted by a user */ export type Comment = { readonly __typename?: 'Comment'; /** The text of the comment */ readonly content: Scalars['String']['output']; /** A timestamp of when the comment was posted */ readonly createdAt: Scalars['Float']['output']; /** The SQL ID of this entry */ readonly id: Scalars['Int']['output']; /** The GitHub user who posted the comment */ readonly postedBy: User; /** The repository which this comment is about */ readonly repoName: Scalars['String']['output']; }; /** Information about a GitHub repository submitted to GitHunt */ export type Entry = { readonly __typename?: 'Entry'; /** The number of comments posted about this repository */ readonly commentCount: Scalars['Int']['output']; /** Comments posted about this repository */ readonly comments: ReadonlyArray>; /** A timestamp of when the entry was submitted */ readonly createdAt: Scalars['Float']['output']; /** The hot score of this repository */ readonly hotScore: Scalars['Float']['output']; /** The SQL ID of this entry */ readonly id: Scalars['Int']['output']; /** The GitHub user who submitted this entry */ readonly postedBy: User; /** Information about the repository from GitHub */ readonly repository: Repository; /** The score of this repository, upvotes - downvotes */ readonly score: Scalars['Int']['output']; /** XXX to be changed */ readonly vote: Vote; }; /** Information about a GitHub repository submitted to GitHunt */ export type EntryCommentsArgs = { limit?: InputMaybe; offset?: InputMaybe; }; /** A list of options for the sort order of the feed */ export enum FeedType { /** Sort by a combination of freshness and score, using Reddit's algorithm */ Hot = 'HOT', /** Newest entries first */ New = 'NEW', /** Highest score entries first */ Top = 'TOP', } export type Mutation = { readonly __typename?: 'Mutation'; /** Comment on a repository, returns the new comment */ readonly submitComment?: Maybe; /** Submit a new repository, returns the new submission */ readonly submitRepository?: Maybe; /** Vote on a repository submission, returns the submission that was voted on */ readonly vote?: Maybe; }; export type MutationSubmitCommentArgs = { commentContent: Scalars['String']['input']; repoFullName: Scalars['String']['input']; }; export type MutationSubmitRepositoryArgs = { repoFullName: Scalars['String']['input']; }; export type MutationVoteArgs = { repoFullName: Scalars['String']['input']; type: VoteType; }; export type Query = { readonly __typename?: 'Query'; /** Return the currently logged in user, or null if nobody is logged in */ readonly currentUser?: Maybe; /** A single entry */ readonly entry?: Maybe; /** A feed of repository submissions */ readonly feed?: Maybe>>; }; export type QueryEntryArgs = { repoFullName: Scalars['String']['input']; }; export type QueryFeedArgs = { limit?: InputMaybe; offset?: InputMaybe; type: FeedType; }; /** * A repository object from the GitHub API. This uses the exact field names returned by the * GitHub API for simplicity, even though the convention for GraphQL is usually to camel case. */ export type Repository = { readonly __typename?: 'Repository'; /** The description of the repository */ readonly description?: Maybe; /** The full name of the repository with the username, e.g. apollostack/GitHunt-API */ readonly full_name: Scalars['String']['output']; /** The link to the repository on GitHub */ readonly html_url: Scalars['String']['output']; /** Just the name of the repository, e.g. GitHunt-API */ readonly name: Scalars['String']['output']; /** The number of open issues on this repository on GitHub */ readonly open_issues_count?: Maybe; /** The owner of this repository on GitHub, e.g. apollostack */ readonly owner?: Maybe; /** The number of people who have starred this repository on GitHub */ readonly stargazers_count: Scalars['Int']['output']; }; export type Subscription = { readonly __typename?: 'Subscription'; /** Subscription fires on every comment added */ readonly commentAdded?: Maybe; }; export type SubscriptionCommentAddedArgs = { repoFullName: Scalars['String']['input']; }; /** A user object from the GitHub API. This uses the exact field names returned from the GitHub API. */ export type User = { readonly __typename?: 'User'; /** The URL to a directly embeddable image for this user's avatar */ readonly avatar_url: Scalars['String']['output']; /** The URL of this user's GitHub page */ readonly html_url: Scalars['String']['output']; /** The name of the user, e.g. apollostack */ readonly login: Scalars['String']['output']; }; /** XXX to be removed */ export type Vote = { readonly __typename?: 'Vote'; readonly vote_value: Scalars['Int']['output']; }; /** The type of vote to record, when submitting a vote */ export enum VoteType { Cancel = 'CANCEL', Down = 'DOWN', Up = 'UP', } export type OnCommentAddedSubscriptionVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type OnCommentAddedSubscription = { readonly __typename?: 'Subscription'; readonly commentAdded?: { readonly __typename?: 'Comment'; readonly id: number; readonly createdAt: number; readonly content: string; readonly postedBy: { readonly __typename?: 'User'; readonly login: string; readonly html_url: string }; } | null; }; export type CommentQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; limit?: InputMaybe; offset?: InputMaybe; }>; export type CommentQuery = { readonly __typename?: 'Query'; readonly currentUser?: { readonly __typename?: 'User'; readonly login: string; readonly html_url: string } | null; readonly entry?: { readonly __typename?: 'Entry'; readonly id: number; readonly createdAt: number; readonly commentCount: number; readonly postedBy: { readonly __typename?: 'User'; readonly login: string; readonly html_url: string }; readonly comments: ReadonlyArray<{ readonly __typename?: 'Comment'; readonly id: number; readonly createdAt: number; readonly content: string; readonly postedBy: { readonly __typename?: 'User'; readonly login: string; readonly html_url: string }; } | null>; readonly repository: { readonly __typename?: 'Repository'; readonly description?: string | null; readonly open_issues_count?: number | null; readonly stargazers_count: number; readonly full_name: string; readonly html_url: string; }; } | null; }; export type CommentsPageCommentFragment = { readonly __typename?: 'Comment'; readonly id: number; readonly createdAt: number; readonly content: string; readonly postedBy: { readonly __typename?: 'User'; readonly login: string; readonly html_url: string }; }; export type CurrentUserForProfileQueryVariables = Exact<{ [key: string]: never }>; export type CurrentUserForProfileQuery = { readonly __typename?: 'Query'; readonly currentUser?: { readonly __typename?: 'User'; readonly login: string; readonly avatar_url: string } | null; }; export type FeedEntryFragment = { readonly __typename?: 'Entry'; readonly id: number; readonly commentCount: number; readonly score: number; readonly createdAt: number; readonly repository: { readonly __typename?: 'Repository'; readonly full_name: string; readonly html_url: string; readonly description?: string | null; readonly stargazers_count: number; readonly open_issues_count?: number | null; readonly owner?: { readonly __typename?: 'User'; readonly avatar_url: string } | null; }; readonly vote: { readonly __typename?: 'Vote'; readonly vote_value: number }; readonly postedBy: { readonly __typename?: 'User'; readonly html_url: string; readonly login: string }; }; export type FeedQueryVariables = Exact<{ type: FeedType; offset?: InputMaybe; limit?: InputMaybe; }>; export type FeedQuery = { readonly __typename?: 'Query'; readonly currentUser?: { readonly __typename?: 'User'; readonly login: string } | null; readonly feed?: ReadonlyArray<{ readonly __typename?: 'Entry'; readonly id: number; readonly commentCount: number; readonly score: number; readonly createdAt: number; readonly repository: { readonly __typename?: 'Repository'; readonly full_name: string; readonly html_url: string; readonly description?: string | null; readonly stargazers_count: number; readonly open_issues_count?: number | null; readonly owner?: { readonly __typename?: 'User'; readonly avatar_url: string } | null; }; readonly vote: { readonly __typename?: 'Vote'; readonly vote_value: number }; readonly postedBy: { readonly __typename?: 'User'; readonly html_url: string; readonly login: string }; } | null> | null; }; export type SubmitRepositoryMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type SubmitRepositoryMutation = { readonly __typename?: 'Mutation'; readonly submitRepository?: { readonly __typename?: 'Entry'; readonly createdAt: number } | null; }; export type RepoInfoFragment = { readonly __typename?: 'Entry'; readonly createdAt: number; readonly repository: { readonly __typename?: 'Repository'; readonly description?: string | null; readonly stargazers_count: number; readonly open_issues_count?: number | null; }; readonly postedBy: { readonly __typename?: 'User'; readonly html_url: string; readonly login: string }; }; export type SubmitCommentMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; commentContent: Scalars['String']['input']; }>; export type SubmitCommentMutation = { readonly __typename?: 'Mutation'; readonly submitComment?: { readonly __typename?: 'Comment'; readonly id: number; readonly createdAt: number; readonly content: string; readonly postedBy: { readonly __typename?: 'User'; readonly login: string; readonly html_url: string }; } | null; }; export type VoteButtonsFragment = { readonly __typename?: 'Entry'; readonly score: number; readonly vote: { readonly __typename?: 'Vote'; readonly vote_value: number }; }; export type VoteMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; type: VoteType; }>; export type VoteMutation = { readonly __typename?: 'Mutation'; readonly vote?: { readonly __typename?: 'Entry'; readonly score: number; readonly id: number; readonly vote: { readonly __typename?: 'Vote'; readonly vote_value: number }; } | null; }; ================================================ FILE: dev-test/githunt/types.onlyEnums.ts ================================================ /** A list of options for the sort order of the feed */ export enum FeedType { /** Sort by a combination of freshness and score, using Reddit's algorithm */ Hot = 'HOT', /** Newest entries first */ New = 'NEW', /** Highest score entries first */ Top = 'TOP', } /** The type of vote to record, when submitting a vote */ export enum VoteType { Cancel = 'CANCEL', Down = 'DOWN', Up = 'UP', } ================================================ FILE: dev-test/githunt/types.preResolveTypes.onlyOperationTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A list of options for the sort order of the feed */ export enum FeedType { /** Sort by a combination of freshness and score, using Reddit's algorithm */ Hot = 'HOT', /** Newest entries first */ New = 'NEW', /** Highest score entries first */ Top = 'TOP', } /** The type of vote to record, when submitting a vote */ export enum VoteType { Cancel = 'CANCEL', Down = 'DOWN', Up = 'UP', } export type OnCommentAddedSubscriptionVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type OnCommentAddedSubscription = { __typename?: 'Subscription'; commentAdded?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type CommentQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; limit?: InputMaybe; offset?: InputMaybe; }>; export type CommentQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; html_url: string } | null; entry?: { __typename?: 'Entry'; id: number; createdAt: number; commentCount: number; postedBy: { __typename?: 'User'; login: string; html_url: string }; comments: Array<{ __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null>; repository: { __typename?: 'Repository'; description?: string | null; open_issues_count?: number | null; stargazers_count: number; full_name: string; html_url: string; }; } | null; }; export type CommentsPageCommentFragment = { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; }; export type CurrentUserForProfileQueryVariables = Exact<{ [key: string]: never }>; export type CurrentUserForProfileQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; avatar_url: string } | null; }; export type FeedEntryFragment = { __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type FeedQueryVariables = Exact<{ type: FeedType; offset?: InputMaybe; limit?: InputMaybe; }>; export type FeedQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string } | null; feed?: Array<{ __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; } | null> | null; }; export type SubmitRepositoryMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type SubmitRepositoryMutation = { __typename?: 'Mutation'; submitRepository?: { __typename?: 'Entry'; createdAt: number } | null; }; export type RepoInfoFragment = { __typename?: 'Entry'; createdAt: number; repository: { __typename?: 'Repository'; description?: string | null; stargazers_count: number; open_issues_count?: number | null; }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type SubmitCommentMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; commentContent: Scalars['String']['input']; }>; export type SubmitCommentMutation = { __typename?: 'Mutation'; submitComment?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type VoteButtonsFragment = { __typename?: 'Entry'; score: number; vote: { __typename?: 'Vote'; vote_value: number }; }; export type VoteMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; type: VoteType; }>; export type VoteMutation = { __typename?: 'Mutation'; vote?: { __typename?: 'Entry'; score: number; id: number; vote: { __typename?: 'Vote'; vote_value: number } } | null; }; ================================================ FILE: dev-test/githunt/types.preResolveTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A comment about an entry, submitted by a user */ export type Comment = { __typename?: 'Comment'; /** The text of the comment */ content: Scalars['String']['output']; /** A timestamp of when the comment was posted */ createdAt: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who posted the comment */ postedBy: User; /** The repository which this comment is about */ repoName: Scalars['String']['output']; }; /** Information about a GitHub repository submitted to GitHunt */ export type Entry = { __typename?: 'Entry'; /** The number of comments posted about this repository */ commentCount: Scalars['Int']['output']; /** Comments posted about this repository */ comments: Array>; /** A timestamp of when the entry was submitted */ createdAt: Scalars['Float']['output']; /** The hot score of this repository */ hotScore: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who submitted this entry */ postedBy: User; /** Information about the repository from GitHub */ repository: Repository; /** The score of this repository, upvotes - downvotes */ score: Scalars['Int']['output']; /** XXX to be changed */ vote: Vote; }; /** Information about a GitHub repository submitted to GitHunt */ export type EntryCommentsArgs = { limit?: InputMaybe; offset?: InputMaybe; }; /** A list of options for the sort order of the feed */ export enum FeedType { /** Sort by a combination of freshness and score, using Reddit's algorithm */ Hot = 'HOT', /** Newest entries first */ New = 'NEW', /** Highest score entries first */ Top = 'TOP', } export type Mutation = { __typename?: 'Mutation'; /** Comment on a repository, returns the new comment */ submitComment?: Maybe; /** Submit a new repository, returns the new submission */ submitRepository?: Maybe; /** Vote on a repository submission, returns the submission that was voted on */ vote?: Maybe; }; export type MutationSubmitCommentArgs = { commentContent: Scalars['String']['input']; repoFullName: Scalars['String']['input']; }; export type MutationSubmitRepositoryArgs = { repoFullName: Scalars['String']['input']; }; export type MutationVoteArgs = { repoFullName: Scalars['String']['input']; type: VoteType; }; export type Query = { __typename?: 'Query'; /** Return the currently logged in user, or null if nobody is logged in */ currentUser?: Maybe; /** A single entry */ entry?: Maybe; /** A feed of repository submissions */ feed?: Maybe>>; }; export type QueryEntryArgs = { repoFullName: Scalars['String']['input']; }; export type QueryFeedArgs = { limit?: InputMaybe; offset?: InputMaybe; type: FeedType; }; /** * A repository object from the GitHub API. This uses the exact field names returned by the * GitHub API for simplicity, even though the convention for GraphQL is usually to camel case. */ export type Repository = { __typename?: 'Repository'; /** The description of the repository */ description?: Maybe; /** The full name of the repository with the username, e.g. apollostack/GitHunt-API */ full_name: Scalars['String']['output']; /** The link to the repository on GitHub */ html_url: Scalars['String']['output']; /** Just the name of the repository, e.g. GitHunt-API */ name: Scalars['String']['output']; /** The number of open issues on this repository on GitHub */ open_issues_count?: Maybe; /** The owner of this repository on GitHub, e.g. apollostack */ owner?: Maybe; /** The number of people who have starred this repository on GitHub */ stargazers_count: Scalars['Int']['output']; }; export type Subscription = { __typename?: 'Subscription'; /** Subscription fires on every comment added */ commentAdded?: Maybe; }; export type SubscriptionCommentAddedArgs = { repoFullName: Scalars['String']['input']; }; /** A user object from the GitHub API. This uses the exact field names returned from the GitHub API. */ export type User = { __typename?: 'User'; /** The URL to a directly embeddable image for this user's avatar */ avatar_url: Scalars['String']['output']; /** The URL of this user's GitHub page */ html_url: Scalars['String']['output']; /** The name of the user, e.g. apollostack */ login: Scalars['String']['output']; }; /** XXX to be removed */ export type Vote = { __typename?: 'Vote'; vote_value: Scalars['Int']['output']; }; /** The type of vote to record, when submitting a vote */ export enum VoteType { Cancel = 'CANCEL', Down = 'DOWN', Up = 'UP', } export type OnCommentAddedSubscriptionVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type OnCommentAddedSubscription = { __typename?: 'Subscription'; commentAdded?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type CommentQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; limit?: InputMaybe; offset?: InputMaybe; }>; export type CommentQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; html_url: string } | null; entry?: { __typename?: 'Entry'; id: number; createdAt: number; commentCount: number; postedBy: { __typename?: 'User'; login: string; html_url: string }; comments: Array<{ __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null>; repository: { __typename?: 'Repository'; description?: string | null; open_issues_count?: number | null; stargazers_count: number; full_name: string; html_url: string; }; } | null; }; export type CommentsPageCommentFragment = { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; }; export type CurrentUserForProfileQueryVariables = Exact<{ [key: string]: never }>; export type CurrentUserForProfileQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; avatar_url: string } | null; }; export type FeedEntryFragment = { __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type FeedQueryVariables = Exact<{ type: FeedType; offset?: InputMaybe; limit?: InputMaybe; }>; export type FeedQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string } | null; feed?: Array<{ __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; } | null> | null; }; export type SubmitRepositoryMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type SubmitRepositoryMutation = { __typename?: 'Mutation'; submitRepository?: { __typename?: 'Entry'; createdAt: number } | null; }; export type RepoInfoFragment = { __typename?: 'Entry'; createdAt: number; repository: { __typename?: 'Repository'; description?: string | null; stargazers_count: number; open_issues_count?: number | null; }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type SubmitCommentMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; commentContent: Scalars['String']['input']; }>; export type SubmitCommentMutation = { __typename?: 'Mutation'; submitComment?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type VoteButtonsFragment = { __typename?: 'Entry'; score: number; vote: { __typename?: 'Vote'; vote_value: number }; }; export type VoteMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; type: VoteType; }>; export type VoteMutation = { __typename?: 'Mutation'; vote?: { __typename?: 'Entry'; score: number; id: number; vote: { __typename?: 'Vote'; vote_value: number } } | null; }; ================================================ FILE: dev-test/githunt/types.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A comment about an entry, submitted by a user */ export type Comment = { __typename?: 'Comment'; /** The text of the comment */ content: Scalars['String']['output']; /** A timestamp of when the comment was posted */ createdAt: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who posted the comment */ postedBy: User; /** The repository which this comment is about */ repoName: Scalars['String']['output']; }; /** Information about a GitHub repository submitted to GitHunt */ export type Entry = { __typename?: 'Entry'; /** The number of comments posted about this repository */ commentCount: Scalars['Int']['output']; /** Comments posted about this repository */ comments: Array>; /** A timestamp of when the entry was submitted */ createdAt: Scalars['Float']['output']; /** The hot score of this repository */ hotScore: Scalars['Float']['output']; /** The SQL ID of this entry */ id: Scalars['Int']['output']; /** The GitHub user who submitted this entry */ postedBy: User; /** Information about the repository from GitHub */ repository: Repository; /** The score of this repository, upvotes - downvotes */ score: Scalars['Int']['output']; /** XXX to be changed */ vote: Vote; }; /** Information about a GitHub repository submitted to GitHunt */ export type EntryCommentsArgs = { limit?: InputMaybe; offset?: InputMaybe; }; /** A list of options for the sort order of the feed */ export enum FeedType { /** Sort by a combination of freshness and score, using Reddit's algorithm */ Hot = 'HOT', /** Newest entries first */ New = 'NEW', /** Highest score entries first */ Top = 'TOP', } export type Mutation = { __typename?: 'Mutation'; /** Comment on a repository, returns the new comment */ submitComment?: Maybe; /** Submit a new repository, returns the new submission */ submitRepository?: Maybe; /** Vote on a repository submission, returns the submission that was voted on */ vote?: Maybe; }; export type MutationSubmitCommentArgs = { commentContent: Scalars['String']['input']; repoFullName: Scalars['String']['input']; }; export type MutationSubmitRepositoryArgs = { repoFullName: Scalars['String']['input']; }; export type MutationVoteArgs = { repoFullName: Scalars['String']['input']; type: VoteType; }; export type Query = { __typename?: 'Query'; /** Return the currently logged in user, or null if nobody is logged in */ currentUser?: Maybe; /** A single entry */ entry?: Maybe; /** A feed of repository submissions */ feed?: Maybe>>; }; export type QueryEntryArgs = { repoFullName: Scalars['String']['input']; }; export type QueryFeedArgs = { limit?: InputMaybe; offset?: InputMaybe; type: FeedType; }; /** * A repository object from the GitHub API. This uses the exact field names returned by the * GitHub API for simplicity, even though the convention for GraphQL is usually to camel case. */ export type Repository = { __typename?: 'Repository'; /** The description of the repository */ description?: Maybe; /** The full name of the repository with the username, e.g. apollostack/GitHunt-API */ full_name: Scalars['String']['output']; /** The link to the repository on GitHub */ html_url: Scalars['String']['output']; /** Just the name of the repository, e.g. GitHunt-API */ name: Scalars['String']['output']; /** The number of open issues on this repository on GitHub */ open_issues_count?: Maybe; /** The owner of this repository on GitHub, e.g. apollostack */ owner?: Maybe; /** The number of people who have starred this repository on GitHub */ stargazers_count: Scalars['Int']['output']; }; export type Subscription = { __typename?: 'Subscription'; /** Subscription fires on every comment added */ commentAdded?: Maybe; }; export type SubscriptionCommentAddedArgs = { repoFullName: Scalars['String']['input']; }; /** A user object from the GitHub API. This uses the exact field names returned from the GitHub API. */ export type User = { __typename?: 'User'; /** The URL to a directly embeddable image for this user's avatar */ avatar_url: Scalars['String']['output']; /** The URL of this user's GitHub page */ html_url: Scalars['String']['output']; /** The name of the user, e.g. apollostack */ login: Scalars['String']['output']; }; /** XXX to be removed */ export type Vote = { __typename?: 'Vote'; vote_value: Scalars['Int']['output']; }; /** The type of vote to record, when submitting a vote */ export enum VoteType { Cancel = 'CANCEL', Down = 'DOWN', Up = 'UP', } export type OnCommentAddedSubscriptionVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type OnCommentAddedSubscription = { __typename?: 'Subscription'; commentAdded?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type CommentQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; limit?: InputMaybe; offset?: InputMaybe; }>; export type CommentQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; html_url: string } | null; entry?: { __typename?: 'Entry'; id: number; createdAt: number; commentCount: number; postedBy: { __typename?: 'User'; login: string; html_url: string }; comments: Array<{ __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null>; repository: { __typename?: 'Repository'; description?: string | null; open_issues_count?: number | null; stargazers_count: number; full_name: string; html_url: string; }; } | null; }; export type CommentsPageCommentFragment = { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; }; export type CurrentUserForProfileQueryVariables = Exact<{ [key: string]: never }>; export type CurrentUserForProfileQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string; avatar_url: string } | null; }; export type FeedEntryFragment = { __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type FeedQueryVariables = Exact<{ type: FeedType; offset?: InputMaybe; limit?: InputMaybe; }>; export type FeedQuery = { __typename?: 'Query'; currentUser?: { __typename?: 'User'; login: string } | null; feed?: Array<{ __typename?: 'Entry'; id: number; commentCount: number; score: number; createdAt: number; repository: { __typename?: 'Repository'; full_name: string; html_url: string; description?: string | null; stargazers_count: number; open_issues_count?: number | null; owner?: { __typename?: 'User'; avatar_url: string } | null; }; vote: { __typename?: 'Vote'; vote_value: number }; postedBy: { __typename?: 'User'; html_url: string; login: string }; } | null> | null; }; export type SubmitRepositoryMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; }>; export type SubmitRepositoryMutation = { __typename?: 'Mutation'; submitRepository?: { __typename?: 'Entry'; createdAt: number } | null; }; export type RepoInfoFragment = { __typename?: 'Entry'; createdAt: number; repository: { __typename?: 'Repository'; description?: string | null; stargazers_count: number; open_issues_count?: number | null; }; postedBy: { __typename?: 'User'; html_url: string; login: string }; }; export type SubmitCommentMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; commentContent: Scalars['String']['input']; }>; export type SubmitCommentMutation = { __typename?: 'Mutation'; submitComment?: { __typename?: 'Comment'; id: number; createdAt: number; content: string; postedBy: { __typename?: 'User'; login: string; html_url: string }; } | null; }; export type VoteButtonsFragment = { __typename?: 'Entry'; score: number; vote: { __typename?: 'Vote'; vote_value: number }; }; export type VoteMutationVariables = Exact<{ repoFullName: Scalars['String']['input']; type: VoteType; }>; export type VoteMutation = { __typename?: 'Mutation'; vote?: { __typename?: 'Entry'; score: number; id: number; vote: { __typename?: 'Vote'; vote_value: number } } | null; }; ================================================ FILE: dev-test/githunt/vote-buttons.fragment.graphql ================================================ fragment VoteButtons on Entry { score vote { vote_value } } ================================================ FILE: dev-test/githunt/vote.mutation.graphql ================================================ mutation vote($repoFullName: String!, $type: VoteType!) { vote(repoFullName: $repoFullName, type: $type) { score id vote { vote_value } } } ================================================ FILE: dev-test/githunt-invalid/invalid.graphql ================================================ INVALID ================================================ FILE: dev-test/gql-tag-operations/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql.js'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: dev-test/gql-tag-operations/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql.js'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': typeof types.FooDocument; '\n fragment Lel on Tweet {\n id\n body\n }\n': typeof types.LelFragmentDoc; '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': typeof types.BarDocument; }; const documents: Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': types.FooDocument, '\n fragment Lel on Tweet {\n id\n body\n }\n': types.LelFragmentDoc, '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': types.BarDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query Foo {\n Tweets {\n id\n }\n }\n' ): (typeof documents)['\n query Foo {\n Tweets {\n id\n }\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment Lel on Tweet {\n id\n body\n }\n' ): (typeof documents)['\n fragment Lel on Tweet {\n id\n body\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n' ): (typeof documents)['\n query Bar {\n Tweets {\n ...Lel\n }\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: dev-test/gql-tag-operations/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; Date: { input: any; output: any }; Url: { input: any; output: any }; }; export type Meta = { __typename?: 'Meta'; count?: Maybe; }; export type Mutation = { __typename?: 'Mutation'; createTweet?: Maybe; deleteTweet?: Maybe; markTweetRead?: Maybe; }; export type MutationCreateTweetArgs = { body?: InputMaybe; }; export type MutationDeleteTweetArgs = { id: Scalars['ID']['input']; }; export type MutationMarkTweetReadArgs = { id: Scalars['ID']['input']; }; export type Notification = { __typename?: 'Notification'; date?: Maybe; id?: Maybe; type?: Maybe; }; export type Query = { __typename?: 'Query'; Notifications?: Maybe>>; NotificationsMeta?: Maybe; Tweet?: Maybe; Tweets?: Maybe>>; TweetsMeta?: Maybe; User?: Maybe; }; export type QueryNotificationsArgs = { limit?: InputMaybe; }; export type QueryTweetArgs = { id: Scalars['ID']['input']; }; export type QueryTweetsArgs = { limit?: InputMaybe; skip?: InputMaybe; sort_field?: InputMaybe; sort_order?: InputMaybe; }; export type QueryUserArgs = { id: Scalars['ID']['input']; }; export type Stat = { __typename?: 'Stat'; likes?: Maybe; responses?: Maybe; retweets?: Maybe; views?: Maybe; }; export type Tweet = { __typename?: 'Tweet'; Author?: Maybe; Stats?: Maybe; body?: Maybe; date?: Maybe; id: Scalars['ID']['output']; }; export type User = { __typename?: 'User'; avatar_url?: Maybe; first_name?: Maybe; full_name?: Maybe; id: Scalars['ID']['output']; last_name?: Maybe; /** @deprecated Field no longer supported */ name?: Maybe; username?: Maybe; }; export type FooQueryVariables = Exact<{ [key: string]: never }>; export type FooQuery = { __typename?: 'Query'; Tweets?: Array<{ __typename?: 'Tweet'; id: string } | null> | null }; export type LelFragment = { __typename?: 'Tweet'; id: string; body?: string | null } & { ' $fragmentName'?: 'LelFragment'; }; export type BarQueryVariables = Exact<{ [key: string]: never }>; export type BarQuery = { __typename?: 'Query'; Tweets?: Array<({ __typename?: 'Tweet' } & { ' $fragmentRefs'?: { LelFragment: LelFragment } }) | null> | null; }; export const LelFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'Lel' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, ], }, }, ], } as unknown as DocumentNode; export const FooDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'Foo' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'Tweets' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'id' } }], }, }, ], }, }, ], } as unknown as DocumentNode; export const BarDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'Bar' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'Tweets' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'Lel' } }], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'Lel' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: dev-test/gql-tag-operations/gql/index.ts ================================================ export * from './fragment-masking.js'; export * from './gql.js'; ================================================ FILE: dev-test/gql-tag-operations/graphql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql.js'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: dev-test/gql-tag-operations/graphql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql.js'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': typeof types.FooDocument; '\n fragment Lel on Tweet {\n id\n body\n }\n': typeof types.LelFragmentDoc; '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': typeof types.BarDocument; }; const documents: Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': types.FooDocument, '\n fragment Lel on Tweet {\n id\n body\n }\n': types.LelFragmentDoc, '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': types.BarDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query Foo {\n Tweets {\n id\n }\n }\n' ): (typeof documents)['\n query Foo {\n Tweets {\n id\n }\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment Lel on Tweet {\n id\n body\n }\n' ): (typeof documents)['\n fragment Lel on Tweet {\n id\n body\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n' ): (typeof documents)['\n query Bar {\n Tweets {\n ...Lel\n }\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: dev-test/gql-tag-operations/graphql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; Date: { input: any; output: any }; Url: { input: any; output: any }; }; export type Meta = { __typename?: 'Meta'; count?: Maybe; }; export type Mutation = { __typename?: 'Mutation'; createTweet?: Maybe; deleteTweet?: Maybe; markTweetRead?: Maybe; }; export type MutationCreateTweetArgs = { body?: InputMaybe; }; export type MutationDeleteTweetArgs = { id: Scalars['ID']['input']; }; export type MutationMarkTweetReadArgs = { id: Scalars['ID']['input']; }; export type Notification = { __typename?: 'Notification'; date?: Maybe; id?: Maybe; type?: Maybe; }; export type Query = { __typename?: 'Query'; Notifications?: Maybe>>; NotificationsMeta?: Maybe; Tweet?: Maybe; Tweets?: Maybe>>; TweetsMeta?: Maybe; User?: Maybe; }; export type QueryNotificationsArgs = { limit?: InputMaybe; }; export type QueryTweetArgs = { id: Scalars['ID']['input']; }; export type QueryTweetsArgs = { limit?: InputMaybe; skip?: InputMaybe; sort_field?: InputMaybe; sort_order?: InputMaybe; }; export type QueryUserArgs = { id: Scalars['ID']['input']; }; export type Stat = { __typename?: 'Stat'; likes?: Maybe; responses?: Maybe; retweets?: Maybe; views?: Maybe; }; export type Tweet = { __typename?: 'Tweet'; Author?: Maybe; Stats?: Maybe; body?: Maybe; date?: Maybe; id: Scalars['ID']['output']; }; export type User = { __typename?: 'User'; avatar_url?: Maybe; first_name?: Maybe; full_name?: Maybe; id: Scalars['ID']['output']; last_name?: Maybe; /** @deprecated Field no longer supported */ name?: Maybe; username?: Maybe; }; export type FooQueryVariables = Exact<{ [key: string]: never }>; export type FooQuery = { __typename?: 'Query'; Tweets?: Array<{ __typename?: 'Tweet'; id: string } | null> | null }; export type LelFragment = { __typename?: 'Tweet'; id: string; body?: string | null } & { ' $fragmentName'?: 'LelFragment'; }; export type BarQueryVariables = Exact<{ [key: string]: never }>; export type BarQuery = { __typename?: 'Query'; Tweets?: Array<({ __typename?: 'Tweet' } & { ' $fragmentRefs'?: { LelFragment: LelFragment } }) | null> | null; }; export const LelFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'Lel' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, ], }, }, ], } as unknown as DocumentNode; export const FooDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'Foo' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'Tweets' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'id' } }], }, }, ], }, }, ], } as unknown as DocumentNode; export const BarDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'Bar' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'Tweets' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'Lel' } }], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'Lel' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: dev-test/gql-tag-operations/graphql/index.ts ================================================ export * from './fragment-masking.js'; export * from './gql.js'; ================================================ FILE: dev-test/gql-tag-operations/schema.graphql ================================================ scalar Url scalar Date type Tweet { id: ID! body: String date: Date Author: User Stats: Stat } type User { id: ID! username: String first_name: String last_name: String full_name: String name: String @deprecated avatar_url: Url } type Stat { views: Int likes: Int retweets: Int responses: Int } type Notification { id: ID date: Date type: String } type Meta { count: Int } type Query { Tweet(id: ID!): Tweet Tweets(limit: Int, skip: Int, sort_field: String, sort_order: String): [Tweet] TweetsMeta: Meta User(id: ID!): User Notifications(limit: Int): [Notification] NotificationsMeta: Meta } type Mutation { createTweet(body: String): Tweet deleteTweet(id: ID!): Tweet markTweetRead(id: ID!): Boolean } ================================================ FILE: dev-test/gql-tag-operations/src/index.ts ================================================ /* eslint-disable @typescript-eslint/no-unused-vars */ import { graphql, DocumentType } from '../gql/gql.js'; const FooQuery = graphql(/* GraphQL */ ` query Foo { Tweets { id } } `); const LelFragment = graphql(/* GraphQL */ ` fragment Lel on Tweet { id body } `); const BarQuery = graphql(/* GraphQL */ ` query Bar { Tweets { ...Lel } } `); const doSth = (params: { lel: DocumentType }) => { params.lel.id; }; ================================================ FILE: dev-test/gql-tag-operations-masking/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql.js'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: dev-test/gql-tag-operations-masking/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql.js'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n fragment TweetFragment on Tweet {\n id\n body\n ...TweetAuthorFragment\n }\n': typeof types.TweetFragmentFragmentDoc; '\n fragment TweetAuthorFragment on Tweet {\n id\n author {\n id\n username\n }\n }\n': typeof types.TweetAuthorFragmentFragmentDoc; '\n fragment TweetsFragment on Query {\n Tweets {\n id\n ...TweetFragment\n }\n }\n': typeof types.TweetsFragmentFragmentDoc; '\n query TweetAppQuery {\n ...TweetsFragment\n }\n': typeof types.TweetAppQueryDocument; }; const documents: Documents = { '\n fragment TweetFragment on Tweet {\n id\n body\n ...TweetAuthorFragment\n }\n': types.TweetFragmentFragmentDoc, '\n fragment TweetAuthorFragment on Tweet {\n id\n author {\n id\n username\n }\n }\n': types.TweetAuthorFragmentFragmentDoc, '\n fragment TweetsFragment on Query {\n Tweets {\n id\n ...TweetFragment\n }\n }\n': types.TweetsFragmentFragmentDoc, '\n query TweetAppQuery {\n ...TweetsFragment\n }\n': types.TweetAppQueryDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment TweetFragment on Tweet {\n id\n body\n ...TweetAuthorFragment\n }\n' ): (typeof documents)['\n fragment TweetFragment on Tweet {\n id\n body\n ...TweetAuthorFragment\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment TweetAuthorFragment on Tweet {\n id\n author {\n id\n username\n }\n }\n' ): (typeof documents)['\n fragment TweetAuthorFragment on Tweet {\n id\n author {\n id\n username\n }\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment TweetsFragment on Query {\n Tweets {\n id\n ...TweetFragment\n }\n }\n' ): (typeof documents)['\n fragment TweetsFragment on Query {\n Tweets {\n id\n ...TweetFragment\n }\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query TweetAppQuery {\n ...TweetsFragment\n }\n' ): (typeof documents)['\n query TweetAppQuery {\n ...TweetsFragment\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: dev-test/gql-tag-operations-masking/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; Date: { input: any; output: any }; Url: { input: any; output: any }; }; export type Meta = { __typename?: 'Meta'; count?: Maybe; }; export type Mutation = { __typename?: 'Mutation'; createTweet?: Maybe; deleteTweet?: Maybe; markTweetRead?: Maybe; }; export type MutationCreateTweetArgs = { body?: InputMaybe; }; export type MutationDeleteTweetArgs = { id: Scalars['ID']['input']; }; export type MutationMarkTweetReadArgs = { id: Scalars['ID']['input']; }; export type Notification = { __typename?: 'Notification'; date?: Maybe; id?: Maybe; type?: Maybe; }; export type Query = { __typename?: 'Query'; Notifications?: Maybe>>; NotificationsMeta?: Maybe; Tweet?: Maybe; Tweets?: Maybe>; TweetsMeta?: Maybe; User?: Maybe; }; export type QueryNotificationsArgs = { limit?: InputMaybe; }; export type QueryTweetArgs = { id: Scalars['ID']['input']; }; export type QueryTweetsArgs = { limit?: InputMaybe; skip?: InputMaybe; sort_field?: InputMaybe; sort_order?: InputMaybe; }; export type QueryUserArgs = { id: Scalars['ID']['input']; }; export type Stat = { __typename?: 'Stat'; likes?: Maybe; responses?: Maybe; retweets?: Maybe; views?: Maybe; }; export type Tweet = { __typename?: 'Tweet'; Stats?: Maybe; author: User; body: Scalars['String']['output']; date?: Maybe; id: Scalars['ID']['output']; }; export type User = { __typename?: 'User'; avatar_url?: Maybe; first_name?: Maybe; full_name?: Maybe; id: Scalars['ID']['output']; last_name?: Maybe; /** @deprecated Field no longer supported */ name?: Maybe; username?: Maybe; }; export type TweetFragmentFragment = ({ __typename?: 'Tweet'; id: string; body: string } & { ' $fragmentRefs'?: { TweetAuthorFragmentFragment: TweetAuthorFragmentFragment }; }) & { ' $fragmentName'?: 'TweetFragmentFragment' }; export type TweetAuthorFragmentFragment = { __typename?: 'Tweet'; id: string; author: { __typename?: 'User'; id: string; username?: string | null }; } & { ' $fragmentName'?: 'TweetAuthorFragmentFragment' }; export type TweetsFragmentFragment = { __typename?: 'Query'; Tweets?: Array< { __typename?: 'Tweet'; id: string } & { ' $fragmentRefs'?: { TweetFragmentFragment: TweetFragmentFragment } } > | null; } & { ' $fragmentName'?: 'TweetsFragmentFragment' }; export type TweetAppQueryQueryVariables = Exact<{ [key: string]: never }>; export type TweetAppQueryQuery = { __typename?: 'Query' } & { ' $fragmentRefs'?: { TweetsFragmentFragment: TweetsFragmentFragment }; }; export const TweetAuthorFragmentFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'TweetAuthorFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'author' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'username' } }, ], }, }, ], }, }, ], } as unknown as DocumentNode; export const TweetFragmentFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'TweetFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'TweetAuthorFragment' } }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'TweetAuthorFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'author' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'username' } }, ], }, }, ], }, }, ], } as unknown as DocumentNode; export const TweetsFragmentFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'TweetsFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Query' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'Tweets' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'TweetFragment' } }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'TweetAuthorFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'author' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'username' } }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'TweetFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'TweetAuthorFragment' } }, ], }, }, ], } as unknown as DocumentNode; export const TweetAppQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'TweetAppQuery' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'TweetsFragment' } }], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'TweetAuthorFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'author' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'username' } }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'TweetFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'TweetAuthorFragment' } }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'TweetsFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Query' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'Tweets' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'TweetFragment' } }, ], }, }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: dev-test/gql-tag-operations-masking/gql/index.ts ================================================ export * from './fragment-masking.js'; export * from './gql.js'; ================================================ FILE: dev-test/gql-tag-operations-masking/schema.graphql ================================================ scalar Url scalar Date type Tweet { id: ID! body: String! date: Date author: User! Stats: Stat } type User { id: ID! username: String first_name: String last_name: String full_name: String name: String @deprecated avatar_url: Url } type Stat { views: Int likes: Int retweets: Int responses: Int } type Notification { id: ID date: Date type: String } type Meta { count: Int } type Query { Tweet(id: ID!): Tweet Tweets(limit: Int, skip: Int, sort_field: String, sort_order: String): [Tweet!] TweetsMeta: Meta User(id: ID!): User Notifications(limit: Int): [Notification] NotificationsMeta: Meta } type Mutation { createTweet(body: String): Tweet deleteTweet(id: ID!): Tweet markTweetRead(id: ID!): Boolean } ================================================ FILE: dev-test/gql-tag-operations-masking/src/index.tsx ================================================ /* eslint-disable @typescript-eslint/no-unused-vars */ import React from 'react'; import { graphql, FragmentType, useFragment } from '../gql'; import { useQuery } from 'urql'; const TweetFragment = graphql(/* GraphQL */ ` fragment TweetFragment on Tweet { id body ...TweetAuthorFragment } `); const TweetAuthorFragment = graphql(/* GraphQL */ ` fragment TweetAuthorFragment on Tweet { id author { id username } } `); const TweetsFragment = graphql(/* GraphQL */ ` fragment TweetsFragment on Query { Tweets { id ...TweetFragment } } `); const TweetAppQuery = graphql(/* GraphQL */ ` query TweetAppQuery { ...TweetsFragment } `); const Tweet = (props: { tweet: FragmentType }) => { const tweet = useFragment(TweetFragment, props.tweet); return (
  • {tweet.id} {tweet.body}
  • ); }; const TweetAuthor = (props: { tweet: FragmentType }) => { const tweet = useFragment(TweetAuthorFragment, props.tweet); return
    {tweet.author?.username}
    ; }; const Tweets = (props: { tweets: FragmentType | null | undefined }) => { const tweets = useFragment(TweetsFragment, props.tweets); return
      {tweets?.Tweets?.map(tweet => ) ?? null}
    ; }; const App = () => { const [query] = useQuery({ query: TweetAppQuery }); return query.data == null ? null : ; }; ================================================ FILE: dev-test/gql-tag-operations-urql/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql.js'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: dev-test/gql-tag-operations-urql/gql/gql.d.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; declare module '@urql/core' { /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function gql( source: '\n query Foo {\n Tweets {\n id\n }\n }\n' ): typeof import('./graphql.js').FooDocument; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function gql( source: '\n fragment Lel on Tweet {\n id\n body\n }\n' ): typeof import('./graphql.js').LelFragmentDoc; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function gql( source: '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n' ): typeof import('./graphql.js').BarDocument; export function gql(source: string): unknown; export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; } ================================================ FILE: dev-test/gql-tag-operations-urql/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql.js'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': typeof types.FooDocument; '\n fragment Lel on Tweet {\n id\n body\n }\n': typeof types.LelFragmentDoc; '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': typeof types.BarDocument; }; const documents: Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': types.FooDocument, '\n fragment Lel on Tweet {\n id\n body\n }\n': types.LelFragmentDoc, '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': types.BarDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query Foo {\n Tweets {\n id\n }\n }\n' ): (typeof documents)['\n query Foo {\n Tweets {\n id\n }\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment Lel on Tweet {\n id\n body\n }\n' ): (typeof documents)['\n fragment Lel on Tweet {\n id\n body\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n' ): (typeof documents)['\n query Bar {\n Tweets {\n ...Lel\n }\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: dev-test/gql-tag-operations-urql/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; Date: { input: any; output: any }; Url: { input: any; output: any }; }; export type Meta = { __typename?: 'Meta'; count?: Maybe; }; export type Mutation = { __typename?: 'Mutation'; createTweet?: Maybe; deleteTweet?: Maybe; markTweetRead?: Maybe; }; export type MutationCreateTweetArgs = { body?: InputMaybe; }; export type MutationDeleteTweetArgs = { id: Scalars['ID']['input']; }; export type MutationMarkTweetReadArgs = { id: Scalars['ID']['input']; }; export type Notification = { __typename?: 'Notification'; date?: Maybe; id?: Maybe; type?: Maybe; }; export type Query = { __typename?: 'Query'; Notifications?: Maybe>>; NotificationsMeta?: Maybe; Tweet?: Maybe; Tweets?: Maybe>>; TweetsMeta?: Maybe; User?: Maybe; }; export type QueryNotificationsArgs = { limit?: InputMaybe; }; export type QueryTweetArgs = { id: Scalars['ID']['input']; }; export type QueryTweetsArgs = { limit?: InputMaybe; skip?: InputMaybe; sort_field?: InputMaybe; sort_order?: InputMaybe; }; export type QueryUserArgs = { id: Scalars['ID']['input']; }; export type Stat = { __typename?: 'Stat'; likes?: Maybe; responses?: Maybe; retweets?: Maybe; views?: Maybe; }; export type Tweet = { __typename?: 'Tweet'; Author?: Maybe; Stats?: Maybe; body?: Maybe; date?: Maybe; id: Scalars['ID']['output']; }; export type User = { __typename?: 'User'; avatar_url?: Maybe; first_name?: Maybe; full_name?: Maybe; id: Scalars['ID']['output']; last_name?: Maybe; /** @deprecated Field no longer supported */ name?: Maybe; username?: Maybe; }; export type FooQueryVariables = Exact<{ [key: string]: never }>; export type FooQuery = { __typename?: 'Query'; Tweets?: Array<{ __typename?: 'Tweet'; id: string } | null> | null }; export type LelFragment = { __typename?: 'Tweet'; id: string; body?: string | null } & { ' $fragmentName'?: 'LelFragment'; }; export type BarQueryVariables = Exact<{ [key: string]: never }>; export type BarQuery = { __typename?: 'Query'; Tweets?: Array<({ __typename?: 'Tweet' } & { ' $fragmentRefs'?: { LelFragment: LelFragment } }) | null> | null; }; export const LelFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'Lel' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, ], }, }, ], } as unknown as DocumentNode; export const FooDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'Foo' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'Tweets' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'id' } }], }, }, ], }, }, ], } as unknown as DocumentNode; export const BarDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'Bar' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'Tweets' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'Lel' } }], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'Lel' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Tweet' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: dev-test/gql-tag-operations-urql/gql/index.ts ================================================ export * from './fragment-masking.js'; export * from './gql.js'; ================================================ FILE: dev-test/gql-tag-operations-urql/schema.graphql ================================================ scalar Url scalar Date type Tweet { id: ID! body: String date: Date Author: User Stats: Stat } type User { id: ID! username: String first_name: String last_name: String full_name: String name: String @deprecated avatar_url: Url } type Stat { views: Int likes: Int retweets: Int responses: Int } type Notification { id: ID date: Date type: String } type Meta { count: Int } type Query { Tweet(id: ID!): Tweet Tweets(limit: Int, skip: Int, sort_field: String, sort_order: String): [Tweet] TweetsMeta: Meta User(id: ID!): User Notifications(limit: Int): [Notification] NotificationsMeta: Meta } type Mutation { createTweet(body: String): Tweet deleteTweet(id: ID!): Tweet markTweetRead(id: ID!): Boolean } ================================================ FILE: dev-test/gql-tag-operations-urql/src/index.ts ================================================ /* eslint-disable @typescript-eslint/no-unused-vars */ import { gql } from 'urql'; const FooQuery = gql(/* GraphQL */ ` query Foo { Tweets { id } } `); const LelFragment = gql(/* GraphQL */ ` fragment Lel on Tweet { id body } `); const BarQuery = gql(/* GraphQL */ ` query Bar { Tweets { ...Lel } } `); ================================================ FILE: dev-test/modules/blog/generated.ts ================================================ import * as Types from '../types.js'; import * as gm from 'graphql-modules'; export namespace BlogModule { interface DefinedFields { Article: 'id' | 'title' | 'text' | 'author'; Query: 'articles' | 'articleById' | 'articlesByUser'; } export type Article = Pick; export type User = Types.User; export type Query = Pick; export type ArticleResolvers = Pick; export type QueryResolvers = Pick; export interface Resolvers { Article?: ArticleResolvers; Query?: QueryResolvers; } export interface MiddlewareMap { '*'?: { '*'?: gm.Middleware[]; }; Article?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; title?: gm.Middleware[]; text?: gm.Middleware[]; author?: gm.Middleware[]; }; Query?: { '*'?: gm.Middleware[]; articles?: gm.Middleware[]; articleById?: gm.Middleware[]; articlesByUser?: gm.Middleware[]; }; } } ================================================ FILE: dev-test/modules/blog/types/blog.graphql ================================================ type Article { id: ID! title: String! text: String! author: User! } extend type Query { articles: [Article!] articleById(id: ID!): Article articlesByUser(userId: ID!): [Article!] } ================================================ FILE: dev-test/modules/common/generated.ts ================================================ import * as Types from '../types.js'; import * as gm from 'graphql-modules'; export namespace CommonModule { interface DefinedFields { Query: 'ping'; Mutation: 'pong'; } export type Query = Pick; export type Mutation = Pick; export type QueryResolvers = Pick; export type MutationResolvers = Pick; export interface Resolvers { Query?: QueryResolvers; Mutation?: MutationResolvers; } export interface MiddlewareMap { '*'?: { '*'?: gm.Middleware[]; }; Query?: { '*'?: gm.Middleware[]; ping?: gm.Middleware[]; }; Mutation?: { '*'?: gm.Middleware[]; pong?: gm.Middleware[]; }; } } ================================================ FILE: dev-test/modules/common/types/common.graphql ================================================ type Query { ping: Int } type Mutation { pong: Int } ================================================ FILE: dev-test/modules/dotanions/generated.ts ================================================ import * as Types from '../types.js'; import * as gm from 'graphql-modules'; export namespace DotanionsModule { interface DefinedFields { Paypal: 'id' | 'url'; CreditCard: 'id' | 'cardNumber' | 'cardOwner'; Donation: 'id' | 'sender' | 'recipient' | 'amount'; Mutation: 'donate'; User: 'paymentOptions'; } interface DefinedInputFields { DonationInput: 'user' | 'amount' | 'paymentOption'; } export type Paypal = Pick; export type CreditCard = Pick; export type PaymentOption = Types.PaymentOption; export type User = Types.User; export type Donation = Pick; export type DonationInput = Pick; export type Mutation = Pick; export type PaypalResolvers = Pick; export type CreditCardResolvers = Pick; export type DonationResolvers = Pick; export type MutationResolvers = Pick; export type UserResolvers = Pick; export interface Resolvers { Paypal?: PaypalResolvers; CreditCard?: CreditCardResolvers; Donation?: DonationResolvers; Mutation?: MutationResolvers; User?: UserResolvers; } export interface MiddlewareMap { '*'?: { '*'?: gm.Middleware[]; }; Paypal?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; url?: gm.Middleware[]; }; CreditCard?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; cardNumber?: gm.Middleware[]; cardOwner?: gm.Middleware[]; }; User?: { '*'?: gm.Middleware[]; paymentOptions?: gm.Middleware[]; }; Donation?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; sender?: gm.Middleware[]; recipient?: gm.Middleware[]; amount?: gm.Middleware[]; }; Mutation?: { '*'?: gm.Middleware[]; donate?: gm.Middleware[]; }; } } ================================================ FILE: dev-test/modules/dotanions/types/donations.graphql ================================================ type Paypal { id: ID! url: String! } type CreditCard { id: ID! cardNumber: Int! cardOwner: String! } union PaymentOption = Paypal | CreditCard extend type User { paymentOptions: [PaymentOption!] } type Donation { id: ID! sender: User! recipient: User! amount: Float! } input DonationInput { user: ID! amount: Float! paymentOption: ID! } extend type Mutation { donate(donation: DonationInput): Donation } ================================================ FILE: dev-test/modules/types.ts ================================================ import { GraphQLResolveInfo } from 'graphql'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; export type Omit = Pick>; export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Article = { __typename?: 'Article'; author: User; id: Scalars['ID']['output']; text: Scalars['String']['output']; title: Scalars['String']['output']; }; export type CreditCard = { __typename?: 'CreditCard'; cardNumber: Scalars['Int']['output']; cardOwner: Scalars['String']['output']; id: Scalars['ID']['output']; }; export type Donation = { __typename?: 'Donation'; amount: Scalars['Float']['output']; id: Scalars['ID']['output']; recipient: User; sender: User; }; export type DonationInput = { amount: Scalars['Float']['input']; paymentOption: Scalars['ID']['input']; user: Scalars['ID']['input']; }; export type Mutation = { __typename?: 'Mutation'; donate?: Maybe; pong?: Maybe; }; export type MutationDonateArgs = { donation?: InputMaybe; }; export type PaymentOption = CreditCard | Paypal; export type Paypal = { __typename?: 'Paypal'; id: Scalars['ID']['output']; url: Scalars['String']['output']; }; export type Query = { __typename?: 'Query'; articleById?: Maybe
    ; articles?: Maybe>; articlesByUser?: Maybe>; ping?: Maybe; userById?: Maybe; users?: Maybe>; }; export type QueryArticleByIdArgs = { id: Scalars['ID']['input']; }; export type QueryArticlesByUserArgs = { userId: Scalars['ID']['input']; }; export type QueryUserByIdArgs = { id: Scalars['ID']['input']; }; export type User = { __typename?: 'User'; firstName: Scalars['String']['output']; id: Scalars['ID']['output']; lastName: Scalars['String']['output']; paymentOptions?: Maybe>; }; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping of union types */ export type ResolversUnionTypes<_RefType extends Record> = { PaymentOption: CreditCard | Paypal; }; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Article: ResolverTypeWrapper & { author: ResolversTypes['User'] }>; Boolean: ResolverTypeWrapper; CreditCard: ResolverTypeWrapper; Donation: ResolverTypeWrapper< Omit & { recipient: ResolversTypes['User']; sender: ResolversTypes['User'] } >; DonationInput: DonationInput; Float: ResolverTypeWrapper; ID: ResolverTypeWrapper; Int: ResolverTypeWrapper; Mutation: ResolverTypeWrapper>; PaymentOption: ResolverTypeWrapper['PaymentOption']>; Paypal: ResolverTypeWrapper; Query: ResolverTypeWrapper>; String: ResolverTypeWrapper; User: ResolverTypeWrapper< Omit & { paymentOptions?: Maybe> } >; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Article: Omit & { author: ResolversParentTypes['User'] }; Boolean: Scalars['Boolean']['output']; CreditCard: CreditCard; Donation: Omit & { recipient: ResolversParentTypes['User']; sender: ResolversParentTypes['User']; }; DonationInput: DonationInput; Float: Scalars['Float']['output']; ID: Scalars['ID']['output']; Int: Scalars['Int']['output']; Mutation: Record; PaymentOption: ResolversUnionTypes['PaymentOption']; Paypal: Paypal; Query: Record; String: Scalars['String']['output']; User: Omit & { paymentOptions?: Maybe> }; }; export type ArticleResolvers< ContextType = any, ParentType extends ResolversParentTypes['Article'] = ResolversParentTypes['Article'] > = { author?: Resolver; id?: Resolver; text?: Resolver; title?: Resolver; }; export type CreditCardResolvers< ContextType = any, ParentType extends ResolversParentTypes['CreditCard'] = ResolversParentTypes['CreditCard'] > = { cardNumber?: Resolver; cardOwner?: Resolver; id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type DonationResolvers< ContextType = any, ParentType extends ResolversParentTypes['Donation'] = ResolversParentTypes['Donation'] > = { amount?: Resolver; id?: Resolver; recipient?: Resolver; sender?: Resolver; }; export type MutationResolvers< ContextType = any, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation'] > = { donate?: Resolver, ParentType, ContextType, Partial>; pong?: Resolver, ParentType, ContextType>; }; export type PaymentOptionResolvers< ContextType = any, ParentType extends ResolversParentTypes['PaymentOption'] = ResolversParentTypes['PaymentOption'] > = { __resolveType: TypeResolveFn<'CreditCard' | 'Paypal', ParentType, ContextType>; }; export type PaypalResolvers< ContextType = any, ParentType extends ResolversParentTypes['Paypal'] = ResolversParentTypes['Paypal'] > = { id?: Resolver; url?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type QueryResolvers< ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'] > = { articleById?: Resolver< Maybe, ParentType, ContextType, RequireFields >; articles?: Resolver>, ParentType, ContextType>; articlesByUser?: Resolver< Maybe>, ParentType, ContextType, RequireFields >; ping?: Resolver, ParentType, ContextType>; userById?: Resolver, ParentType, ContextType, RequireFields>; users?: Resolver>, ParentType, ContextType>; }; export type UserResolvers< ContextType = any, ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User'] > = { firstName?: Resolver; id?: Resolver; lastName?: Resolver; paymentOptions?: Resolver>, ParentType, ContextType>; }; export type Resolvers = { Article?: ArticleResolvers; CreditCard?: CreditCardResolvers; Donation?: DonationResolvers; Mutation?: MutationResolvers; PaymentOption?: PaymentOptionResolvers; Paypal?: PaypalResolvers; Query?: QueryResolvers; User?: UserResolvers; }; ================================================ FILE: dev-test/modules/users/generated.ts ================================================ import * as Types from '../types.js'; import * as gm from 'graphql-modules'; export namespace UsersModule { interface DefinedFields { User: 'id' | 'firstName' | 'lastName'; Query: 'users' | 'userById'; } export type User = Pick; export type Query = Pick; export type UserResolvers = Pick; export type QueryResolvers = Pick; export interface Resolvers { User?: UserResolvers; Query?: QueryResolvers; } export interface MiddlewareMap { '*'?: { '*'?: gm.Middleware[]; }; User?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; firstName?: gm.Middleware[]; lastName?: gm.Middleware[]; }; Query?: { '*'?: gm.Middleware[]; users?: gm.Middleware[]; userById?: gm.Middleware[]; }; } } ================================================ FILE: dev-test/modules/users/types/users.graphql ================================================ type User { id: ID! firstName: String! lastName: String! } extend type Query { users: [User!] userById(id: ID!): User } ================================================ FILE: dev-test/setup.js ================================================ process.on('unhandledRejection', err => { fail(err); }); ================================================ FILE: dev-test/star-wars/CreateReviewForEpisode.graphql ================================================ mutation CreateReviewForEpisode($episode: Episode!, $review: ReviewInput!) { createReview(episode: $episode, review: $review) { stars commentary } } ================================================ FILE: dev-test/star-wars/ExcludeQueryAlpha.graphql ================================================ # This file should be excluded by pattern matching in types.excludeQueryAlpha query ExcludeQueryAlpha($episode: Episode) { hero(episode: $episode) { name } } ================================================ FILE: dev-test/star-wars/ExcludeQueryBeta.graphql ================================================ # This file should be excluded by pattern matching in types.excludeQueryBeta query ExcludeQueryBeta($episode: Episode) { hero(episode: $episode) { name } } ================================================ FILE: dev-test/star-wars/HeroAndFriendsNames.graphql ================================================ query HeroAndFriendsNames($episode: Episode) { hero(episode: $episode) { name friends { name } } } ================================================ FILE: dev-test/star-wars/HeroAppearsIn.graphql ================================================ query HeroAppearsIn { hero { name appearsIn } } ================================================ FILE: dev-test/star-wars/HeroDetails.graphql ================================================ query HeroDetails($episode: Episode) { hero(episode: $episode) { name ... on Human { height } ... on Droid { primaryFunction } } } ================================================ FILE: dev-test/star-wars/HeroDetailsFragment.graphql ================================================ fragment HeroDetails on Character { name ... on Human { height } ... on Droid { primaryFunction } } ================================================ FILE: dev-test/star-wars/HeroDetailsWithFragment.graphql ================================================ query HeroDetailsWithFragment($episode: Episode) { hero(episode: $episode) { ...HeroDetails } } ================================================ FILE: dev-test/star-wars/HeroName.graphql ================================================ query HeroName($episode: Episode) { hero(episode: $episode) { name } } ================================================ FILE: dev-test/star-wars/HeroNameConditional.graphql ================================================ query HeroNameConditionalInclusion($episode: Episode, $includeName: Boolean!) { hero(episode: $episode) { name @include(if: $includeName) } } query HeroNameConditionalExclusion($episode: Episode, $skipName: Boolean!) { hero(episode: $episode) { name @skip(if: $skipName) } } ================================================ FILE: dev-test/star-wars/HeroParentTypeDependentField.graphql ================================================ query HeroParentTypeDependentField($episode: Episode) { hero(episode: $episode) { name ... on Human { friends { name ... on Human { height(unit: FOOT) } } } ... on Droid { friends { name ... on Human { height(unit: METER) } } } } } ================================================ FILE: dev-test/star-wars/HeroTypeDependentAliasedField.graphql ================================================ query HeroTypeDependentAliasedField($episode: Episode) { hero(episode: $episode) { ... on Human { property: homePlanet } ... on Droid { property: primaryFunction } } } ================================================ FILE: dev-test/star-wars/HumanFields.graphql ================================================ fragment HumanFields on Human { name mass } ================================================ FILE: dev-test/star-wars/HumanWithNullWeight.graphql ================================================ query HumanWithNullHeight { human(id: 1004) { ...HumanFields } } ================================================ FILE: dev-test/star-wars/TwoHeroes.graphql ================================================ query TwoHeroes { r2: hero { name } luke: hero(episode: EMPIRE) { name } } ================================================ FILE: dev-test/star-wars/schema.json ================================================ { "data": { "__schema": { "queryType": { "name": "Query" }, "mutationType": { "name": "Mutation" }, "subscriptionType": null, "types": [ { "kind": "OBJECT", "name": "Query", "description": "The query type, represents all of the entry points into our object graph", "fields": [ { "name": "hero", "description": "", "args": [ { "name": "episode", "description": "", "type": { "kind": "ENUM", "name": "Episode", "ofType": null }, "defaultValue": null } ], "type": { "kind": "INTERFACE", "name": "Character", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reviews", "description": "", "args": [ { "name": "episode", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "Episode", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Review", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "search", "description": "", "args": [ { "name": "text", "description": "", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "UNION", "name": "SearchResult", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "character", "description": "", "args": [ { "name": "id", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "INTERFACE", "name": "Character", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "droid", "description": "", "args": [ { "name": "id", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Droid", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "human", "description": "", "args": [ { "name": "id", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Human", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "starship", "description": "", "args": [ { "name": "id", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Starship", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "Episode", "description": "The episodes in the Star Wars trilogy", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "NEWHOPE", "description": "Star Wars Episode IV: A New Hope, released in 1977.", "isDeprecated": false, "deprecationReason": null }, { "name": "EMPIRE", "description": "Star Wars Episode V: The Empire Strikes Back, released in 1980.", "isDeprecated": false, "deprecationReason": null }, { "name": "JEDI", "description": "Star Wars Episode VI: Return of the Jedi, released in 1983.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INTERFACE", "name": "Character", "description": "A character from the Star Wars universe", "fields": [ { "name": "id", "description": "The ID of the character", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The name of the character", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "friends", "description": "The friends of the character, or an empty list if they have none", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "INTERFACE", "name": "Character", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "friendsConnection", "description": "The friends of the character exposed as a connection with edges", "args": [ { "name": "first", "description": "", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "FriendsConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "appearsIn", "description": "The movies this character appears in", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "Episode", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Human", "ofType": null }, { "kind": "OBJECT", "name": "Droid", "ofType": null } ] }, { "kind": "SCALAR", "name": "ID", "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "String", "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "Int", "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "FriendsConnection", "description": "A connection object for a character's friends", "fields": [ { "name": "totalCount", "description": "The total number of friends", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "edges", "description": "The edges for each of the character's friends.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "FriendsEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "friends", "description": "A list of the friends, as a convenience when edges are not needed.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "INTERFACE", "name": "Character", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information for paginating this connection", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "FriendsEdge", "description": "An edge object for a character's friends", "fields": [ { "name": "cursor", "description": "A cursor used for pagination", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The character represented by this friendship edge", "args": [], "type": { "kind": "INTERFACE", "name": "Character", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PageInfo", "description": "Information for paginating this connection", "fields": [ { "name": "startCursor", "description": "", "args": [], "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "endCursor", "description": "", "args": [], "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasNextPage", "description": "", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "Boolean", "description": "The `Boolean` scalar type represents `true` or `false`.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Review", "description": "Represents a review for a movie", "fields": [ { "name": "stars", "description": "The number of stars this review gave, 1-5", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commentary", "description": "Comment about the movie", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "SearchResult", "description": "", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Human", "ofType": null }, { "kind": "OBJECT", "name": "Droid", "ofType": null }, { "kind": "OBJECT", "name": "Starship", "ofType": null } ] }, { "kind": "OBJECT", "name": "Human", "description": "A humanoid creature from the Star Wars universe", "fields": [ { "name": "id", "description": "The ID of the human", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "What this human calls themselves", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "homePlanet", "description": "The home planet of the human, or null if unknown", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "height", "description": "Height in the preferred unit, default is meters", "args": [ { "name": "unit", "description": "", "type": { "kind": "ENUM", "name": "LengthUnit", "ofType": null }, "defaultValue": "METER" } ], "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mass", "description": "Mass in kilograms, or null if unknown", "args": [], "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "friends", "description": "This human's friends, or an empty list if they have none", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "INTERFACE", "name": "Character", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "friendsConnection", "description": "The friends of the human exposed as a connection with edges", "args": [ { "name": "first", "description": "", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "FriendsConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "appearsIn", "description": "The movies this human appears in", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "Episode", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "starships", "description": "A list of starships this person has piloted, or an empty list if none", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Starship", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Character", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "LengthUnit", "description": "Units of height", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "METER", "description": "The standard unit around the world", "isDeprecated": false, "deprecationReason": null }, { "name": "FOOT", "description": "Primarily used in the United States", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "SCALAR", "name": "Float", "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Starship", "description": "", "fields": [ { "name": "id", "description": "The ID of the starship", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The name of the starship", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "length", "description": "Length of the starship, along the longest axis", "args": [ { "name": "unit", "description": "", "type": { "kind": "ENUM", "name": "LengthUnit", "ofType": null }, "defaultValue": "METER" } ], "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Droid", "description": "An autonomous mechanical character in the Star Wars universe", "fields": [ { "name": "id", "description": "The ID of the droid", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "What others call this droid", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "friends", "description": "This droid's friends, or an empty list if they have none", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "INTERFACE", "name": "Character", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "friendsConnection", "description": "The friends of the droid exposed as a connection with edges", "args": [ { "name": "first", "description": "", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "FriendsConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "appearsIn", "description": "The movies this droid appears in", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "Episode", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "primaryFunction", "description": "This droid's primary function", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Character", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Mutation", "description": "The mutation type, represents all updates we can make to our data", "fields": [ { "name": "createReview", "description": "", "args": [ { "name": "episode", "description": "", "type": { "kind": "ENUM", "name": "Episode", "ofType": null }, "defaultValue": null }, { "name": "review", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ReviewInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Review", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ReviewInput", "description": "The input object sent when someone is creating a new review", "fields": null, "inputFields": [ { "name": "stars", "description": "0-5 stars", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null }, { "name": "commentary", "description": "Comment about the movie, optional", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "favoriteColor", "description": "Favorite color, optional", "type": { "kind": "INPUT_OBJECT", "name": "ColorInput", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ColorInput", "description": "The input object sent when passing a color", "fields": null, "inputFields": [ { "name": "red", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null }, { "name": "green", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null }, { "name": "blue", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Schema", "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", "fields": [ { "name": "types", "description": "A list of all types supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "queryType", "description": "The type that query operations will be rooted at.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mutationType", "description": "If this server supports mutation, the type that mutation operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "subscriptionType", "description": "If this server support subscription, the type that subscription operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "directives", "description": "A list of all directives supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Type", "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", "fields": [ { "name": "kind", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "fields", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "interfaces", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "possibleTypes", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "enumValues", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "inputFields", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ofType", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__TypeKind", "description": "An enum describing what kind of type a given `__Type` is.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "SCALAR", "description": "Indicates this type is a scalar.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Indicates this type is a union. `possibleTypes` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Indicates this type is an enum. `enumValues` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Indicates this type is an input object. `inputFields` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "LIST", "description": "Indicates this type is a list. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "NON_NULL", "description": "Indicates this type is a non-null. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "__Field", "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__InputValue", "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "defaultValue", "description": "A GraphQL-formatted string representing the default value for this input value.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__EnumValue", "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Directive", "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "locations", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "onOperation", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onFragment", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onField", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__DirectiveLocation", "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "QUERY", "description": "Location adjacent to a query operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "MUTATION", "description": "Location adjacent to a mutation operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "SUBSCRIPTION", "description": "Location adjacent to a subscription operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD", "description": "Location adjacent to a field.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_DEFINITION", "description": "Location adjacent to a fragment definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_SPREAD", "description": "Location adjacent to a fragment spread.", "isDeprecated": false, "deprecationReason": null }, { "name": "INLINE_FRAGMENT", "description": "Location adjacent to an inline fragment.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCHEMA", "description": "Location adjacent to a schema definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCALAR", "description": "Location adjacent to a scalar definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Location adjacent to an object type definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD_DEFINITION", "description": "Location adjacent to a field definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ARGUMENT_DEFINITION", "description": "Location adjacent to an argument definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Location adjacent to an interface definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Location adjacent to a union definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Location adjacent to an enum definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM_VALUE", "description": "Location adjacent to an enum value definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Location adjacent to an input object type definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_FIELD_DEFINITION", "description": "Location adjacent to an input object field definition.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null } ], "directives": [ { "name": "skip", "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Skipped when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ] }, { "name": "include", "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Included when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ] }, { "name": "deprecated", "description": "Marks an element of a GraphQL schema as no longer supported.", "locations": ["FIELD_DEFINITION", "ENUM_VALUE"], "args": [ { "name": "reason", "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": "\"No longer supported\"" } ] } ] } } } ================================================ FILE: dev-test/star-wars/types.OnlyEnums.ts ================================================ /** The episodes in the Star Wars trilogy */ export enum Episode { /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ Empire = 'EMPIRE', /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ Jedi = 'JEDI', /** Star Wars Episode IV: A New Hope, released in 1977. */ Newhope = 'NEWHOPE', } /** Units of height */ export enum LengthUnit { /** Primarily used in the United States */ Foot = 'FOOT', /** The standard unit around the world */ Meter = 'METER', } ================================================ FILE: dev-test/star-wars/types.avoidOptionals.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A character from the Star Wars universe */ export type Character = { /** The movies this character appears in */ appearsIn: Array>; /** The friends of the character, or an empty list if they have none */ friends: Maybe>>; /** The friends of the character exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the character */ id: Scalars['ID']['output']; /** The name of the character */ name: Scalars['String']['output']; }; /** A character from the Star Wars universe */ export type CharacterFriendsConnectionArgs = { after: InputMaybe; first: InputMaybe; }; /** The input object sent when passing a color */ export type ColorInput = { blue: Scalars['Int']['input']; green: Scalars['Int']['input']; red: Scalars['Int']['input']; }; /** An autonomous mechanical character in the Star Wars universe */ export type Droid = Character & { __typename?: 'Droid'; /** The movies this droid appears in */ appearsIn: Array>; /** This droid's friends, or an empty list if they have none */ friends: Maybe>>; /** The friends of the droid exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the droid */ id: Scalars['ID']['output']; /** What others call this droid */ name: Scalars['String']['output']; /** This droid's primary function */ primaryFunction: Maybe; }; /** An autonomous mechanical character in the Star Wars universe */ export type DroidFriendsConnectionArgs = { after: InputMaybe; first: InputMaybe; }; /** The episodes in the Star Wars trilogy */ export enum Episode { /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ Empire = 'EMPIRE', /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ Jedi = 'JEDI', /** Star Wars Episode IV: A New Hope, released in 1977. */ Newhope = 'NEWHOPE', } /** A connection object for a character's friends */ export type FriendsConnection = { __typename?: 'FriendsConnection'; /** The edges for each of the character's friends. */ edges: Maybe>>; /** A list of the friends, as a convenience when edges are not needed. */ friends: Maybe>>; /** Information for paginating this connection */ pageInfo: PageInfo; /** The total number of friends */ totalCount: Maybe; }; /** An edge object for a character's friends */ export type FriendsEdge = { __typename?: 'FriendsEdge'; /** A cursor used for pagination */ cursor: Scalars['ID']['output']; /** The character represented by this friendship edge */ node: Maybe; }; /** A humanoid creature from the Star Wars universe */ export type Human = Character & { __typename?: 'Human'; /** The movies this human appears in */ appearsIn: Array>; /** This human's friends, or an empty list if they have none */ friends: Maybe>>; /** The friends of the human exposed as a connection with edges */ friendsConnection: FriendsConnection; /** Height in the preferred unit, default is meters */ height: Maybe; /** The home planet of the human, or null if unknown */ homePlanet: Maybe; /** The ID of the human */ id: Scalars['ID']['output']; /** Mass in kilograms, or null if unknown */ mass: Maybe; /** What this human calls themselves */ name: Scalars['String']['output']; /** A list of starships this person has piloted, or an empty list if none */ starships: Maybe>>; }; /** A humanoid creature from the Star Wars universe */ export type HumanFriendsConnectionArgs = { after: InputMaybe; first: InputMaybe; }; /** A humanoid creature from the Star Wars universe */ export type HumanHeightArgs = { unit?: InputMaybe; }; /** Units of height */ export enum LengthUnit { /** Primarily used in the United States */ Foot = 'FOOT', /** The standard unit around the world */ Meter = 'METER', } /** The mutation type, represents all updates we can make to our data */ export type Mutation = { __typename?: 'Mutation'; createReview: Maybe; }; /** The mutation type, represents all updates we can make to our data */ export type MutationCreateReviewArgs = { episode: InputMaybe; review: ReviewInput; }; /** Information for paginating this connection */ export type PageInfo = { __typename?: 'PageInfo'; endCursor: Maybe; hasNextPage: Scalars['Boolean']['output']; startCursor: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type Query = { __typename?: 'Query'; character: Maybe; droid: Maybe; hero: Maybe; human: Maybe; reviews: Maybe>>; search: Maybe>>; starship: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryCharacterArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryDroidArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHeroArgs = { episode: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHumanArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryReviewsArgs = { episode: Episode; }; /** The query type, represents all of the entry points into our object graph */ export type QuerySearchArgs = { text: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryStarshipArgs = { id: Scalars['ID']['input']; }; /** Represents a review for a movie */ export type Review = { __typename?: 'Review'; /** Comment about the movie */ commentary: Maybe; /** The number of stars this review gave, 1-5 */ stars: Scalars['Int']['output']; }; /** The input object sent when someone is creating a new review */ export type ReviewInput = { /** Comment about the movie, optional */ commentary: InputMaybe; /** Favorite color, optional */ favoriteColor: InputMaybe; /** 0-5 stars */ stars: Scalars['Int']['input']; }; export type SearchResult = Droid | Human | Starship; export type Starship = { __typename?: 'Starship'; /** The ID of the starship */ id: Scalars['ID']['output']; /** Length of the starship, along the longest axis */ length: Maybe; /** The name of the starship */ name: Scalars['String']['output']; }; export type StarshipLengthArgs = { unit?: InputMaybe; }; export type CreateReviewForEpisodeMutationVariables = Exact<{ episode: Episode; review: ReviewInput; }>; export type CreateReviewForEpisodeMutation = { __typename?: 'Mutation'; createReview: { __typename?: 'Review'; stars: number; commentary: string | null } | null; }; export type ExcludeQueryAlphaQueryVariables = Exact<{ episode: InputMaybe; }>; export type ExcludeQueryAlphaQuery = { __typename?: 'Query'; hero: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type ExcludeQueryBetaQueryVariables = Exact<{ episode: InputMaybe; }>; export type ExcludeQueryBetaQuery = { __typename?: 'Query'; hero: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroAndFriendsNamesQueryVariables = Exact<{ episode: InputMaybe; }>; export type HeroAndFriendsNamesQuery = { __typename?: 'Query'; hero: | { __typename?: 'Droid'; name: string; friends: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | { __typename?: 'Human'; name: string; friends: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | null; }; export type HeroAppearsInQueryVariables = Exact<{ [key: string]: never }>; export type HeroAppearsInQuery = { __typename?: 'Query'; hero: | { __typename?: 'Droid'; name: string; appearsIn: Array } | { __typename?: 'Human'; name: string; appearsIn: Array } | null; }; export type HeroDetailsQueryVariables = Exact<{ episode: InputMaybe; }>; export type HeroDetailsQuery = { __typename?: 'Query'; hero: | { __typename?: 'Droid'; primaryFunction: string | null; name: string } | { __typename?: 'Human'; height: number | null; name: string } | null; }; type HeroDetails_Droid_Fragment = { __typename?: 'Droid'; primaryFunction: string | null; name: string }; type HeroDetails_Human_Fragment = { __typename?: 'Human'; height: number | null; name: string }; export type HeroDetailsFragment = HeroDetails_Droid_Fragment | HeroDetails_Human_Fragment; export type HeroDetailsWithFragmentQueryVariables = Exact<{ episode: InputMaybe; }>; export type HeroDetailsWithFragmentQuery = { __typename?: 'Query'; hero: | { __typename?: 'Droid'; primaryFunction: string | null; name: string } | { __typename?: 'Human'; height: number | null; name: string } | null; }; export type HeroNameQueryVariables = Exact<{ episode: InputMaybe; }>; export type HeroNameQuery = { __typename?: 'Query'; hero: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroNameConditionalInclusionQueryVariables = Exact<{ episode: InputMaybe; includeName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalInclusionQuery = { __typename?: 'Query'; hero: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroNameConditionalExclusionQueryVariables = Exact<{ episode: InputMaybe; skipName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalExclusionQuery = { __typename?: 'Query'; hero: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroParentTypeDependentFieldQueryVariables = Exact<{ episode: InputMaybe; }>; export type HeroParentTypeDependentFieldQuery = { __typename?: 'Query'; hero: | { __typename?: 'Droid'; name: string; friends: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height: number | null; name: string } | null > | null; } | { __typename?: 'Human'; name: string; friends: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height: number | null; name: string } | null > | null; } | null; }; export type HeroTypeDependentAliasedFieldQueryVariables = Exact<{ episode: InputMaybe; }>; export type HeroTypeDependentAliasedFieldQuery = { __typename?: 'Query'; hero: { __typename?: 'Droid'; property: string | null } | { __typename?: 'Human'; property: string | null } | null; }; export type HumanFieldsFragment = { __typename?: 'Human'; name: string; mass: number | null }; export type HumanWithNullHeightQueryVariables = Exact<{ [key: string]: never }>; export type HumanWithNullHeightQuery = { __typename?: 'Query'; human: { __typename?: 'Human'; name: string; mass: number | null } | null; }; export type TwoHeroesQueryVariables = Exact<{ [key: string]: never }>; export type TwoHeroesQuery = { __typename?: 'Query'; r2: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; luke: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; ================================================ FILE: dev-test/star-wars/types.d.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A character from the Star Wars universe */ export type Character = { /** The movies this character appears in */ appearsIn: Array>; /** The friends of the character, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the character exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the character */ id: Scalars['ID']['output']; /** The name of the character */ name: Scalars['String']['output']; }; /** A character from the Star Wars universe */ export type CharacterFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The input object sent when passing a color */ export type ColorInput = { blue: Scalars['Int']['input']; green: Scalars['Int']['input']; red: Scalars['Int']['input']; }; /** An autonomous mechanical character in the Star Wars universe */ export type Droid = Character & { __typename?: 'Droid'; /** The movies this droid appears in */ appearsIn: Array>; /** This droid's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the droid exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the droid */ id: Scalars['ID']['output']; /** What others call this droid */ name: Scalars['String']['output']; /** This droid's primary function */ primaryFunction?: Maybe; }; /** An autonomous mechanical character in the Star Wars universe */ export type DroidFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The episodes in the Star Wars trilogy */ export type Episode = /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ | 'EMPIRE' /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ | 'JEDI' /** Star Wars Episode IV: A New Hope, released in 1977. */ | 'NEWHOPE'; /** A connection object for a character's friends */ export type FriendsConnection = { __typename?: 'FriendsConnection'; /** The edges for each of the character's friends. */ edges?: Maybe>>; /** A list of the friends, as a convenience when edges are not needed. */ friends?: Maybe>>; /** Information for paginating this connection */ pageInfo: PageInfo; /** The total number of friends */ totalCount?: Maybe; }; /** An edge object for a character's friends */ export type FriendsEdge = { __typename?: 'FriendsEdge'; /** A cursor used for pagination */ cursor: Scalars['ID']['output']; /** The character represented by this friendship edge */ node?: Maybe; }; /** A humanoid creature from the Star Wars universe */ export type Human = Character & { __typename?: 'Human'; /** The movies this human appears in */ appearsIn: Array>; /** This human's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the human exposed as a connection with edges */ friendsConnection: FriendsConnection; /** Height in the preferred unit, default is meters */ height?: Maybe; /** The home planet of the human, or null if unknown */ homePlanet?: Maybe; /** The ID of the human */ id: Scalars['ID']['output']; /** Mass in kilograms, or null if unknown */ mass?: Maybe; /** What this human calls themselves */ name: Scalars['String']['output']; /** A list of starships this person has piloted, or an empty list if none */ starships?: Maybe>>; }; /** A humanoid creature from the Star Wars universe */ export type HumanFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** A humanoid creature from the Star Wars universe */ export type HumanHeightArgs = { unit?: InputMaybe; }; /** Units of height */ export type LengthUnit = /** Primarily used in the United States */ | 'FOOT' /** The standard unit around the world */ | 'METER'; /** The mutation type, represents all updates we can make to our data */ export type Mutation = { __typename?: 'Mutation'; createReview?: Maybe; }; /** The mutation type, represents all updates we can make to our data */ export type MutationCreateReviewArgs = { episode?: InputMaybe; review: ReviewInput; }; /** Information for paginating this connection */ export type PageInfo = { __typename?: 'PageInfo'; endCursor?: Maybe; hasNextPage: Scalars['Boolean']['output']; startCursor?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type Query = { __typename?: 'Query'; character?: Maybe; droid?: Maybe; hero?: Maybe; human?: Maybe; reviews?: Maybe>>; search?: Maybe>>; starship?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryCharacterArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryDroidArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHeroArgs = { episode?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHumanArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryReviewsArgs = { episode: Episode; }; /** The query type, represents all of the entry points into our object graph */ export type QuerySearchArgs = { text?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryStarshipArgs = { id: Scalars['ID']['input']; }; /** Represents a review for a movie */ export type Review = { __typename?: 'Review'; /** Comment about the movie */ commentary?: Maybe; /** The number of stars this review gave, 1-5 */ stars: Scalars['Int']['output']; }; /** The input object sent when someone is creating a new review */ export type ReviewInput = { /** Comment about the movie, optional */ commentary?: InputMaybe; /** Favorite color, optional */ favoriteColor?: InputMaybe; /** 0-5 stars */ stars: Scalars['Int']['input']; }; export type SearchResult = Droid | Human | Starship; export type Starship = { __typename?: 'Starship'; /** The ID of the starship */ id: Scalars['ID']['output']; /** Length of the starship, along the longest axis */ length?: Maybe; /** The name of the starship */ name: Scalars['String']['output']; }; export type StarshipLengthArgs = { unit?: InputMaybe; }; ================================================ FILE: dev-test/star-wars/types.excludeQueryAlpha.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A character from the Star Wars universe */ export type Character = { /** The movies this character appears in */ appearsIn: Array>; /** The friends of the character, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the character exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the character */ id: Scalars['ID']['output']; /** The name of the character */ name: Scalars['String']['output']; }; /** A character from the Star Wars universe */ export type CharacterFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The input object sent when passing a color */ export type ColorInput = { blue: Scalars['Int']['input']; green: Scalars['Int']['input']; red: Scalars['Int']['input']; }; /** An autonomous mechanical character in the Star Wars universe */ export type Droid = Character & { __typename?: 'Droid'; /** The movies this droid appears in */ appearsIn: Array>; /** This droid's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the droid exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the droid */ id: Scalars['ID']['output']; /** What others call this droid */ name: Scalars['String']['output']; /** This droid's primary function */ primaryFunction?: Maybe; }; /** An autonomous mechanical character in the Star Wars universe */ export type DroidFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The episodes in the Star Wars trilogy */ export enum Episode { /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ Empire = 'EMPIRE', /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ Jedi = 'JEDI', /** Star Wars Episode IV: A New Hope, released in 1977. */ Newhope = 'NEWHOPE', } /** A connection object for a character's friends */ export type FriendsConnection = { __typename?: 'FriendsConnection'; /** The edges for each of the character's friends. */ edges?: Maybe>>; /** A list of the friends, as a convenience when edges are not needed. */ friends?: Maybe>>; /** Information for paginating this connection */ pageInfo: PageInfo; /** The total number of friends */ totalCount?: Maybe; }; /** An edge object for a character's friends */ export type FriendsEdge = { __typename?: 'FriendsEdge'; /** A cursor used for pagination */ cursor: Scalars['ID']['output']; /** The character represented by this friendship edge */ node?: Maybe; }; /** A humanoid creature from the Star Wars universe */ export type Human = Character & { __typename?: 'Human'; /** The movies this human appears in */ appearsIn: Array>; /** This human's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the human exposed as a connection with edges */ friendsConnection: FriendsConnection; /** Height in the preferred unit, default is meters */ height?: Maybe; /** The home planet of the human, or null if unknown */ homePlanet?: Maybe; /** The ID of the human */ id: Scalars['ID']['output']; /** Mass in kilograms, or null if unknown */ mass?: Maybe; /** What this human calls themselves */ name: Scalars['String']['output']; /** A list of starships this person has piloted, or an empty list if none */ starships?: Maybe>>; }; /** A humanoid creature from the Star Wars universe */ export type HumanFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** A humanoid creature from the Star Wars universe */ export type HumanHeightArgs = { unit?: InputMaybe; }; /** Units of height */ export enum LengthUnit { /** Primarily used in the United States */ Foot = 'FOOT', /** The standard unit around the world */ Meter = 'METER', } /** The mutation type, represents all updates we can make to our data */ export type Mutation = { __typename?: 'Mutation'; createReview?: Maybe; }; /** The mutation type, represents all updates we can make to our data */ export type MutationCreateReviewArgs = { episode?: InputMaybe; review: ReviewInput; }; /** Information for paginating this connection */ export type PageInfo = { __typename?: 'PageInfo'; endCursor?: Maybe; hasNextPage: Scalars['Boolean']['output']; startCursor?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type Query = { __typename?: 'Query'; character?: Maybe; droid?: Maybe; hero?: Maybe; human?: Maybe; reviews?: Maybe>>; search?: Maybe>>; starship?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryCharacterArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryDroidArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHeroArgs = { episode?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHumanArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryReviewsArgs = { episode: Episode; }; /** The query type, represents all of the entry points into our object graph */ export type QuerySearchArgs = { text?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryStarshipArgs = { id: Scalars['ID']['input']; }; /** Represents a review for a movie */ export type Review = { __typename?: 'Review'; /** Comment about the movie */ commentary?: Maybe; /** The number of stars this review gave, 1-5 */ stars: Scalars['Int']['output']; }; /** The input object sent when someone is creating a new review */ export type ReviewInput = { /** Comment about the movie, optional */ commentary?: InputMaybe; /** Favorite color, optional */ favoriteColor?: InputMaybe; /** 0-5 stars */ stars: Scalars['Int']['input']; }; export type SearchResult = Droid | Human | Starship; export type Starship = { __typename?: 'Starship'; /** The ID of the starship */ id: Scalars['ID']['output']; /** Length of the starship, along the longest axis */ length?: Maybe; /** The name of the starship */ name: Scalars['String']['output']; }; export type StarshipLengthArgs = { unit?: InputMaybe; }; export type CreateReviewForEpisodeMutationVariables = Exact<{ episode: Episode; review: ReviewInput; }>; export type CreateReviewForEpisodeMutation = { __typename?: 'Mutation'; createReview?: { __typename?: 'Review'; stars: number; commentary?: string | null } | null; }; export type ExcludeQueryBetaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryBetaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroAndFriendsNamesQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroAndFriendsNamesQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | { __typename?: 'Human'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | null; }; export type HeroAppearsInQueryVariables = Exact<{ [key: string]: never }>; export type HeroAppearsInQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; appearsIn: Array } | { __typename?: 'Human'; name: string; appearsIn: Array } | null; }; export type HeroDetailsQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; type HeroDetails_Droid_Fragment = { __typename?: 'Droid'; primaryFunction?: string | null; name: string }; type HeroDetails_Human_Fragment = { __typename?: 'Human'; height?: number | null; name: string }; export type HeroDetailsFragment = HeroDetails_Droid_Fragment | HeroDetails_Human_Fragment; export type HeroDetailsWithFragmentQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsWithFragmentQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; export type HeroNameQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroNameQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroNameConditionalInclusionQueryVariables = Exact<{ episode?: InputMaybe; includeName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalInclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroNameConditionalExclusionQueryVariables = Exact<{ episode?: InputMaybe; skipName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalExclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroParentTypeDependentFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroParentTypeDependentFieldQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | { __typename?: 'Human'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | null; }; export type HeroTypeDependentAliasedFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroTypeDependentAliasedFieldQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; property?: string | null } | { __typename?: 'Human'; property?: string | null } | null; }; export type HumanFieldsFragment = { __typename?: 'Human'; name: string; mass?: number | null }; export type HumanWithNullHeightQueryVariables = Exact<{ [key: string]: never }>; export type HumanWithNullHeightQuery = { __typename?: 'Query'; human?: { __typename?: 'Human'; name: string; mass?: number | null } | null; }; export type TwoHeroesQueryVariables = Exact<{ [key: string]: never }>; export type TwoHeroesQuery = { __typename?: 'Query'; r2?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; luke?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; ================================================ FILE: dev-test/star-wars/types.excludeQueryBeta.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A character from the Star Wars universe */ export type Character = { /** The movies this character appears in */ appearsIn: Array>; /** The friends of the character, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the character exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the character */ id: Scalars['ID']['output']; /** The name of the character */ name: Scalars['String']['output']; }; /** A character from the Star Wars universe */ export type CharacterFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The input object sent when passing a color */ export type ColorInput = { blue: Scalars['Int']['input']; green: Scalars['Int']['input']; red: Scalars['Int']['input']; }; /** An autonomous mechanical character in the Star Wars universe */ export type Droid = Character & { __typename?: 'Droid'; /** The movies this droid appears in */ appearsIn: Array>; /** This droid's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the droid exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the droid */ id: Scalars['ID']['output']; /** What others call this droid */ name: Scalars['String']['output']; /** This droid's primary function */ primaryFunction?: Maybe; }; /** An autonomous mechanical character in the Star Wars universe */ export type DroidFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The episodes in the Star Wars trilogy */ export enum Episode { /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ Empire = 'EMPIRE', /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ Jedi = 'JEDI', /** Star Wars Episode IV: A New Hope, released in 1977. */ Newhope = 'NEWHOPE', } /** A connection object for a character's friends */ export type FriendsConnection = { __typename?: 'FriendsConnection'; /** The edges for each of the character's friends. */ edges?: Maybe>>; /** A list of the friends, as a convenience when edges are not needed. */ friends?: Maybe>>; /** Information for paginating this connection */ pageInfo: PageInfo; /** The total number of friends */ totalCount?: Maybe; }; /** An edge object for a character's friends */ export type FriendsEdge = { __typename?: 'FriendsEdge'; /** A cursor used for pagination */ cursor: Scalars['ID']['output']; /** The character represented by this friendship edge */ node?: Maybe; }; /** A humanoid creature from the Star Wars universe */ export type Human = Character & { __typename?: 'Human'; /** The movies this human appears in */ appearsIn: Array>; /** This human's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the human exposed as a connection with edges */ friendsConnection: FriendsConnection; /** Height in the preferred unit, default is meters */ height?: Maybe; /** The home planet of the human, or null if unknown */ homePlanet?: Maybe; /** The ID of the human */ id: Scalars['ID']['output']; /** Mass in kilograms, or null if unknown */ mass?: Maybe; /** What this human calls themselves */ name: Scalars['String']['output']; /** A list of starships this person has piloted, or an empty list if none */ starships?: Maybe>>; }; /** A humanoid creature from the Star Wars universe */ export type HumanFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** A humanoid creature from the Star Wars universe */ export type HumanHeightArgs = { unit?: InputMaybe; }; /** Units of height */ export enum LengthUnit { /** Primarily used in the United States */ Foot = 'FOOT', /** The standard unit around the world */ Meter = 'METER', } /** The mutation type, represents all updates we can make to our data */ export type Mutation = { __typename?: 'Mutation'; createReview?: Maybe; }; /** The mutation type, represents all updates we can make to our data */ export type MutationCreateReviewArgs = { episode?: InputMaybe; review: ReviewInput; }; /** Information for paginating this connection */ export type PageInfo = { __typename?: 'PageInfo'; endCursor?: Maybe; hasNextPage: Scalars['Boolean']['output']; startCursor?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type Query = { __typename?: 'Query'; character?: Maybe; droid?: Maybe; hero?: Maybe; human?: Maybe; reviews?: Maybe>>; search?: Maybe>>; starship?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryCharacterArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryDroidArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHeroArgs = { episode?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHumanArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryReviewsArgs = { episode: Episode; }; /** The query type, represents all of the entry points into our object graph */ export type QuerySearchArgs = { text?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryStarshipArgs = { id: Scalars['ID']['input']; }; /** Represents a review for a movie */ export type Review = { __typename?: 'Review'; /** Comment about the movie */ commentary?: Maybe; /** The number of stars this review gave, 1-5 */ stars: Scalars['Int']['output']; }; /** The input object sent when someone is creating a new review */ export type ReviewInput = { /** Comment about the movie, optional */ commentary?: InputMaybe; /** Favorite color, optional */ favoriteColor?: InputMaybe; /** 0-5 stars */ stars: Scalars['Int']['input']; }; export type SearchResult = Droid | Human | Starship; export type Starship = { __typename?: 'Starship'; /** The ID of the starship */ id: Scalars['ID']['output']; /** Length of the starship, along the longest axis */ length?: Maybe; /** The name of the starship */ name: Scalars['String']['output']; }; export type StarshipLengthArgs = { unit?: InputMaybe; }; export type CreateReviewForEpisodeMutationVariables = Exact<{ episode: Episode; review: ReviewInput; }>; export type CreateReviewForEpisodeMutation = { __typename?: 'Mutation'; createReview?: { __typename?: 'Review'; stars: number; commentary?: string | null } | null; }; export type ExcludeQueryAlphaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryAlphaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroAndFriendsNamesQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroAndFriendsNamesQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | { __typename?: 'Human'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | null; }; export type HeroAppearsInQueryVariables = Exact<{ [key: string]: never }>; export type HeroAppearsInQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; appearsIn: Array } | { __typename?: 'Human'; name: string; appearsIn: Array } | null; }; export type HeroDetailsQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; type HeroDetails_Droid_Fragment = { __typename?: 'Droid'; primaryFunction?: string | null; name: string }; type HeroDetails_Human_Fragment = { __typename?: 'Human'; height?: number | null; name: string }; export type HeroDetailsFragment = HeroDetails_Droid_Fragment | HeroDetails_Human_Fragment; export type HeroDetailsWithFragmentQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsWithFragmentQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; export type HeroNameQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroNameQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroNameConditionalInclusionQueryVariables = Exact<{ episode?: InputMaybe; includeName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalInclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroNameConditionalExclusionQueryVariables = Exact<{ episode?: InputMaybe; skipName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalExclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroParentTypeDependentFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroParentTypeDependentFieldQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | { __typename?: 'Human'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | null; }; export type HeroTypeDependentAliasedFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroTypeDependentAliasedFieldQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; property?: string | null } | { __typename?: 'Human'; property?: string | null } | null; }; export type HumanFieldsFragment = { __typename?: 'Human'; name: string; mass?: number | null }; export type HumanWithNullHeightQueryVariables = Exact<{ [key: string]: never }>; export type HumanWithNullHeightQuery = { __typename?: 'Query'; human?: { __typename?: 'Human'; name: string; mass?: number | null } | null; }; export type TwoHeroesQueryVariables = Exact<{ [key: string]: never }>; export type TwoHeroesQuery = { __typename?: 'Query'; r2?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; luke?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; ================================================ FILE: dev-test/star-wars/types.globallyAvailable.d.ts ================================================ type Maybe = T | null; type InputMaybe = Maybe; type Exact = { [K in keyof T]: T[K] }; type MakeOptional = Omit & { [SubKey in K]?: Maybe }; type MakeMaybe = Omit & { [SubKey in K]: Maybe }; type MakeEmpty = { [_ in K]?: never }; type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A character from the Star Wars universe */ type Character = { /** The movies this character appears in */ appearsIn: Array>; /** The friends of the character, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the character exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the character */ id: Scalars['ID']['output']; /** The name of the character */ name: Scalars['String']['output']; }; /** A character from the Star Wars universe */ type CharacterFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The input object sent when passing a color */ type ColorInput = { blue: Scalars['Int']['input']; green: Scalars['Int']['input']; red: Scalars['Int']['input']; }; /** An autonomous mechanical character in the Star Wars universe */ type Droid = Character & { __typename?: 'Droid'; /** The movies this droid appears in */ appearsIn: Array>; /** This droid's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the droid exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the droid */ id: Scalars['ID']['output']; /** What others call this droid */ name: Scalars['String']['output']; /** This droid's primary function */ primaryFunction?: Maybe; }; /** An autonomous mechanical character in the Star Wars universe */ type DroidFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The episodes in the Star Wars trilogy */ type Episode = /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ | 'EMPIRE' /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ | 'JEDI' /** Star Wars Episode IV: A New Hope, released in 1977. */ | 'NEWHOPE'; /** A connection object for a character's friends */ type FriendsConnection = { __typename?: 'FriendsConnection'; /** The edges for each of the character's friends. */ edges?: Maybe>>; /** A list of the friends, as a convenience when edges are not needed. */ friends?: Maybe>>; /** Information for paginating this connection */ pageInfo: PageInfo; /** The total number of friends */ totalCount?: Maybe; }; /** An edge object for a character's friends */ type FriendsEdge = { __typename?: 'FriendsEdge'; /** A cursor used for pagination */ cursor: Scalars['ID']['output']; /** The character represented by this friendship edge */ node?: Maybe; }; /** A humanoid creature from the Star Wars universe */ type Human = Character & { __typename?: 'Human'; /** The movies this human appears in */ appearsIn: Array>; /** This human's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the human exposed as a connection with edges */ friendsConnection: FriendsConnection; /** Height in the preferred unit, default is meters */ height?: Maybe; /** The home planet of the human, or null if unknown */ homePlanet?: Maybe; /** The ID of the human */ id: Scalars['ID']['output']; /** Mass in kilograms, or null if unknown */ mass?: Maybe; /** What this human calls themselves */ name: Scalars['String']['output']; /** A list of starships this person has piloted, or an empty list if none */ starships?: Maybe>>; }; /** A humanoid creature from the Star Wars universe */ type HumanFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** A humanoid creature from the Star Wars universe */ type HumanHeightArgs = { unit?: InputMaybe; }; /** Units of height */ type LengthUnit = /** Primarily used in the United States */ | 'FOOT' /** The standard unit around the world */ | 'METER'; /** The mutation type, represents all updates we can make to our data */ type Mutation = { __typename?: 'Mutation'; createReview?: Maybe; }; /** The mutation type, represents all updates we can make to our data */ type MutationCreateReviewArgs = { episode?: InputMaybe; review: ReviewInput; }; /** Information for paginating this connection */ type PageInfo = { __typename?: 'PageInfo'; endCursor?: Maybe; hasNextPage: Scalars['Boolean']['output']; startCursor?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ type Query = { __typename?: 'Query'; character?: Maybe; droid?: Maybe; hero?: Maybe; human?: Maybe; reviews?: Maybe>>; search?: Maybe>>; starship?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ type QueryCharacterArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ type QueryDroidArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ type QueryHeroArgs = { episode?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ type QueryHumanArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ type QueryReviewsArgs = { episode: Episode; }; /** The query type, represents all of the entry points into our object graph */ type QuerySearchArgs = { text?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ type QueryStarshipArgs = { id: Scalars['ID']['input']; }; /** Represents a review for a movie */ type Review = { __typename?: 'Review'; /** Comment about the movie */ commentary?: Maybe; /** The number of stars this review gave, 1-5 */ stars: Scalars['Int']['output']; }; /** The input object sent when someone is creating a new review */ type ReviewInput = { /** Comment about the movie, optional */ commentary?: InputMaybe; /** Favorite color, optional */ favoriteColor?: InputMaybe; /** 0-5 stars */ stars: Scalars['Int']['input']; }; type SearchResult = Droid | Human | Starship; type Starship = { __typename?: 'Starship'; /** The ID of the starship */ id: Scalars['ID']['output']; /** Length of the starship, along the longest axis */ length?: Maybe; /** The name of the starship */ name: Scalars['String']['output']; }; type StarshipLengthArgs = { unit?: InputMaybe; }; type CreateReviewForEpisodeMutationVariables = Exact<{ episode: Episode; review: ReviewInput; }>; type CreateReviewForEpisodeMutation = { __typename?: 'Mutation'; createReview?: { __typename?: 'Review'; stars: number; commentary?: string | null } | null; }; type ExcludeQueryAlphaQueryVariables = Exact<{ episode?: InputMaybe; }>; type ExcludeQueryAlphaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; type ExcludeQueryBetaQueryVariables = Exact<{ episode?: InputMaybe; }>; type ExcludeQueryBetaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; type HeroAndFriendsNamesQueryVariables = Exact<{ episode?: InputMaybe; }>; type HeroAndFriendsNamesQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | { __typename?: 'Human'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | null; }; type HeroAppearsInQueryVariables = Exact<{ [key: string]: never }>; type HeroAppearsInQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; appearsIn: Array } | { __typename?: 'Human'; name: string; appearsIn: Array } | null; }; type HeroDetailsQueryVariables = Exact<{ episode?: InputMaybe; }>; type HeroDetailsQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; type HeroDetails_Droid_Fragment = { __typename?: 'Droid'; primaryFunction?: string | null; name: string }; type HeroDetails_Human_Fragment = { __typename?: 'Human'; height?: number | null; name: string }; type HeroDetailsFragment = HeroDetails_Droid_Fragment | HeroDetails_Human_Fragment; type HeroDetailsWithFragmentQueryVariables = Exact<{ episode?: InputMaybe; }>; type HeroDetailsWithFragmentQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; type HeroNameQueryVariables = Exact<{ episode?: InputMaybe; }>; type HeroNameQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; type HeroNameConditionalInclusionQueryVariables = Exact<{ episode?: InputMaybe; includeName: Scalars['Boolean']['input']; }>; type HeroNameConditionalInclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; type HeroNameConditionalExclusionQueryVariables = Exact<{ episode?: InputMaybe; skipName: Scalars['Boolean']['input']; }>; type HeroNameConditionalExclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; type HeroParentTypeDependentFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; type HeroParentTypeDependentFieldQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | { __typename?: 'Human'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | null; }; type HeroTypeDependentAliasedFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; type HeroTypeDependentAliasedFieldQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; property?: string | null } | { __typename?: 'Human'; property?: string | null } | null; }; type HumanFieldsFragment = { __typename?: 'Human'; name: string; mass?: number | null }; type HumanWithNullHeightQueryVariables = Exact<{ [key: string]: never }>; type HumanWithNullHeightQuery = { __typename?: 'Query'; human?: { __typename?: 'Human'; name: string; mass?: number | null } | null; }; type TwoHeroesQueryVariables = Exact<{ [key: string]: never }>; type TwoHeroesQuery = { __typename?: 'Query'; r2?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; luke?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; ================================================ FILE: dev-test/star-wars/types.immutableTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A character from the Star Wars universe */ export type Character = { /** The movies this character appears in */ readonly appearsIn: ReadonlyArray>; /** The friends of the character, or an empty list if they have none */ readonly friends?: Maybe>>; /** The friends of the character exposed as a connection with edges */ readonly friendsConnection: FriendsConnection; /** The ID of the character */ readonly id: Scalars['ID']['output']; /** The name of the character */ readonly name: Scalars['String']['output']; }; /** A character from the Star Wars universe */ export type CharacterFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The input object sent when passing a color */ export type ColorInput = { readonly blue: Scalars['Int']['input']; readonly green: Scalars['Int']['input']; readonly red: Scalars['Int']['input']; }; /** An autonomous mechanical character in the Star Wars universe */ export type Droid = Character & { readonly __typename?: 'Droid'; /** The movies this droid appears in */ readonly appearsIn: ReadonlyArray>; /** This droid's friends, or an empty list if they have none */ readonly friends?: Maybe>>; /** The friends of the droid exposed as a connection with edges */ readonly friendsConnection: FriendsConnection; /** The ID of the droid */ readonly id: Scalars['ID']['output']; /** What others call this droid */ readonly name: Scalars['String']['output']; /** This droid's primary function */ readonly primaryFunction?: Maybe; }; /** An autonomous mechanical character in the Star Wars universe */ export type DroidFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The episodes in the Star Wars trilogy */ export enum Episode { /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ Empire = 'EMPIRE', /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ Jedi = 'JEDI', /** Star Wars Episode IV: A New Hope, released in 1977. */ Newhope = 'NEWHOPE', } /** A connection object for a character's friends */ export type FriendsConnection = { readonly __typename?: 'FriendsConnection'; /** The edges for each of the character's friends. */ readonly edges?: Maybe>>; /** A list of the friends, as a convenience when edges are not needed. */ readonly friends?: Maybe>>; /** Information for paginating this connection */ readonly pageInfo: PageInfo; /** The total number of friends */ readonly totalCount?: Maybe; }; /** An edge object for a character's friends */ export type FriendsEdge = { readonly __typename?: 'FriendsEdge'; /** A cursor used for pagination */ readonly cursor: Scalars['ID']['output']; /** The character represented by this friendship edge */ readonly node?: Maybe; }; /** A humanoid creature from the Star Wars universe */ export type Human = Character & { readonly __typename?: 'Human'; /** The movies this human appears in */ readonly appearsIn: ReadonlyArray>; /** This human's friends, or an empty list if they have none */ readonly friends?: Maybe>>; /** The friends of the human exposed as a connection with edges */ readonly friendsConnection: FriendsConnection; /** Height in the preferred unit, default is meters */ readonly height?: Maybe; /** The home planet of the human, or null if unknown */ readonly homePlanet?: Maybe; /** The ID of the human */ readonly id: Scalars['ID']['output']; /** Mass in kilograms, or null if unknown */ readonly mass?: Maybe; /** What this human calls themselves */ readonly name: Scalars['String']['output']; /** A list of starships this person has piloted, or an empty list if none */ readonly starships?: Maybe>>; }; /** A humanoid creature from the Star Wars universe */ export type HumanFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** A humanoid creature from the Star Wars universe */ export type HumanHeightArgs = { unit?: InputMaybe; }; /** Units of height */ export enum LengthUnit { /** Primarily used in the United States */ Foot = 'FOOT', /** The standard unit around the world */ Meter = 'METER', } /** The mutation type, represents all updates we can make to our data */ export type Mutation = { readonly __typename?: 'Mutation'; readonly createReview?: Maybe; }; /** The mutation type, represents all updates we can make to our data */ export type MutationCreateReviewArgs = { episode?: InputMaybe; review: ReviewInput; }; /** Information for paginating this connection */ export type PageInfo = { readonly __typename?: 'PageInfo'; readonly endCursor?: Maybe; readonly hasNextPage: Scalars['Boolean']['output']; readonly startCursor?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type Query = { readonly __typename?: 'Query'; readonly character?: Maybe; readonly droid?: Maybe; readonly hero?: Maybe; readonly human?: Maybe; readonly reviews?: Maybe>>; readonly search?: Maybe>>; readonly starship?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryCharacterArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryDroidArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHeroArgs = { episode?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHumanArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryReviewsArgs = { episode: Episode; }; /** The query type, represents all of the entry points into our object graph */ export type QuerySearchArgs = { text?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryStarshipArgs = { id: Scalars['ID']['input']; }; /** Represents a review for a movie */ export type Review = { readonly __typename?: 'Review'; /** Comment about the movie */ readonly commentary?: Maybe; /** The number of stars this review gave, 1-5 */ readonly stars: Scalars['Int']['output']; }; /** The input object sent when someone is creating a new review */ export type ReviewInput = { /** Comment about the movie, optional */ readonly commentary?: InputMaybe; /** Favorite color, optional */ readonly favoriteColor?: InputMaybe; /** 0-5 stars */ readonly stars: Scalars['Int']['input']; }; export type SearchResult = Droid | Human | Starship; export type Starship = { readonly __typename?: 'Starship'; /** The ID of the starship */ readonly id: Scalars['ID']['output']; /** Length of the starship, along the longest axis */ readonly length?: Maybe; /** The name of the starship */ readonly name: Scalars['String']['output']; }; export type StarshipLengthArgs = { unit?: InputMaybe; }; export type CreateReviewForEpisodeMutationVariables = Exact<{ episode: Episode; review: ReviewInput; }>; export type CreateReviewForEpisodeMutation = { readonly __typename?: 'Mutation'; readonly createReview?: { readonly __typename?: 'Review'; readonly stars: number; readonly commentary?: string | null; } | null; }; export type ExcludeQueryAlphaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryAlphaQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly name: string } | { readonly __typename?: 'Human'; readonly name: string } | null; }; export type ExcludeQueryBetaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryBetaQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly name: string } | { readonly __typename?: 'Human'; readonly name: string } | null; }; export type HeroAndFriendsNamesQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroAndFriendsNamesQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly name: string; readonly friends?: ReadonlyArray< | { readonly __typename?: 'Droid'; readonly name: string } | { readonly __typename?: 'Human'; readonly name: string } | null > | null; } | { readonly __typename?: 'Human'; readonly name: string; readonly friends?: ReadonlyArray< | { readonly __typename?: 'Droid'; readonly name: string } | { readonly __typename?: 'Human'; readonly name: string } | null > | null; } | null; }; export type HeroAppearsInQueryVariables = Exact<{ [key: string]: never }>; export type HeroAppearsInQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly name: string; readonly appearsIn: ReadonlyArray } | { readonly __typename?: 'Human'; readonly name: string; readonly appearsIn: ReadonlyArray } | null; }; export type HeroDetailsQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly primaryFunction?: string | null; readonly name: string } | { readonly __typename?: 'Human'; readonly height?: number | null; readonly name: string } | null; }; type HeroDetails_Droid_Fragment = { readonly __typename?: 'Droid'; readonly primaryFunction?: string | null; readonly name: string; }; type HeroDetails_Human_Fragment = { readonly __typename?: 'Human'; readonly height?: number | null; readonly name: string; }; export type HeroDetailsFragment = HeroDetails_Droid_Fragment | HeroDetails_Human_Fragment; export type HeroDetailsWithFragmentQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsWithFragmentQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly primaryFunction?: string | null; readonly name: string } | { readonly __typename?: 'Human'; readonly height?: number | null; readonly name: string } | null; }; export type HeroNameQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroNameQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly name: string } | { readonly __typename?: 'Human'; readonly name: string } | null; }; export type HeroNameConditionalInclusionQueryVariables = Exact<{ episode?: InputMaybe; includeName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalInclusionQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly name?: string } | { readonly __typename?: 'Human'; readonly name?: string } | null; }; export type HeroNameConditionalExclusionQueryVariables = Exact<{ episode?: InputMaybe; skipName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalExclusionQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly name?: string } | { readonly __typename?: 'Human'; readonly name?: string } | null; }; export type HeroParentTypeDependentFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroParentTypeDependentFieldQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly name: string; readonly friends?: ReadonlyArray< | { readonly __typename?: 'Droid'; readonly name: string } | { readonly __typename?: 'Human'; readonly height?: number | null; readonly name: string } | null > | null; } | { readonly __typename?: 'Human'; readonly name: string; readonly friends?: ReadonlyArray< | { readonly __typename?: 'Droid'; readonly name: string } | { readonly __typename?: 'Human'; readonly height?: number | null; readonly name: string } | null > | null; } | null; }; export type HeroTypeDependentAliasedFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroTypeDependentAliasedFieldQuery = { readonly __typename?: 'Query'; readonly hero?: | { readonly __typename?: 'Droid'; readonly property?: string | null } | { readonly __typename?: 'Human'; readonly property?: string | null } | null; }; export type HumanFieldsFragment = { readonly __typename?: 'Human'; readonly name: string; readonly mass?: number | null; }; export type HumanWithNullHeightQueryVariables = Exact<{ [key: string]: never }>; export type HumanWithNullHeightQuery = { readonly __typename?: 'Query'; readonly human?: { readonly __typename?: 'Human'; readonly name: string; readonly mass?: number | null } | null; }; export type TwoHeroesQueryVariables = Exact<{ [key: string]: never }>; export type TwoHeroesQuery = { readonly __typename?: 'Query'; readonly r2?: | { readonly __typename?: 'Droid'; readonly name: string } | { readonly __typename?: 'Human'; readonly name: string } | null; readonly luke?: | { readonly __typename?: 'Droid'; readonly name: string } | { readonly __typename?: 'Human'; readonly name: string } | null; }; ================================================ FILE: dev-test/star-wars/types.preResolveTypes.onlyOperationTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** The input object sent when passing a color */ export type ColorInput = { blue: Scalars['Int']['input']; green: Scalars['Int']['input']; red: Scalars['Int']['input']; }; /** The episodes in the Star Wars trilogy */ export enum Episode { /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ Empire = 'EMPIRE', /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ Jedi = 'JEDI', /** Star Wars Episode IV: A New Hope, released in 1977. */ Newhope = 'NEWHOPE', } /** Units of height */ export enum LengthUnit { /** Primarily used in the United States */ Foot = 'FOOT', /** The standard unit around the world */ Meter = 'METER', } /** The input object sent when someone is creating a new review */ export type ReviewInput = { /** Comment about the movie, optional */ commentary?: InputMaybe; /** Favorite color, optional */ favoriteColor?: InputMaybe; /** 0-5 stars */ stars: Scalars['Int']['input']; }; export type CreateReviewForEpisodeMutationVariables = Exact<{ episode: Episode; review: ReviewInput; }>; export type CreateReviewForEpisodeMutation = { __typename?: 'Mutation'; createReview?: { __typename?: 'Review'; stars: number; commentary?: string | null } | null; }; export type ExcludeQueryAlphaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryAlphaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type ExcludeQueryBetaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryBetaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroAndFriendsNamesQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroAndFriendsNamesQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | { __typename?: 'Human'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | null; }; export type HeroAppearsInQueryVariables = Exact<{ [key: string]: never }>; export type HeroAppearsInQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; appearsIn: Array } | { __typename?: 'Human'; name: string; appearsIn: Array } | null; }; export type HeroDetailsQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; type HeroDetails_Droid_Fragment = { __typename?: 'Droid'; primaryFunction?: string | null; name: string }; type HeroDetails_Human_Fragment = { __typename?: 'Human'; height?: number | null; name: string }; export type HeroDetailsFragment = HeroDetails_Droid_Fragment | HeroDetails_Human_Fragment; export type HeroDetailsWithFragmentQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsWithFragmentQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; export type HeroNameQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroNameQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroNameConditionalInclusionQueryVariables = Exact<{ episode?: InputMaybe; includeName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalInclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroNameConditionalExclusionQueryVariables = Exact<{ episode?: InputMaybe; skipName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalExclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroParentTypeDependentFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroParentTypeDependentFieldQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | { __typename?: 'Human'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | null; }; export type HeroTypeDependentAliasedFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroTypeDependentAliasedFieldQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; property?: string | null } | { __typename?: 'Human'; property?: string | null } | null; }; export type HumanFieldsFragment = { __typename?: 'Human'; name: string; mass?: number | null }; export type HumanWithNullHeightQueryVariables = Exact<{ [key: string]: never }>; export type HumanWithNullHeightQuery = { __typename?: 'Query'; human?: { __typename?: 'Human'; name: string; mass?: number | null } | null; }; export type TwoHeroesQueryVariables = Exact<{ [key: string]: never }>; export type TwoHeroesQuery = { __typename?: 'Query'; r2?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; luke?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; ================================================ FILE: dev-test/star-wars/types.preResolveTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A character from the Star Wars universe */ export type Character = { /** The movies this character appears in */ appearsIn: Array>; /** The friends of the character, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the character exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the character */ id: Scalars['ID']['output']; /** The name of the character */ name: Scalars['String']['output']; }; /** A character from the Star Wars universe */ export type CharacterFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The input object sent when passing a color */ export type ColorInput = { blue: Scalars['Int']['input']; green: Scalars['Int']['input']; red: Scalars['Int']['input']; }; /** An autonomous mechanical character in the Star Wars universe */ export type Droid = Character & { __typename?: 'Droid'; /** The movies this droid appears in */ appearsIn: Array>; /** This droid's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the droid exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the droid */ id: Scalars['ID']['output']; /** What others call this droid */ name: Scalars['String']['output']; /** This droid's primary function */ primaryFunction?: Maybe; }; /** An autonomous mechanical character in the Star Wars universe */ export type DroidFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The episodes in the Star Wars trilogy */ export enum Episode { /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ Empire = 'EMPIRE', /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ Jedi = 'JEDI', /** Star Wars Episode IV: A New Hope, released in 1977. */ Newhope = 'NEWHOPE', } /** A connection object for a character's friends */ export type FriendsConnection = { __typename?: 'FriendsConnection'; /** The edges for each of the character's friends. */ edges?: Maybe>>; /** A list of the friends, as a convenience when edges are not needed. */ friends?: Maybe>>; /** Information for paginating this connection */ pageInfo: PageInfo; /** The total number of friends */ totalCount?: Maybe; }; /** An edge object for a character's friends */ export type FriendsEdge = { __typename?: 'FriendsEdge'; /** A cursor used for pagination */ cursor: Scalars['ID']['output']; /** The character represented by this friendship edge */ node?: Maybe; }; /** A humanoid creature from the Star Wars universe */ export type Human = Character & { __typename?: 'Human'; /** The movies this human appears in */ appearsIn: Array>; /** This human's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the human exposed as a connection with edges */ friendsConnection: FriendsConnection; /** Height in the preferred unit, default is meters */ height?: Maybe; /** The home planet of the human, or null if unknown */ homePlanet?: Maybe; /** The ID of the human */ id: Scalars['ID']['output']; /** Mass in kilograms, or null if unknown */ mass?: Maybe; /** What this human calls themselves */ name: Scalars['String']['output']; /** A list of starships this person has piloted, or an empty list if none */ starships?: Maybe>>; }; /** A humanoid creature from the Star Wars universe */ export type HumanFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** A humanoid creature from the Star Wars universe */ export type HumanHeightArgs = { unit?: InputMaybe; }; /** Units of height */ export enum LengthUnit { /** Primarily used in the United States */ Foot = 'FOOT', /** The standard unit around the world */ Meter = 'METER', } /** The mutation type, represents all updates we can make to our data */ export type Mutation = { __typename?: 'Mutation'; createReview?: Maybe; }; /** The mutation type, represents all updates we can make to our data */ export type MutationCreateReviewArgs = { episode?: InputMaybe; review: ReviewInput; }; /** Information for paginating this connection */ export type PageInfo = { __typename?: 'PageInfo'; endCursor?: Maybe; hasNextPage: Scalars['Boolean']['output']; startCursor?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type Query = { __typename?: 'Query'; character?: Maybe; droid?: Maybe; hero?: Maybe; human?: Maybe; reviews?: Maybe>>; search?: Maybe>>; starship?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryCharacterArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryDroidArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHeroArgs = { episode?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHumanArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryReviewsArgs = { episode: Episode; }; /** The query type, represents all of the entry points into our object graph */ export type QuerySearchArgs = { text?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryStarshipArgs = { id: Scalars['ID']['input']; }; /** Represents a review for a movie */ export type Review = { __typename?: 'Review'; /** Comment about the movie */ commentary?: Maybe; /** The number of stars this review gave, 1-5 */ stars: Scalars['Int']['output']; }; /** The input object sent when someone is creating a new review */ export type ReviewInput = { /** Comment about the movie, optional */ commentary?: InputMaybe; /** Favorite color, optional */ favoriteColor?: InputMaybe; /** 0-5 stars */ stars: Scalars['Int']['input']; }; export type SearchResult = Droid | Human | Starship; export type Starship = { __typename?: 'Starship'; /** The ID of the starship */ id: Scalars['ID']['output']; /** Length of the starship, along the longest axis */ length?: Maybe; /** The name of the starship */ name: Scalars['String']['output']; }; export type StarshipLengthArgs = { unit?: InputMaybe; }; export type CreateReviewForEpisodeMutationVariables = Exact<{ episode: Episode; review: ReviewInput; }>; export type CreateReviewForEpisodeMutation = { __typename?: 'Mutation'; createReview?: { __typename?: 'Review'; stars: number; commentary?: string | null } | null; }; export type ExcludeQueryAlphaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryAlphaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type ExcludeQueryBetaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryBetaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroAndFriendsNamesQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroAndFriendsNamesQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | { __typename?: 'Human'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | null; }; export type HeroAppearsInQueryVariables = Exact<{ [key: string]: never }>; export type HeroAppearsInQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; appearsIn: Array } | { __typename?: 'Human'; name: string; appearsIn: Array } | null; }; export type HeroDetailsQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; type HeroDetails_Droid_Fragment = { __typename?: 'Droid'; primaryFunction?: string | null; name: string }; type HeroDetails_Human_Fragment = { __typename?: 'Human'; height?: number | null; name: string }; export type HeroDetailsFragment = HeroDetails_Droid_Fragment | HeroDetails_Human_Fragment; export type HeroDetailsWithFragmentQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsWithFragmentQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; export type HeroNameQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroNameQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroNameConditionalInclusionQueryVariables = Exact<{ episode?: InputMaybe; includeName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalInclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroNameConditionalExclusionQueryVariables = Exact<{ episode?: InputMaybe; skipName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalExclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroParentTypeDependentFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroParentTypeDependentFieldQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | { __typename?: 'Human'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | null; }; export type HeroTypeDependentAliasedFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroTypeDependentAliasedFieldQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; property?: string | null } | { __typename?: 'Human'; property?: string | null } | null; }; export type HumanFieldsFragment = { __typename?: 'Human'; name: string; mass?: number | null }; export type HumanWithNullHeightQueryVariables = Exact<{ [key: string]: never }>; export type HumanWithNullHeightQuery = { __typename?: 'Query'; human?: { __typename?: 'Human'; name: string; mass?: number | null } | null; }; export type TwoHeroesQueryVariables = Exact<{ [key: string]: never }>; export type TwoHeroesQuery = { __typename?: 'Query'; r2?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; luke?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; ================================================ FILE: dev-test/star-wars/types.skipSchema.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A character from the Star Wars universe */ export type Character = { /** The movies this character appears in */ appearsIn: Array>; /** The friends of the character, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the character exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the character */ id: Scalars['ID']['output']; /** The name of the character */ name: Scalars['String']['output']; }; /** A character from the Star Wars universe */ export type CharacterFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The input object sent when passing a color */ export type ColorInput = { blue: Scalars['Int']['input']; green: Scalars['Int']['input']; red: Scalars['Int']['input']; }; /** An autonomous mechanical character in the Star Wars universe */ export type Droid = Character & { __typename?: 'Droid'; /** The movies this droid appears in */ appearsIn: Array>; /** This droid's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the droid exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the droid */ id: Scalars['ID']['output']; /** What others call this droid */ name: Scalars['String']['output']; /** This droid's primary function */ primaryFunction?: Maybe; }; /** An autonomous mechanical character in the Star Wars universe */ export type DroidFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The episodes in the Star Wars trilogy */ export enum Episode { /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ Empire = 'EMPIRE', /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ Jedi = 'JEDI', /** Star Wars Episode IV: A New Hope, released in 1977. */ Newhope = 'NEWHOPE', } /** A connection object for a character's friends */ export type FriendsConnection = { __typename?: 'FriendsConnection'; /** The edges for each of the character's friends. */ edges?: Maybe>>; /** A list of the friends, as a convenience when edges are not needed. */ friends?: Maybe>>; /** Information for paginating this connection */ pageInfo: PageInfo; /** The total number of friends */ totalCount?: Maybe; }; /** An edge object for a character's friends */ export type FriendsEdge = { __typename?: 'FriendsEdge'; /** A cursor used for pagination */ cursor: Scalars['ID']['output']; /** The character represented by this friendship edge */ node?: Maybe; }; /** A humanoid creature from the Star Wars universe */ export type Human = Character & { __typename?: 'Human'; /** The movies this human appears in */ appearsIn: Array>; /** This human's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the human exposed as a connection with edges */ friendsConnection: FriendsConnection; /** Height in the preferred unit, default is meters */ height?: Maybe; /** The home planet of the human, or null if unknown */ homePlanet?: Maybe; /** The ID of the human */ id: Scalars['ID']['output']; /** Mass in kilograms, or null if unknown */ mass?: Maybe; /** What this human calls themselves */ name: Scalars['String']['output']; /** A list of starships this person has piloted, or an empty list if none */ starships?: Maybe>>; }; /** A humanoid creature from the Star Wars universe */ export type HumanFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** A humanoid creature from the Star Wars universe */ export type HumanHeightArgs = { unit?: InputMaybe; }; /** Units of height */ export enum LengthUnit { /** Primarily used in the United States */ Foot = 'FOOT', /** The standard unit around the world */ Meter = 'METER', } /** The mutation type, represents all updates we can make to our data */ export type Mutation = { __typename?: 'Mutation'; createReview?: Maybe; }; /** The mutation type, represents all updates we can make to our data */ export type MutationCreateReviewArgs = { episode?: InputMaybe; review: ReviewInput; }; /** Information for paginating this connection */ export type PageInfo = { __typename?: 'PageInfo'; endCursor?: Maybe; hasNextPage: Scalars['Boolean']['output']; startCursor?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type Query = { __typename?: 'Query'; character?: Maybe; droid?: Maybe; hero?: Maybe; human?: Maybe; reviews?: Maybe>>; search?: Maybe>>; starship?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryCharacterArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryDroidArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHeroArgs = { episode?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHumanArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryReviewsArgs = { episode: Episode; }; /** The query type, represents all of the entry points into our object graph */ export type QuerySearchArgs = { text?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryStarshipArgs = { id: Scalars['ID']['input']; }; /** Represents a review for a movie */ export type Review = { __typename?: 'Review'; /** Comment about the movie */ commentary?: Maybe; /** The number of stars this review gave, 1-5 */ stars: Scalars['Int']['output']; }; /** The input object sent when someone is creating a new review */ export type ReviewInput = { /** Comment about the movie, optional */ commentary?: InputMaybe; /** Favorite color, optional */ favoriteColor?: InputMaybe; /** 0-5 stars */ stars: Scalars['Int']['input']; }; export type SearchResult = Droid | Human | Starship; export type Starship = { __typename?: 'Starship'; /** The ID of the starship */ id: Scalars['ID']['output']; /** Length of the starship, along the longest axis */ length?: Maybe; /** The name of the starship */ name: Scalars['String']['output']; }; export type StarshipLengthArgs = { unit?: InputMaybe; }; export type CreateReviewForEpisodeMutationVariables = Exact<{ episode: Episode; review: ReviewInput; }>; export type CreateReviewForEpisodeMutation = { __typename?: 'Mutation'; createReview?: { __typename?: 'Review'; stars: number; commentary?: string | null } | null; }; export type ExcludeQueryAlphaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryAlphaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type ExcludeQueryBetaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryBetaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroAndFriendsNamesQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroAndFriendsNamesQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | { __typename?: 'Human'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | null; }; export type HeroAppearsInQueryVariables = Exact<{ [key: string]: never }>; export type HeroAppearsInQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; appearsIn: Array } | { __typename?: 'Human'; name: string; appearsIn: Array } | null; }; export type HeroDetailsQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; type HeroDetails_Droid_Fragment = { __typename?: 'Droid'; primaryFunction?: string | null; name: string }; type HeroDetails_Human_Fragment = { __typename?: 'Human'; height?: number | null; name: string }; export type HeroDetailsFragment = HeroDetails_Droid_Fragment | HeroDetails_Human_Fragment; export type HeroDetailsWithFragmentQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsWithFragmentQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; export type HeroNameQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroNameQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroNameConditionalInclusionQueryVariables = Exact<{ episode?: InputMaybe; includeName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalInclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroNameConditionalExclusionQueryVariables = Exact<{ episode?: InputMaybe; skipName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalExclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroParentTypeDependentFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroParentTypeDependentFieldQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | { __typename?: 'Human'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | null; }; export type HeroTypeDependentAliasedFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroTypeDependentAliasedFieldQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; property?: string | null } | { __typename?: 'Human'; property?: string | null } | null; }; export type HumanFieldsFragment = { __typename?: 'Human'; name: string; mass?: number | null }; export type HumanWithNullHeightQueryVariables = Exact<{ [key: string]: never }>; export type HumanWithNullHeightQuery = { __typename?: 'Query'; human?: { __typename?: 'Human'; name: string; mass?: number | null } | null; }; export type TwoHeroesQueryVariables = Exact<{ [key: string]: never }>; export type TwoHeroesQuery = { __typename?: 'Query'; r2?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; luke?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; ================================================ FILE: dev-test/star-wars/types.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A character from the Star Wars universe */ export type Character = { /** The movies this character appears in */ appearsIn: Array>; /** The friends of the character, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the character exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the character */ id: Scalars['ID']['output']; /** The name of the character */ name: Scalars['String']['output']; }; /** A character from the Star Wars universe */ export type CharacterFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The input object sent when passing a color */ export type ColorInput = { blue: Scalars['Int']['input']; green: Scalars['Int']['input']; red: Scalars['Int']['input']; }; /** An autonomous mechanical character in the Star Wars universe */ export type Droid = Character & { __typename?: 'Droid'; /** The movies this droid appears in */ appearsIn: Array>; /** This droid's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the droid exposed as a connection with edges */ friendsConnection: FriendsConnection; /** The ID of the droid */ id: Scalars['ID']['output']; /** What others call this droid */ name: Scalars['String']['output']; /** This droid's primary function */ primaryFunction?: Maybe; }; /** An autonomous mechanical character in the Star Wars universe */ export type DroidFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** The episodes in the Star Wars trilogy */ export enum Episode { /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ Empire = 'EMPIRE', /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ Jedi = 'JEDI', /** Star Wars Episode IV: A New Hope, released in 1977. */ Newhope = 'NEWHOPE', } /** A connection object for a character's friends */ export type FriendsConnection = { __typename?: 'FriendsConnection'; /** The edges for each of the character's friends. */ edges?: Maybe>>; /** A list of the friends, as a convenience when edges are not needed. */ friends?: Maybe>>; /** Information for paginating this connection */ pageInfo: PageInfo; /** The total number of friends */ totalCount?: Maybe; }; /** An edge object for a character's friends */ export type FriendsEdge = { __typename?: 'FriendsEdge'; /** A cursor used for pagination */ cursor: Scalars['ID']['output']; /** The character represented by this friendship edge */ node?: Maybe; }; /** A humanoid creature from the Star Wars universe */ export type Human = Character & { __typename?: 'Human'; /** The movies this human appears in */ appearsIn: Array>; /** This human's friends, or an empty list if they have none */ friends?: Maybe>>; /** The friends of the human exposed as a connection with edges */ friendsConnection: FriendsConnection; /** Height in the preferred unit, default is meters */ height?: Maybe; /** The home planet of the human, or null if unknown */ homePlanet?: Maybe; /** The ID of the human */ id: Scalars['ID']['output']; /** Mass in kilograms, or null if unknown */ mass?: Maybe; /** What this human calls themselves */ name: Scalars['String']['output']; /** A list of starships this person has piloted, or an empty list if none */ starships?: Maybe>>; }; /** A humanoid creature from the Star Wars universe */ export type HumanFriendsConnectionArgs = { after?: InputMaybe; first?: InputMaybe; }; /** A humanoid creature from the Star Wars universe */ export type HumanHeightArgs = { unit?: InputMaybe; }; /** Units of height */ export enum LengthUnit { /** Primarily used in the United States */ Foot = 'FOOT', /** The standard unit around the world */ Meter = 'METER', } /** The mutation type, represents all updates we can make to our data */ export type Mutation = { __typename?: 'Mutation'; createReview?: Maybe; }; /** The mutation type, represents all updates we can make to our data */ export type MutationCreateReviewArgs = { episode?: InputMaybe; review: ReviewInput; }; /** Information for paginating this connection */ export type PageInfo = { __typename?: 'PageInfo'; endCursor?: Maybe; hasNextPage: Scalars['Boolean']['output']; startCursor?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type Query = { __typename?: 'Query'; character?: Maybe; droid?: Maybe; hero?: Maybe; human?: Maybe; reviews?: Maybe>>; search?: Maybe>>; starship?: Maybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryCharacterArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryDroidArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHeroArgs = { episode?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryHumanArgs = { id: Scalars['ID']['input']; }; /** The query type, represents all of the entry points into our object graph */ export type QueryReviewsArgs = { episode: Episode; }; /** The query type, represents all of the entry points into our object graph */ export type QuerySearchArgs = { text?: InputMaybe; }; /** The query type, represents all of the entry points into our object graph */ export type QueryStarshipArgs = { id: Scalars['ID']['input']; }; /** Represents a review for a movie */ export type Review = { __typename?: 'Review'; /** Comment about the movie */ commentary?: Maybe; /** The number of stars this review gave, 1-5 */ stars: Scalars['Int']['output']; }; /** The input object sent when someone is creating a new review */ export type ReviewInput = { /** Comment about the movie, optional */ commentary?: InputMaybe; /** Favorite color, optional */ favoriteColor?: InputMaybe; /** 0-5 stars */ stars: Scalars['Int']['input']; }; export type SearchResult = Droid | Human | Starship; export type Starship = { __typename?: 'Starship'; /** The ID of the starship */ id: Scalars['ID']['output']; /** Length of the starship, along the longest axis */ length?: Maybe; /** The name of the starship */ name: Scalars['String']['output']; }; export type StarshipLengthArgs = { unit?: InputMaybe; }; export type CreateReviewForEpisodeMutationVariables = Exact<{ episode: Episode; review: ReviewInput; }>; export type CreateReviewForEpisodeMutation = { __typename?: 'Mutation'; createReview?: { __typename?: 'Review'; stars: number; commentary?: string | null } | null; }; export type ExcludeQueryAlphaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryAlphaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type ExcludeQueryBetaQueryVariables = Exact<{ episode?: InputMaybe; }>; export type ExcludeQueryBetaQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroAndFriendsNamesQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroAndFriendsNamesQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | { __typename?: 'Human'; name: string; friends?: Array<{ __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null> | null; } | null; }; export type HeroAppearsInQueryVariables = Exact<{ [key: string]: never }>; export type HeroAppearsInQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; appearsIn: Array } | { __typename?: 'Human'; name: string; appearsIn: Array } | null; }; export type HeroDetailsQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; type HeroDetails_Droid_Fragment = { __typename?: 'Droid'; primaryFunction?: string | null; name: string }; type HeroDetails_Human_Fragment = { __typename?: 'Human'; height?: number | null; name: string }; export type HeroDetailsFragment = HeroDetails_Droid_Fragment | HeroDetails_Human_Fragment; export type HeroDetailsWithFragmentQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroDetailsWithFragmentQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; primaryFunction?: string | null; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null; }; export type HeroNameQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroNameQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; export type HeroNameConditionalInclusionQueryVariables = Exact<{ episode?: InputMaybe; includeName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalInclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroNameConditionalExclusionQueryVariables = Exact<{ episode?: InputMaybe; skipName: Scalars['Boolean']['input']; }>; export type HeroNameConditionalExclusionQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; name?: string } | { __typename?: 'Human'; name?: string } | null; }; export type HeroParentTypeDependentFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroParentTypeDependentFieldQuery = { __typename?: 'Query'; hero?: | { __typename?: 'Droid'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | { __typename?: 'Human'; name: string; friends?: Array< { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; height?: number | null; name: string } | null > | null; } | null; }; export type HeroTypeDependentAliasedFieldQueryVariables = Exact<{ episode?: InputMaybe; }>; export type HeroTypeDependentAliasedFieldQuery = { __typename?: 'Query'; hero?: { __typename?: 'Droid'; property?: string | null } | { __typename?: 'Human'; property?: string | null } | null; }; export type HumanFieldsFragment = { __typename?: 'Human'; name: string; mass?: number | null }; export type HumanWithNullHeightQueryVariables = Exact<{ [key: string]: never }>; export type HumanWithNullHeightQuery = { __typename?: 'Query'; human?: { __typename?: 'Human'; name: string; mass?: number | null } | null; }; export type TwoHeroesQueryVariables = Exact<{ [key: string]: never }>; export type TwoHeroesQuery = { __typename?: 'Query'; r2?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; luke?: { __typename?: 'Droid'; name: string } | { __typename?: 'Human'; name: string } | null; }; ================================================ FILE: dev-test/subpath-import/result.d.ts ================================================ import { RoleStatus } from '#changeName/server/drizzle/schema'; import { GraphQLResolveInfo } from 'graphql'; import { TestContext } from '#test-null-value/context'; import { FiedContextType } from '#test/root'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; export type EnumResolverSignature = { [key in keyof T]?: AllowedValues }; export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export { RoleStatus }; export type User = { __typename?: 'User'; createdAt: Scalars['String']['output']; email: Scalars['String']['output']; id: Scalars['ID']['output']; name: Scalars['String']['output']; password: Scalars['String']['output']; updatedAt: Scalars['String']['output']; }; export type Mutation = { __typename?: 'mutation'; createUser: User; }; export type MutationCreateUserArgs = { email: Scalars['String']['input']; name: Scalars['String']['input']; password: Scalars['String']['input']; }; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Boolean: ResolverTypeWrapper; ID: ResolverTypeWrapper; RoleStatus: RoleStatus; String: ResolverTypeWrapper; User: ResolverTypeWrapper; mutation: ResolverTypeWrapper; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Boolean: Scalars['Boolean']['output']; ID: Scalars['ID']['output']; String: Scalars['String']['output']; User: User; mutation: Mutation; }; export type RoleStatusResolvers = EnumResolverSignature<{ ADMIN?: any; USER?: any }, ResolversTypes['RoleStatus']>; export type UserResolvers< ContextType = TestContext, ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User'] > = { createdAt?: Resolver; email?: Resolver; id?: Resolver; name?: Resolver; password?: Resolver; updatedAt?: Resolver; }; export type MutationResolvers< ContextType = TestContext, ParentType extends ResolversParentTypes['mutation'] = ResolversParentTypes['mutation'] > = { createUser?: Resolver< ResolversTypes['User'], ParentType, FiedContextType, RequireFields >; }; export type Resolvers = { RoleStatus?: RoleStatusResolvers; User?: UserResolvers; mutation?: MutationResolvers; }; ================================================ FILE: dev-test/subpath-import/schema.graphql ================================================ type User { id: ID! name: String! email: String! password: String! createdAt: String! updatedAt: String! } enum RoleStatus { ADMIN USER } type mutation { createUser(name: String!, email: String!, password: String!): User! } ================================================ FILE: dev-test/test-federation/generated/types.ts ================================================ import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; export type Maybe = T | null | undefined; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; /** Represents a car */ CarKey: { input: string; output: string }; }; export type Car = { __typename?: 'Car'; carKey: Scalars['CarKey']['output']; /** Extend Car with a simple "dummy" field */ dummy?: Maybe; }; export type WithIndex = TObject & Record; export type ResolversObject = WithIndex; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = ResolversObject<{ Boolean: ResolverTypeWrapper; Car: ResolverTypeWrapper; CarKey: ResolverTypeWrapper; String: ResolverTypeWrapper; }>; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = ResolversObject<{ Boolean: Scalars['Boolean']['output']; Car: Car; CarKey: Scalars['CarKey']['output']; String: Scalars['String']['output']; }>; export type CarResolvers< ContextType = any, ParentType extends ResolversParentTypes['Car'] = ResolversParentTypes['Car'] > = ResolversObject<{ carKey?: Resolver; dummy?: Resolver, ParentType, ContextType>; }>; export interface CarKeyScalarConfig extends GraphQLScalarTypeConfig { name: 'CarKey'; } export type Resolvers = ResolversObject<{ Car?: CarResolvers; CarKey?: GraphQLScalarType; }>; ================================================ FILE: dev-test/test-federation/schema.gql ================================================ extend schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.6", import: ["@key", "@extends"]) type Car @extends @key(fields: "carKey") { carKey: CarKey! """ Extend Car with a simple "dummy" field """ dummy: String } """ Represents a car """ scalar CarKey ================================================ FILE: dev-test/test-message/schema.graphql ================================================ type Message { id: String! } type Query { messages(tab: String!): [Message] } input CreateMessageInput { description: String! } type Mutation { createMessage(args: CreateMessageInput!): Message approve(id: ID!): Message decline(id: ID!, reason: String!): Message escalate(id: ID!): Message } schema { query: Query mutation: Mutation } ================================================ FILE: dev-test/test-mongodb/schema.graphql ================================================ enum Role { ADMIN WRITER READER } scalar Date type Post @entity { id: ID @id title: String @column content: String @column createdAt: Date @column author: User @link @map(path: "userId") } interface User @abstractEntity(discriminatorField: "role") { id: ID @id username: String @column role: Role @column likedPosts: [Post] followerUsers(skip: Int, limit: Int): [User] followingUsers(skip: Int, limit: Int): [User] @link @map(path: "followingUserIds") } type AdminUser implements User @entity { id: ID @id username: String @column role: Role @column likedPosts: [Post] followerUsers(skip: Int, limit: Int): [User] followingUsers(skip: Int, limit: Int): [User] @link @map(path: "followingUserIds") posts(skip: Int, limit: Int): [Post] } type WriterUser @entity { id: ID @id username: String @column role: Role @column likedPosts(skip: Int, limit: Int): [Post] followerUsers(skip: Int, limit: Int): [User] followingUsers(skip: Int, limit: Int): [User] @link @map(path: "followingUserIds") posts(skip: Int, limit: Int): [Post] } type ReaderUser @entity { id: ID @id username: String @column role: Role @column likedPosts(skip: Int, limit: Int): [Post] followerUsers(skip: Int, limit: Int): [User] followingUsers(skip: Int, limit: Int): [User] @link @map(path: "followingUserIds") } ================================================ FILE: dev-test/test-null-value/query.ts ================================================ export const MY_QUERY = /* GraphQL */ ` fragment CartLine on CartLine { id quantity } query Test { cart { lines { nodes { ...CartLine } } } } `; ================================================ FILE: dev-test/test-null-value/result.d.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type BaseCartLine = { id: Scalars['String']['output']; quantity: Scalars['Int']['output']; }; export type BaseCartLineConnection = { id: Scalars['String']['output']; nodes: Array; }; export type Cart = { id: Scalars['String']['output']; lines: BaseCartLineConnection; }; export type CartLine = BaseCartLine & { id: Scalars['String']['output']; quantity: Scalars['Int']['output']; }; export type ComponentizableCartLine = BaseCartLine & { id: Scalars['String']['output']; quantity: Scalars['Int']['output']; }; export type QueryRoot = { cart?: Maybe; }; export type CartLineFragment = { id: string; quantity: number }; export type TestQueryVariables = Exact<{ [key: string]: never }>; export type TestQuery = { cart?: { lines: { nodes: Array<{ id: string; quantity: number }> } } | null }; ================================================ FILE: dev-test/test-null-value/schema.graphql ================================================ schema { query: QueryRoot } interface BaseCartLine { id: String! quantity: Int! } type BaseCartLineConnection { id: String! nodes: [BaseCartLine!]! } type Cart { id: String! lines: BaseCartLineConnection! } type CartLine implements BaseCartLine { id: String! quantity: Int! } type ComponentizableCartLine implements BaseCartLine { id: String! quantity: Int! } type QueryRoot { cart: Cart } ================================================ FILE: dev-test/test-schema/env.types.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; allUsers: Array>; /** * Generates a new answer for th * guessing game */ answer: Array; testArr1?: Maybe>>; testArr2: Array>; testArr3: Array; userById?: Maybe; }; export type QueryUserByIdArgs = { id: Scalars['Int']['input']; }; export type User = { __typename?: 'User'; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; ================================================ FILE: dev-test/test-schema/flow-types.flow.js ================================================ // @flow import { type GraphQLResolveInfo } from 'graphql'; export type $RequireFields = $Diff & $ObjMapi(k: Key) => $NonMaybeType<$ElementType>>; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = {| ID: string, String: string, Boolean: boolean, Int: number, Float: number, |}; export type Query = {| __typename?: 'Query', allUsers: Array, userById?: ?User, |}; export type QueryUserByIdArgs = {| id: $ElementType, |}; export type User = {| __typename?: 'User', email: $ElementType, id: $ElementType, name: $ElementType, |}; export type Resolver = ( parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo ) => Promise | Result; export type SubscriptionSubscribeFn = ( parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo ) => AsyncIterator | Promise>; export type SubscriptionResolveFn = ( parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo ) => Result | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key: Key]: Result }, Parent, Context, Args>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver = | ((...args: Array) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn = ( parent: Parent, context: Context, info: GraphQLResolveInfo ) => ?Types | Promise; export type IsTypeOfResolverFn = ( obj: T, context: Context, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn = ( next: NextResolverFn, parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo ) => Result | Promise; export type ResolverTypeWrapper = Promise | T; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Boolean: ResolverTypeWrapper<$ElementType>, Int: ResolverTypeWrapper<$ElementType>, Query: ResolverTypeWrapper<{}>, String: ResolverTypeWrapper<$ElementType>, User: ResolverTypeWrapper, }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Boolean: $ElementType, Int: $ElementType, Query: {}, String: $ElementType, User: User, }; export type QueryResolvers> = { allUsers?: Resolver>, ParentType, ContextType>, userById?: Resolver< ?$ElementType, ParentType, ContextType, $RequireFields >, }; export type UserResolvers> = { email?: Resolver<$ElementType, ParentType, ContextType>, id?: Resolver<$ElementType, ParentType, ContextType>, name?: Resolver<$ElementType, ParentType, ContextType>, __isTypeOf?: IsTypeOfResolverFn, }; export type Resolvers = { Query?: QueryResolvers, User?: UserResolvers, }; ================================================ FILE: dev-test/test-schema/local/schema-ast.js ================================================ const schemaFormats = require('./schema-formats'); module.exports.schema = schemaFormats.schemaAst; ================================================ FILE: dev-test/test-schema/local/schema-formats.js ================================================ /** * There are four formats the schema can be in: * 1. GraphQLSchema object * 2. Text (the GraphQL schema language textual format) * 3. AST (the GraphQL schema language textual format parsed into an AST) * * This file imports the textual and introspection json files and * exports all four formats to be used in tests. */ const GraphQL = require('graphql'); const fs = require('fs'); const path = require('path'); const schemaText = fs.readFileSync(path.join(__dirname, 'schema.graphql'), 'utf8'); const schemaObject = GraphQL.buildSchema(schemaText); const schemaAst = GraphQL.parse(schemaText); module.exports.schemaText = schemaText; module.exports.schemaAst = schemaAst; module.exports.schemaObject = schemaObject; ================================================ FILE: dev-test/test-schema/local/schema-object.js ================================================ const schemaFormats = require('./schema-formats'); module.exports.schema = schemaFormats.schemaObject; ================================================ FILE: dev-test/test-schema/local/schema-text.js ================================================ const schemaFormats = require('./schema-formats'); module.exports.schema = schemaFormats.schemaText; ================================================ FILE: dev-test/test-schema/local/schema.graphql ================================================ type Post { id: Int! title: String! } type Query { allPosts: [Post]! } ================================================ FILE: dev-test/test-schema/resolvers-federation.ts ================================================ import { GraphQLResolveInfo } from 'graphql'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; _FieldSet: { input: any; output: any }; }; export type Address = { __typename?: 'Address'; city?: Maybe; lines: Lines; state?: Maybe; }; export type Book = { __typename?: 'Book'; id: Scalars['ID']['output']; }; export type Lines = { __typename?: 'Lines'; line1: Scalars['String']['output']; line2?: Maybe; }; export type Query = { __typename?: 'Query'; users?: Maybe>>; }; export type User = { __typename?: 'User'; address?: Maybe
    ; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; export type ResolverTypeWrapper = Promise | T; export type ReferenceResolver = ( reference: TReference, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; type ScalarCheck = S extends true ? T : NullableCheck; type NullableCheck = Maybe extends T ? Maybe, S>> : ListCheck; type ListCheck = T extends (infer U)[] ? NullableCheck[] : GraphQLRecursivePick; export type GraphQLRecursivePick = { [K in keyof T & keyof S]: ScalarCheck }; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping of federation types */ export type FederationTypes = { User: User; }; /** Mapping of federation reference types */ export type FederationReferenceTypes = { User: { __typename: 'User' } & ( | GraphQLRecursivePick | GraphQLRecursivePick ) & ( | Record | GraphQLRecursivePick ); }; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Address: ResolverTypeWrapper
    ; String: ResolverTypeWrapper; Book: ResolverTypeWrapper; ID: ResolverTypeWrapper; Lines: ResolverTypeWrapper; Query: ResolverTypeWrapper>; User: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Address: Address; String: Scalars['String']['output']; Book: Book; ID: Scalars['ID']['output']; Lines: Lines; Query: Record; User: User | FederationReferenceTypes['User']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; export type AddressResolvers< ContextType = any, ParentType extends ResolversParentTypes['Address'] = ResolversParentTypes['Address'] > = { city?: Resolver, ParentType, ContextType>; lines?: Resolver; state?: Resolver, ParentType, ContextType>; }; export type BookResolvers< ContextType = any, ParentType extends ResolversParentTypes['Book'] = ResolversParentTypes['Book'] > = { id?: Resolver; }; export type LinesResolvers< ContextType = any, ParentType extends ResolversParentTypes['Lines'] = ResolversParentTypes['Lines'] > = { line1?: Resolver; line2?: Resolver, ParentType, ContextType>; }; export type QueryResolvers< ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'] > = { users?: Resolver>>, ParentType, ContextType>; }; export type UserResolvers< ContextType = any, ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User'], FederationReferenceType extends FederationReferenceTypes['User'] = FederationReferenceTypes['User'] > = { __resolveReference?: ReferenceResolver< Maybe | FederationReferenceType, FederationReferenceType, ContextType >; email?: Resolver; }; export type Resolvers = { Address?: AddressResolvers; Book?: BookResolvers; Lines?: LinesResolvers; Query?: QueryResolvers; User?: UserResolvers; }; ================================================ FILE: dev-test/test-schema/resolvers-root.ts ================================================ import { GraphQLResolveInfo } from 'graphql'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; someDummyField: Scalars['Int']['output']; }; export type QueryRoot = { __typename?: 'QueryRoot'; allUsers: Array>; answer: Array; userById?: Maybe; }; export type QueryRootUserByIdArgs = { id: Scalars['Int']['input']; }; export type SubscriptionRoot = { __typename?: 'SubscriptionRoot'; newUser?: Maybe; }; export type User = { __typename?: 'User'; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Boolean: ResolverTypeWrapper; Int: ResolverTypeWrapper; Query: ResolverTypeWrapper; QueryRoot: ResolverTypeWrapper>; String: ResolverTypeWrapper; SubscriptionRoot: ResolverTypeWrapper>; User: ResolverTypeWrapper; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Boolean: Scalars['Boolean']['output']; Int: Scalars['Int']['output']; Query: Query; QueryRoot: Record; String: Scalars['String']['output']; SubscriptionRoot: Record; User: User; }; export type QueryResolvers< ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'] > = { someDummyField?: Resolver; }; export type QueryRootResolvers< ContextType = any, ParentType extends ResolversParentTypes['QueryRoot'] = ResolversParentTypes['QueryRoot'] > = { allUsers?: Resolver>, ParentType, ContextType>; answer?: Resolver, ParentType, ContextType>; userById?: Resolver< Maybe, ParentType, ContextType, RequireFields >; }; export type SubscriptionRootResolvers< ContextType = any, ParentType extends ResolversParentTypes['SubscriptionRoot'] = ResolversParentTypes['SubscriptionRoot'] > = { newUser?: SubscriptionResolver, 'newUser', ParentType, ContextType>; }; export type UserResolvers< ContextType = any, ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User'] > = { email?: Resolver; id?: Resolver; name?: Resolver; }; export type Resolvers = { Query?: QueryResolvers; QueryRoot?: QueryRootResolvers; SubscriptionRoot?: SubscriptionRootResolvers; User?: UserResolvers; }; ================================================ FILE: dev-test/test-schema/resolvers-stitching.ts ================================================ import { GraphQLResolveInfo, SelectionSetNode, FieldNode } from 'graphql'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; allUsers: Array>; /** * Generates a new answer for th * guessing game */ answer: Array; testArr1?: Maybe>>; testArr2: Array>; testArr3: Array; userById?: Maybe; }; export type QueryUserByIdArgs = { id: Scalars['Int']['input']; }; export type User = { __typename?: 'User'; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type LegacyStitchingResolver = { fragment: string; resolve: ResolverFn; }; export type NewStitchingResolver = { selectionSet: string | ((fieldNode: FieldNode) => SelectionSetNode); resolve: ResolverFn; }; export type StitchingResolver = | LegacyStitchingResolver | NewStitchingResolver; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = | ResolverFn | ResolverWithResolve | StitchingResolver; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Boolean: ResolverTypeWrapper; Int: ResolverTypeWrapper; Query: ResolverTypeWrapper>; String: ResolverTypeWrapper; User: ResolverTypeWrapper; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Boolean: Scalars['Boolean']['output']; Int: Scalars['Int']['output']; Query: Record; String: Scalars['String']['output']; User: User; }; export type QueryResolvers< ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'] > = { allUsers?: Resolver>, ParentType, ContextType>; answer?: Resolver, ParentType, ContextType>; testArr1?: Resolver>>, ParentType, ContextType>; testArr2?: Resolver>, ParentType, ContextType>; testArr3?: Resolver, ParentType, ContextType>; userById?: Resolver, ParentType, ContextType, RequireFields>; }; export type UserResolvers< ContextType = any, ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User'] > = { email?: Resolver; id?: Resolver; name?: Resolver; }; export type Resolvers = { Query?: QueryResolvers; User?: UserResolvers; }; ================================================ FILE: dev-test/test-schema/resolvers-types.ts ================================================ import { GraphQLResolveInfo } from 'graphql'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; allUsers: Array>; /** * Generates a new answer for th * guessing game */ answer: Array; testArr1?: Maybe>>; testArr2: Array>; testArr3: Array; userById?: Maybe; }; export type QueryUserByIdArgs = { id: Scalars['Int']['input']; }; export type User = { __typename?: 'User'; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Boolean: ResolverTypeWrapper; Int: ResolverTypeWrapper; Query: ResolverTypeWrapper>; String: ResolverTypeWrapper; User: ResolverTypeWrapper; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Boolean: Scalars['Boolean']['output']; Int: Scalars['Int']['output']; Query: Record; String: Scalars['String']['output']; User: User; }; export type QueryResolvers< ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'] > = { allUsers?: Resolver>, ParentType, ContextType>; answer?: Resolver, ParentType, ContextType>; testArr1?: Resolver>>, ParentType, ContextType>; testArr2?: Resolver>, ParentType, ContextType>; testArr3?: Resolver, ParentType, ContextType>; userById?: Resolver, ParentType, ContextType, RequireFields>; }; export type UserResolvers< ContextType = any, ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User'] > = { email?: Resolver; id?: Resolver; name?: Resolver; }; export type Resolvers = { Query?: QueryResolvers; User?: UserResolvers; }; ================================================ FILE: dev-test/test-schema/schema-ast.js ================================================ const schemaFormats = require('./schema-formats'); module.exports.schema = schemaFormats.schemaAst; ================================================ FILE: dev-test/test-schema/schema-federation.graphql ================================================ extend type Query { users: [User] } extend type User @key(fields: "id") @key(fields: "name") { id: Int! @external name: String! @external email: String! @requires( fields: """ address(works: "with params!") { city lines { line2 } } """ ) address: Address @external } extend type Address { lines: Lines! city: String state: String } extend type Lines { line1: String! line2: String } type Book { id: ID! } ================================================ FILE: dev-test/test-schema/schema-formats.js ================================================ /** * There are four formats the schema can be in: * 1. GraphQLSchema object * 2. Text (the GraphQL schema language textual format) * 3. AST (the GraphQL schema language textual format parsed into an AST) * 4. Introspection JSON (result returned by introspection query) * * This file imports the textual and introspection json files and * exports all four formats to be used in tests. */ const GraphQL = require('graphql'); const fs = require('fs'); const path = require('path'); const schemaText = fs.readFileSync(path.join(__dirname, 'schema.graphql'), 'utf8'); const schemaObject = new GraphQL.GraphQLSchema({ query: new GraphQL.GraphQLObjectType({ name: 'Query', fields: { foo: { type: new GraphQL.GraphQLEnumType({ name: 'Foo', values: { BAR: { value: 'QUX', }, }, }), }, }, }), }); const schemaAst = GraphQL.parse(schemaText); const schemaJson = require('./schema.json'); module.exports.schemaText = schemaText; module.exports.schemaAst = schemaAst; module.exports.schemaObject = schemaObject; module.exports.schemaJson = schemaJson; ================================================ FILE: dev-test/test-schema/schema-json.js ================================================ const schemaFormats = require('./schema-formats'); module.exports.schema = schemaFormats.schemaJson; ================================================ FILE: dev-test/test-schema/schema-object.js ================================================ const schemaFormats = require('./schema-formats'); module.exports.schema = schemaFormats.schemaObject; ================================================ FILE: dev-test/test-schema/schema-text.js ================================================ const schemaFormats = require('./schema-formats'); module.exports.schema = schemaFormats.schemaText; ================================================ FILE: dev-test/test-schema/schema-with-imports.graphql ================================================ # import User from './schema.graphql' type Query { allUsers: [User]! userById(id: Int!): User # Generates a new answer for the guessing game answer: [Int!]! } ================================================ FILE: dev-test/test-schema/schema-with-root.graphql ================================================ schema { query: QueryRoot subscription: SubscriptionRoot } type Query { someDummyField: Int! } type QueryRoot { allUsers: [User]! userById(id: Int!): User # Generates a new answer for the guessing game answer: [Int!]! } type User { id: Int! name: String! email: String! } type SubscriptionRoot { newUser: User } ================================================ FILE: dev-test/test-schema/schema.graphql ================================================ type User { id: Int! name: String! email: String! } type Query { allUsers: [User]! userById(id: Int!): User """ Generates a new answer for th guessing game """ answer: [Int!]! testArr1: [String] testArr2: [String]! testArr3: [String!]! } ================================================ FILE: dev-test/test-schema/schema.json ================================================ { "data": { "__schema": { "queryType": { "name": "Query" }, "mutationType": null, "subscriptionType": null, "types": [ { "kind": "OBJECT", "name": "Query", "description": "", "fields": [ { "name": "allUsers", "description": "", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userById", "description": "", "args": [ { "name": "id", "description": "", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "User", "description": "", "fields": [ { "name": "id", "description": "", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "email", "description": "", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "Int", "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "String", "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Schema", "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", "fields": [ { "name": "types", "description": "A list of all types supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "queryType", "description": "The type that query operations will be rooted at.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mutationType", "description": "If this server supports mutation, the type that mutation operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "subscriptionType", "description": "If this server support subscription, the type that subscription operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "directives", "description": "A list of all directives supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Type", "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", "fields": [ { "name": "kind", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "fields", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "interfaces", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "possibleTypes", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "enumValues", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "inputFields", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ofType", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__TypeKind", "description": "An enum describing what kind of type a given `__Type` is.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "SCALAR", "description": "Indicates this type is a scalar.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Indicates this type is a union. `possibleTypes` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Indicates this type is an enum. `enumValues` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Indicates this type is an input object. `inputFields` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "LIST", "description": "Indicates this type is a list. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "NON_NULL", "description": "Indicates this type is a non-null. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "SCALAR", "name": "Boolean", "description": "The `Boolean` scalar type represents `true` or `false`.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Field", "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__InputValue", "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "defaultValue", "description": "A GraphQL-formatted string representing the default value for this input value.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__EnumValue", "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Directive", "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "locations", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "onOperation", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onFragment", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onField", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__DirectiveLocation", "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "QUERY", "description": "Location adjacent to a query operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "MUTATION", "description": "Location adjacent to a mutation operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "SUBSCRIPTION", "description": "Location adjacent to a subscription operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD", "description": "Location adjacent to a field.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_DEFINITION", "description": "Location adjacent to a fragment definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_SPREAD", "description": "Location adjacent to a fragment spread.", "isDeprecated": false, "deprecationReason": null }, { "name": "INLINE_FRAGMENT", "description": "Location adjacent to an inline fragment.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCHEMA", "description": "Location adjacent to a schema definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCALAR", "description": "Location adjacent to a scalar definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Location adjacent to an object type definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD_DEFINITION", "description": "Location adjacent to a field definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ARGUMENT_DEFINITION", "description": "Location adjacent to an argument definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Location adjacent to an interface definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Location adjacent to a union definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Location adjacent to an enum definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM_VALUE", "description": "Location adjacent to an enum value definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Location adjacent to an input object type definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_FIELD_DEFINITION", "description": "Location adjacent to an input object field definition.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null } ], "directives": [ { "name": "skip", "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Skipped when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ] }, { "name": "include", "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Included when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ] }, { "name": "deprecated", "description": "Marks an element of a GraphQL schema as no longer supported.", "locations": ["FIELD_DEFINITION", "ENUM_VALUE"], "args": [ { "name": "reason", "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": "\"No longer supported\"" } ] } ] } } } ================================================ FILE: dev-test/test-schema/types.onlyEnums.ts ================================================ export type TestQueryVariables = Exact<{ [key: string]: never }>; export type TestQuery = { __typename?: 'Query'; testArr1?: Array | null; testArr2: Array; testArr3: Array; }; ================================================ FILE: dev-test/test-schema/types.preResolveTypes.onlyOperationTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type TestQueryVariables = Exact<{ [key: string]: never }>; export type TestQuery = { __typename?: 'Query'; testArr1?: Array | null; testArr2: Array; testArr3: Array; }; ================================================ FILE: dev-test/test-schema/types.preResolveTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; allUsers: Array>; /** * Generates a new answer for th * guessing game */ answer: Array; testArr1?: Maybe>>; testArr2: Array>; testArr3: Array; userById?: Maybe; }; export type QueryUserByIdArgs = { id: Scalars['Int']['input']; }; export type User = { __typename?: 'User'; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; export type TestQueryVariables = Exact<{ [key: string]: never }>; export type TestQuery = { __typename?: 'Query'; testArr1?: Array | null; testArr2: Array; testArr3: Array; }; ================================================ FILE: dev-test/test-schema/typings.avoidOptionals.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; allUsers: Array>; userById: Maybe; }; export type QueryUserByIdArgs = { id: Scalars['Int']['input']; }; export type User = { __typename?: 'User'; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; ================================================ FILE: dev-test/test-schema/typings.enum.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export enum Foo { Bar = 'QUX', } export type Query = { __typename?: 'Query'; foo?: Maybe; }; ================================================ FILE: dev-test/test-schema/typings.immutableTypes.ts ================================================ export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; allUsers: Array>; userById?: Maybe; }; export type QueryUserByIdArgs = { id: Scalars['Int']['input']; }; export type User = { __typename?: 'User'; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; ================================================ FILE: dev-test/test-schema/typings.ts ================================================ import { GraphQLResolveInfo } from 'graphql'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; allUsers: Array>; userById?: Maybe; }; export type QueryUserByIdArgs = { id: Scalars['Int']['input']; }; export type User = { __typename?: 'User'; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Boolean: ResolverTypeWrapper; Int: ResolverTypeWrapper; Query: ResolverTypeWrapper>; String: ResolverTypeWrapper; User: ResolverTypeWrapper; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Boolean: Scalars['Boolean']['output']; Int: Scalars['Int']['output']; Query: Record; String: Scalars['String']['output']; User: User; }; export type QueryResolvers< ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'] > = { allUsers?: Resolver>, ParentType, ContextType>; userById?: Resolver, ParentType, ContextType, RequireFields>; }; export type UserResolvers< ContextType = any, ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User'] > = { email?: Resolver; id?: Resolver; name?: Resolver; }; export type Resolvers = { Query?: QueryResolvers; User?: UserResolvers; }; ================================================ FILE: dev-test/test-schema/typings.wrapped.ts ================================================ declare namespace GraphQL { export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; allUsers: Array>; userById?: Maybe; }; export type QueryUserByIdArgs = { id: Scalars['Int']['input']; }; export type User = { __typename?: 'User'; email: Scalars['String']['output']; id: Scalars['Int']['output']; name: Scalars['String']['output']; }; } ================================================ FILE: dev-test/tsconfig.json ================================================ { "compilerOptions": { "esModuleInterop": true, "lib": ["esnext", "DOM"], "jsx": "react", "jsxFactory": "React.createElement", "skipLibCheck": true, "strict": true, "noImplicitAny": true, "noImplicitThis": true, "alwaysStrict": true, "noImplicitReturns": true, "noUnusedLocals": true, "noUnusedParameters": true, "experimentalDecorators": true }, "include": ["**/*.ts", "**/*.tsx"] } ================================================ FILE: dev-test-outer-dir/githunt/current-user.query.graphql ================================================ # When running `yarn watch:examples`, updating this file should trigger rebuild, # even though it's "outside" of the CWD of `dev-test/codegen.ts` query CurrentUserForProfileFromOutsideDirectory { currentUser { login avatar_url } } ================================================ FILE: dev-test-outer-dir/githunt/nothing-should-use-this-query.graphql ================================================ # This file should be excluded by all dev-test/codegen.ts patterns that otherwise # include files from dev-test-outer-dir, so that when running `yarn watch:examples`, # updating this file should _never_ trigger rebuild query NothingShouldUseThisQuery { currentUser { login avatar_url } } ================================================ FILE: examples/persisted-documents/README.md ================================================ # Yoga Persisted Documents Example Example for showing how to use GraphQL Code Generator for only allowing the execution of persisted operations. [Learn more about Yoga Persisted Operations](https://the-guild.dev/graphql/yoga-server/docs/features/persisted-operations) ## Usage Run `yarn codegen --watch` for starting GraphQL Code Generator in watch mode. Run `yarn test` for running a tests located within `yoga.spec.ts`. ================================================ FILE: examples/persisted-documents/babel.config.js ================================================ module.exports = { presets: [ ['@babel/preset-env', { targets: { node: process.versions.node.split('.')[0] } }], '@babel/preset-typescript', ], }; ================================================ FILE: examples/persisted-documents/codegen.ts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: './src/yoga.ts', documents: ['src/**/*.ts'], generates: { './src/gql/': { preset: 'client-preset', presetConfig: { persistedDocuments: true, }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/persisted-documents/package.json ================================================ { "name": "example-persisted-documents", "version": "0.0.0", "private": true, "dependencies": { "graphql-yoga": "5.7.0", "@graphql-yoga/plugin-persisted-operations": "3.7.0" }, "devDependencies": { "@graphql-typed-document-node/core": "3.2.0", "@graphql-codegen/cli": "6.2.1", "@babel/core": "7.25.2", "@babel/preset-env": "7.25.3", "@babel/preset-typescript": "7.28.5" }, "scripts": { "test": "vitest --no-watch", "codegen": "graphql-codegen --config codegen.ts", "build": "tsc", "test:end2end": "yarn test" }, "bob": false } ================================================ FILE: examples/persisted-documents/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/persisted-documents/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query HelloQuery {\n hello\n }\n': typeof types.HelloQueryDocument; }; const documents: Documents = { '\n query HelloQuery {\n hello\n }\n': types.HelloQueryDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query HelloQuery {\n hello\n }\n' ): (typeof documents)['\n query HelloQuery {\n hello\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/persisted-documents/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Mutation = { __typename?: 'Mutation'; echo: Scalars['String']['output']; }; export type MutationEchoArgs = { message: Scalars['String']['input']; }; export type Query = { __typename?: 'Query'; hello: Scalars['String']['output']; }; export type HelloQueryQueryVariables = Exact<{ [key: string]: never }>; export type HelloQueryQuery = { __typename?: 'Query'; hello: string }; export const HelloQueryDocument = { __meta__: { hash: '86f01e23de1c770cabbc35b2d87f2e5fd7557b6f' }, kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'HelloQuery' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'hello' } }] }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/persisted-documents/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/persisted-documents/src/gql/persisted-documents.json ================================================ { "86f01e23de1c770cabbc35b2d87f2e5fd7557b6f": "query HelloQuery { hello }" } ================================================ FILE: examples/persisted-documents/src/main.ts ================================================ import { createServer } from 'http'; import { makeYoga } from './yoga.js'; import persistedDocumentsDictionary from './gql/persisted-documents.json'; const persistedDocuments = new Map(Object.entries(persistedDocumentsDictionary)); const yoga = makeYoga({ persistedDocuments }); const server = createServer(yoga); // Start the server and you're done! server.listen(4000, () => { // eslint-disable-next-line no-console console.info('Server is running on http://localhost:4000/graphql'); }); ================================================ FILE: examples/persisted-documents/src/yoga.spec.ts ================================================ import { describe, it, expect } from 'vitest'; import { graphql } from './gql/index'; import { makeYoga } from './yoga'; import persistedDocumentsDictionary from './gql/persisted-documents.json'; import { print } from 'graphql'; const persistedDocuments = new Map(Object.entries(persistedDocumentsDictionary)); const HelloQuery = graphql(/* GraphQL */ ` query HelloQuery { hello } `); describe('Persisted Documents', () => { it('execute document without persisted operation enabled', async () => { const yoga = makeYoga({ persistedDocuments: null }); const result = await yoga.fetch('http://yoga/graphql', { method: 'POST', headers: { 'content-type': 'application/json', accept: 'application/json', }, body: JSON.stringify({ query: print(HelloQuery), }), }); expect(await result.json()).toMatchInlineSnapshot(` { "data": { "hello": "Hello world!", }, } `); }); it('can not execute arbitrary operation with persisted operations enabled', async () => { const yoga = makeYoga({ persistedDocuments }); const result = await yoga.fetch('http://yoga/graphql', { method: 'POST', headers: { 'content-type': 'application/json', accept: 'application/json', }, body: JSON.stringify({ query: print(HelloQuery), }), }); expect(await result.json()).toMatchInlineSnapshot(` { "errors": [ { "message": "PersistedQueryOnly", }, ], } `); }); it('can execute persisted operation with persisted operations enabled', async () => { const yoga = makeYoga({ persistedDocuments }); const result = await yoga.fetch('http://yoga/graphql', { method: 'POST', headers: { 'content-type': 'application/json', accept: 'application/json', }, body: JSON.stringify({ extensions: { persistedQuery: { version: 1, sha256Hash: (HelloQuery as any)['__meta__']['hash'], }, }, }), }); expect(await result.json()).toMatchInlineSnapshot(` { "data": { "hello": "Hello world!", }, } `); }); }); ================================================ FILE: examples/persisted-documents/src/yoga.ts ================================================ import { createSchema, createYoga, type Plugin } from 'graphql-yoga'; import { usePersistedOperations } from '@graphql-yoga/plugin-persisted-operations'; const schema = createSchema({ typeDefs: /* GraphQL */ ` type Query { hello: String! } type Mutation { echo(message: String!): String! } `, resolvers: { Query: { hello: () => 'Hello world!', }, Mutation: { echo: (_, args) => args.message, }, }, }); export function makeYoga(args: { persistedDocuments: null | Map }) { const plugins: Array> = []; if (args.persistedDocuments !== null) { const { persistedDocuments } = args; plugins.push( usePersistedOperations({ getPersistedOperation: hash => persistedDocuments.get(hash), }) ); } return createYoga({ schema, plugins, }); } ================================================ FILE: examples/persisted-documents/tsconfig.json ================================================ { "compilerOptions": { "target": "ES2018", "module": "Node16", "outDir": "dist", "resolveJsonModule": true, "skipLibCheck": true }, "include": ["src/**/*"] } ================================================ FILE: examples/persisted-documents/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'examples-persisted-documents', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: examples/persisted-documents-string-mode/README.md ================================================ # Yoga Persisted Documents Example Example for showing how to use GraphQL Code Generator for only allowing the execution of persisted operations. [Learn more about Yoga Persisted Operations](https://the-guild.dev/graphql/yoga-server/docs/features/persisted-operations) ## Usage Run `yarn codegen --watch` for starting GraphQL Code Generator in watch mode. Run `yarn test` for running a tests located within `yoga.spec.ts`. ================================================ FILE: examples/persisted-documents-string-mode/babel.config.js ================================================ module.exports = { presets: [ ['@babel/preset-env', { targets: { node: process.versions.node.split('.')[0] } }], '@babel/preset-typescript', ], }; ================================================ FILE: examples/persisted-documents-string-mode/codegen.ts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: './src/yoga.ts', documents: ['src/**/*.ts'], generates: { './src/gql/': { preset: 'client-preset', presetConfig: { persistedDocuments: true, }, config: { documentMode: 'string', }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/persisted-documents-string-mode/package.json ================================================ { "name": "example-persisted-documents-string-mode", "version": "0.0.0", "private": true, "dependencies": { "graphql-yoga": "5.7.0", "@graphql-yoga/plugin-persisted-operations": "3.7.0" }, "devDependencies": { "@graphql-typed-document-node/core": "3.2.0", "@graphql-codegen/cli": "6.2.1", "@babel/core": "7.25.2", "@babel/preset-env": "7.25.3", "@babel/preset-typescript": "7.28.5" }, "scripts": { "test": "vitest --no-watch", "codegen": "graphql-codegen --config codegen.ts", "build": "tsc", "test:end2end": "yarn test" }, "bob": false } ================================================ FILE: examples/persisted-documents-string-mode/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; import { Incremental, TypedDocumentString } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: TypedDocumentString, fragmentNode: TypedDocumentString, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = queryNode.__meta__?.deferredFields as Record; const fragName = fragmentNode.__meta__?.fragmentName as string | undefined; if (!deferredFields || !fragName) return true; const fields = deferredFields[fragName] ?? []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/persisted-documents-string-mode/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query HelloQuery {\n hello\n }\n': typeof types.HelloQueryDocument; }; const documents: Documents = { '\n query HelloQuery {\n hello\n }\n': types.HelloQueryDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query HelloQuery {\n hello\n }\n' ): typeof import('./graphql').HelloQueryDocument; export function graphql(source: string) { return (documents as any)[source] ?? {}; } ================================================ FILE: examples/persisted-documents-string-mode/src/gql/graphql.ts ================================================ /* eslint-disable */ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Mutation = { __typename?: 'Mutation'; echo: Scalars['String']['output']; }; export type MutationEchoArgs = { message: Scalars['String']['input']; }; export type Query = { __typename?: 'Query'; hello: Scalars['String']['output']; }; export type HelloQueryQueryVariables = Exact<{ [key: string]: never }>; export type HelloQueryQuery = { __typename?: 'Query'; hello: string }; export class TypedDocumentString extends String implements DocumentTypeDecoration { __apiType?: NonNullable['__apiType']>; private value: string; public __meta__?: Record | undefined; constructor(value: string, __meta__?: Record | undefined) { super(value); this.value = value; this.__meta__ = __meta__; } override toString(): string & DocumentTypeDecoration { return this.value; } } export const HelloQueryDocument = new TypedDocumentString( ` query HelloQuery { hello } `, { hash: '86f01e23de1c770cabbc35b2d87f2e5fd7557b6f' } ) as unknown as TypedDocumentString; ================================================ FILE: examples/persisted-documents-string-mode/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/persisted-documents-string-mode/src/gql/persisted-documents.json ================================================ { "86f01e23de1c770cabbc35b2d87f2e5fd7557b6f": "query HelloQuery { hello }" } ================================================ FILE: examples/persisted-documents-string-mode/src/main.ts ================================================ import { createServer } from 'http'; import { makeYoga } from './yoga.js'; import persistedDocumentsDictionary from './gql/persisted-documents.json'; const persistedDocuments = new Map(Object.entries(persistedDocumentsDictionary)); const yoga = makeYoga({ persistedDocuments }); const server = createServer(yoga); // Start the server and you're done! server.listen(4000, () => { // eslint-disable-next-line no-console console.info('Server is running on http://localhost:4000/graphql'); }); ================================================ FILE: examples/persisted-documents-string-mode/src/yoga.spec.ts ================================================ import { describe, it, expect } from 'vitest'; import { graphql } from './gql/index'; import { makeYoga } from './yoga'; import persistedDocumentsDictionary from './gql/persisted-documents.json'; const persistedDocuments = new Map(Object.entries(persistedDocumentsDictionary)); const HelloQuery = graphql(/* GraphQL */ ` query HelloQuery { hello } `); describe('Persisted Documents', () => { it('execute document without persisted operation enabled', async () => { const yoga = makeYoga({ persistedDocuments: null }); const result = await yoga.fetch('http://yoga/graphql', { method: 'POST', headers: { 'content-type': 'application/json', accept: 'application/json', }, body: JSON.stringify({ query: HelloQuery, }), }); expect(await result.json()).toMatchInlineSnapshot(` { "data": { "hello": "Hello world!", }, } `); }); it('can not execute arbitrary operation with persisted operations enabled', async () => { const yoga = makeYoga({ persistedDocuments }); const result = await yoga.fetch('http://yoga/graphql', { method: 'POST', headers: { 'content-type': 'application/json', accept: 'application/json', }, body: JSON.stringify({ query: HelloQuery, }), }); expect(await result.json()).toMatchInlineSnapshot(` { "errors": [ { "message": "PersistedQueryOnly", }, ], } `); }); it('can execute persisted operation with persisted operations enabled', async () => { const yoga = makeYoga({ persistedDocuments }); const result = await yoga.fetch('http://yoga/graphql', { method: 'POST', headers: { 'content-type': 'application/json', accept: 'application/json', }, body: JSON.stringify({ extensions: { persistedQuery: { version: 1, sha256Hash: (HelloQuery as any)['__meta__']['hash'], }, }, }), }); expect(await result.json()).toMatchInlineSnapshot(` { "data": { "hello": "Hello world!", }, } `); }); }); ================================================ FILE: examples/persisted-documents-string-mode/src/yoga.ts ================================================ import { createSchema, createYoga, type Plugin } from 'graphql-yoga'; import { usePersistedOperations } from '@graphql-yoga/plugin-persisted-operations'; const schema = createSchema({ typeDefs: /* GraphQL */ ` type Query { hello: String! } type Mutation { echo(message: String!): String! } `, resolvers: { Query: { hello: () => 'Hello world!', }, Mutation: { echo: (_, args) => args.message, }, }, }); export function makeYoga(args: { persistedDocuments: null | Map }) { const plugins: Array> = []; if (args.persistedDocuments !== null) { const { persistedDocuments } = args; plugins.push( usePersistedOperations({ getPersistedOperation: hash => persistedDocuments.get(hash), }) ); } return createYoga({ schema, plugins, }); } ================================================ FILE: examples/persisted-documents-string-mode/tsconfig.json ================================================ { "compilerOptions": { "target": "ES2018", "module": "Node16", "outDir": "dist", "resolveJsonModule": true, "skipLibCheck": true }, "include": ["src/**/*"] } ================================================ FILE: examples/persisted-documents-string-mode/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'examples-persisted-documents-string-mode', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: examples/programmatic-typescript/package.json ================================================ { "name": "example-programmatic-typescript", "version": "0.0.1", "private": true, "scripts": { "start:cjs": "tsup --onSuccess \"node dist/index.js\"", "start:mjs": "tsup --onSuccess \"node dist/index.mjs\"", "codegen": "exit 0", "build": "yarn start:cjs && yarn start:mjs", "test:end2end": "exit 0" }, "dependencies": { "@graphql-codegen/core": "5.0.1", "@graphql-codegen/plugin-helpers": "6.2.0", "@graphql-codegen/typed-document-node": "6.1.7", "@graphql-codegen/typescript": "5.0.9", "@graphql-codegen/typescript-operations": "5.0.9", "@graphql-codegen/typescript-resolvers": "5.1.7", "@graphql-tools/graphql-file-loader": "^8.1.12", "@graphql-tools/load": "8.1.0", "@graphql-tools/schema": "10.0.6", "graphql": "16.9.0", "graphql-tag": "2.12.6", "prettier": "2.8.8" }, "devDependencies": { "@types/node": "22.10.7", "tsup": "8.2.4" } } ================================================ FILE: examples/programmatic-typescript/src/gql.generated.ts ================================================ import type { GraphQLResolveInfo } from 'graphql'; import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; hello: Scalars['String']['output']; }; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Query: ResolverTypeWrapper>; String: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Query: Record; String: Scalars['String']['output']; Boolean: Scalars['Boolean']['output']; }; export type QueryResolvers< ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'] > = { hello?: Resolver; }; export type Resolvers = { Query?: QueryResolvers; }; export type HelloQueryVariables = Exact<{ [key: string]: never }>; export type HelloQuery = { __typename?: 'Query'; hello: string }; export const HelloDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'hello' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'hello' } }] }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/programmatic-typescript/src/graphql/hello.gql ================================================ query hello { hello } ================================================ FILE: examples/programmatic-typescript/src/index.ts ================================================ /* eslint-disable no-console */ import { promises } from 'node:fs'; import { codegen } from '@graphql-codegen/core'; import { getCachedDocumentNodeFromSchema } from '@graphql-codegen/plugin-helpers'; import * as typedDocumentNode from '@graphql-codegen/typed-document-node'; import * as typescript from '@graphql-codegen/typescript'; import * as typescriptOperations from '@graphql-codegen/typescript-operations'; import * as typescriptResolvers from '@graphql-codegen/typescript-resolvers'; import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'; import { loadDocuments } from '@graphql-tools/load'; import { makeExecutableSchema } from '@graphql-tools/schema'; import gql from 'graphql-tag'; import prettier from 'prettier'; import type { Resolvers } from './gql.generated.js'; const schema = makeExecutableSchema({ typeDefs: gql` type Query { hello: String! } `, resolvers: { Query: { hello(_root, _args, _ctx) { return 'world'; }, }, } as Resolvers, }); (async () => { const loadedDocuments = await loadDocuments(['src/graphql/**/*.gql'], { loaders: [new GraphQLFileLoader()], }); const config: typescript.TypeScriptPluginConfig & typescriptResolvers.TypeScriptResolversPluginConfig & typescriptOperations.TypeScriptDocumentsPluginConfig & typedDocumentNode.TypeScriptTypedDocumentNodesConfig = { useTypeImports: true, }; const schemaAsDocumentNode = getCachedDocumentNodeFromSchema(schema); const codegenCode = await codegen({ schema: schemaAsDocumentNode, schemaAst: schema, config, documents: loadedDocuments, filename: 'gql.generated.ts', pluginMap: { typescript, typescriptResolvers, typescriptOperations, typedDocumentNode, }, plugins: [ { typescript: {}, }, { typescriptResolvers: {}, }, { typescriptOperations: {}, }, { typedDocumentNode: {}, }, ], }); await promises.writeFile( 'src/gql.generated.ts', prettier.format(codegenCode, { ...(await prettier.resolveConfig(process.cwd())), parser: 'typescript', }), 'utf8' ); console.log('done generating.'); })().catch(err => { console.error(err); process.exit(1); }); ================================================ FILE: examples/programmatic-typescript/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "target": "es2020", "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "rootDir": "../../" }, "include": ["src/**/*.ts"] } ================================================ FILE: examples/programmatic-typescript/tsup.config.ts ================================================ export const tsup: import('tsup').Options = { target: 'es2019', entryPoints: ['src/index.ts'], format: ['cjs', 'esm'], ignoreWatch: ['src/ez.generated.ts'], }; ================================================ FILE: examples/react/apollo-client/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: examples/react/apollo-client/README.md ================================================ # Using GraphQL Code Generator with Apollo Client and React This example illustrates how to use GraphQL Code Generator in a React application using the Apollo React GraphQL Client. You will find the TypeScript-based codegen configuration in [`codegen.ts`](./codegen.ts). This simple codegen configuration generates types and helpers in the [`src/gql`](./src/gql/) folder that help you to get typed GraphQL Queries and Mutations seamlessly ⚡️
    For a step-by-step implementation tutorial, please refer to the related guide: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular -- Please note that the `client` preset used in this example is compatible with `@apollo/client` (since `3.2.0`, not when using React Components (``)). ================================================ FILE: examples/react/apollo-client/codegen.ts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/react/apollo-client/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/react/apollo-client/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/react/apollo-client/cypress/support/e2e.ts ================================================ // Import commands.js using ES2015 syntax: import './commands'; ================================================ FILE: examples/react/apollo-client/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/react/apollo-client/index.html ================================================ Vite App
    ================================================ FILE: examples/react/apollo-client/package.json ================================================ { "name": "example-react-apollo-client", "version": "0.1.0", "private": true, "dependencies": { "@apollo/client": "^3.7.10", "graphql": "^16.6.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@graphql-codegen/cli": "^6.2.1", "@vitejs/plugin-react": "^5.0.0", "@types/node": "^22.0.0", "@types/react": "^18.0.15", "@types/react-dom": "^18.0.10", "typescript": "5.5.4", "serve": "14.2.3", "cypress": "15.7.1", "start-server-and-test": "2.0.5", "vite": "^6.0.0" }, "scripts": { "dev": "vite", "build": "vite build", "start": "serve -s dist", "test": "cypress run", "test:end2end": "start-server-and-test start http://localhost:3000 test", "codegen": "graphql-codegen --config codegen.ts" } } ================================================ FILE: examples/react/apollo-client/src/App.css ================================================ .App { text-align: center; } .App-logo { height: 40vmin; pointer-events: none; } @media (prefers-reduced-motion: no-preference) { .App-logo { animation: App-logo-spin infinite 20s linear; } } .App-header { background-color: #282c34; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; } .App-link { color: #61dafb; } @keyframes App-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ================================================ FILE: examples/react/apollo-client/src/App.tsx ================================================ import React from 'react'; import { useQuery } from '@apollo/client'; import './App.css'; import Film from './Film'; import { graphql } from './gql/gql'; const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `); function App() { const { data } = useQuery(allFilmsWithVariablesQueryDocument, { variables: { first: 10 } }); return (
    {data &&
      {data.allFilms?.edges?.map((e, i) => e?.node && )}
    }
    ); } export default App; ================================================ FILE: examples/react/apollo-client/src/Film.tsx ================================================ import { graphql, FragmentType, useFragment } from './gql'; export const FilmFragment = graphql(/* GraphQL */ ` fragment FilmItem on Film { id title releaseDate producers } `); const Film = (props: { film: FragmentType }) => { const film = useFragment(FilmFragment, props.film); return (

    {film.title}

    {film.releaseDate}

    ); }; export default Film; ================================================ FILE: examples/react/apollo-client/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/react/apollo-client/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': typeof types.AllFilmsWithVariablesQueryDocument; '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; }; const documents: Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': types.AllFilmsWithVariablesQueryDocument, '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/react/apollo-client/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/react/apollo-client/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/react/apollo-client/src/main.css ================================================ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } ================================================ FILE: examples/react/apollo-client/src/main.tsx ================================================ import React from 'react'; import ReactDOM from 'react-dom/client'; import './main.css'; import App from './App'; import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'; const client = new ApolloClient({ uri: 'https://graphql.org/graphql/', cache: new InMemoryCache(), }); const root = ReactDOM.createRoot(document.getElementById('app') as HTMLElement); root.render( ); ================================================ FILE: examples/react/apollo-client/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/react/apollo-client/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/react/apollo-client/vite.config.ts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/react/apollo-client-defer/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: examples/react/apollo-client-defer/README.md ================================================ # Using GraphQL Code Generator with Apollo Client and React This example illustrates how to use GraphQL Code Generator in a React application using the Apollo React GraphQL Client. You will find the TypeScript-based codegen configuration in [`codegen.ts`](./codegen.ts). This simple codegen configuration generates types and helpers in the [`src/gql`](./src/gql/) folder that help you to get typed GraphQL Queries and Mutations seamlessly ⚡️
    For a step-by-step implementation tutorial, please refer to the related guide: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular -- Please note that the `client` preset used in this example is compatible with `@apollo/client` (since `3.2.0`, not when using React Components (``)). ================================================ FILE: examples/react/apollo-client-defer/codegen.ts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: './src/yoga.mjs', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/react/apollo-client-defer/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('.App').should('contain', 'I am speed'); cy.get('.App').should('not.contain', 'I am slow'); cy.wait(5000); cy.get('.App').should('contain', 'I am slow'); cy.get('.App').should('contain', 'I am slow inlined fragment'); }); }); ================================================ FILE: examples/react/apollo-client-defer/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/react/apollo-client-defer/cypress/support/e2e.ts ================================================ // Import commands.js using ES2015 syntax: import './commands'; ================================================ FILE: examples/react/apollo-client-defer/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/react/apollo-client-defer/index.html ================================================ Vite App
    ================================================ FILE: examples/react/apollo-client-defer/package.json ================================================ { "name": "example-react-apollo-client-defer", "version": "0.1.0", "private": true, "dependencies": { "@apollo/client": "^3.7.10", "@graphql-yoga/plugin-defer-stream": "^3.0.0", "graphql": "^16.6.0", "react": "^18.2.0", "react-dom": "^18.2.0", "graphql-yoga": "5.7.0" }, "devDependencies": { "@graphql-codegen/cli": "^6.2.1", "@types/node": "^22.0.0", "@types/react": "^18.0.15", "@types/react-dom": "^18.0.10", "@vitejs/plugin-react": "^5.0.0", "cypress": "15.7.1", "serve": "14.2.3", "start-server-and-test": "2.0.5", "typescript": "5.5.4", "vite": "^6.0.0" }, "scripts": { "dev": "vite", "build": "vite build", "start:yoga": "node src/yoga.mjs", "start": "yarn start:yoga & serve -s dist", "test": "cypress run", "test:end2end": "start-server-and-test start http://localhost:3000 test", "codegen": "graphql-codegen --config codegen.ts" } } ================================================ FILE: examples/react/apollo-client-defer/src/App.tsx ================================================ import { useQuery } from '@apollo/client'; import { useFragment, graphql, FragmentType, isFragmentReady, DocumentType } from './gql'; export const slowFieldFragment = graphql(/* GraphQL */ ` fragment SlowFieldFragment on Query { slowField(waitFor: 5000) } `); const alphabetQuery = graphql(/* GraphQL */ ` query SlowAndFastFieldWithDefer { fastField ...SlowFieldFragment @defer ... @defer { inlinedSlowField: slowField(waitFor: 5000) } } `); const SlowDataField = (props: { data: FragmentType }) => { const data = useFragment(slowFieldFragment, props.data); return

    {data.slowField}

    ; }; const InlinedSlowDataField = (props: { data: DocumentType }) => { try { // @ts-expect-error - this field should be either undefined or a string const _ = props.data.inlinedSlowField.toLowerCase(); } catch (e) {} if (!props.data.inlinedSlowField) { return null; } return

    {props.data.inlinedSlowField} inlined fragment

    ; }; function App() { const { data } = useQuery(alphabetQuery); return (
    {data && ( <>

    {data.fastField}

    {isFragmentReady(alphabetQuery, slowFieldFragment, data) && } )}
    ); } export default App; ================================================ FILE: examples/react/apollo-client-defer/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/react/apollo-client-defer/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n fragment SlowFieldFragment on Query {\n slowField(waitFor: 5000)\n }\n': typeof types.SlowFieldFragmentFragmentDoc; '\n query SlowAndFastFieldWithDefer {\n fastField\n ...SlowFieldFragment @defer\n\n ... @defer {\n inlinedSlowField: slowField(waitFor: 5000)\n }\n }\n': typeof types.SlowAndFastFieldWithDeferDocument; }; const documents: Documents = { '\n fragment SlowFieldFragment on Query {\n slowField(waitFor: 5000)\n }\n': types.SlowFieldFragmentFragmentDoc, '\n query SlowAndFastFieldWithDefer {\n fastField\n ...SlowFieldFragment @defer\n\n ... @defer {\n inlinedSlowField: slowField(waitFor: 5000)\n }\n }\n': types.SlowAndFastFieldWithDeferDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment SlowFieldFragment on Query {\n slowField(waitFor: 5000)\n }\n' ): (typeof documents)['\n fragment SlowFieldFragment on Query {\n slowField(waitFor: 5000)\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query SlowAndFastFieldWithDefer {\n fastField\n ...SlowFieldFragment @defer\n\n ... @defer {\n inlinedSlowField: slowField(waitFor: 5000)\n }\n }\n' ): (typeof documents)['\n query SlowAndFastFieldWithDefer {\n fastField\n ...SlowFieldFragment @defer\n\n ... @defer {\n inlinedSlowField: slowField(waitFor: 5000)\n }\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/react/apollo-client-defer/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Query = { __typename?: 'Query'; alphabet: Array; /** A field that resolves fast. */ fastField: Scalars['String']['output']; /** * A field that resolves slowly. * Maybe you want to @defer this field ;) */ slowField: Scalars['String']['output']; }; export type QuerySlowFieldArgs = { waitFor?: Scalars['Int']['input']; }; export type SlowFieldFragmentFragment = { __typename?: 'Query'; slowField: string } & { ' $fragmentName'?: 'SlowFieldFragmentFragment'; }; export type SlowAndFastFieldWithDeferQueryVariables = Exact<{ [key: string]: never }>; export type SlowAndFastFieldWithDeferQuery = { __typename?: 'Query'; fastField: string } & ( | { __typename?: 'Query'; inlinedSlowField: string } | { __typename?: 'Query'; inlinedSlowField?: never } ) & ({ __typename?: 'Query' } & { ' $fragmentRefs'?: { SlowFieldFragmentFragment: Incremental }; }); export const SlowFieldFragmentFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'SlowFieldFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Query' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'slowField' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'waitFor' }, value: { kind: 'IntValue', value: '5000' }, }, ], }, ], }, }, ], } as unknown as DocumentNode; export const SlowAndFastFieldWithDeferDocument = { __meta__: { deferredFields: { SlowFieldFragment: ['slowField'] } }, kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'SlowAndFastFieldWithDefer' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'fastField' } }, { kind: 'FragmentSpread', name: { kind: 'Name', value: 'SlowFieldFragment' }, directives: [{ kind: 'Directive', name: { kind: 'Name', value: 'defer' } }], }, { kind: 'InlineFragment', directives: [{ kind: 'Directive', name: { kind: 'Name', value: 'defer' } }], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', alias: { kind: 'Name', value: 'inlinedSlowField' }, name: { kind: 'Name', value: 'slowField' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'waitFor' }, value: { kind: 'IntValue', value: '5000' }, }, ], }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'SlowFieldFragment' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Query' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'slowField' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'waitFor' }, value: { kind: 'IntValue', value: '5000' }, }, ], }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/react/apollo-client-defer/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/react/apollo-client-defer/src/main.tsx ================================================ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'; const client = new ApolloClient({ uri: 'http://localhost:4000/graphql', cache: new InMemoryCache(), }); const root = ReactDOM.createRoot(document.getElementById('app') as HTMLElement); root.render( ); ================================================ FILE: examples/react/apollo-client-defer/src/yoga.mjs ================================================ import { createSchema, createYoga } from 'graphql-yoga'; import { useDeferStream } from '@graphql-yoga/plugin-defer-stream'; import { createServer } from 'node:http'; const typeDefs = /* GraphQL */ ` type Query { alphabet: [String!]! """ A field that resolves fast. """ fastField: String! """ A field that resolves slowly. Maybe you want to @defer this field ;) """ slowField(waitFor: Int! = 5000): String! } `; const wait = time => new Promise(resolve => setTimeout(resolve, time)); const resolvers = { Query: { async *alphabet() { for (const character of ['a', 'b', 'c', 'd', 'e', 'f', 'g']) { yield character; await wait(1000); } }, fastField: async () => { await wait(100); return 'I am speed'; }, slowField: async (_, { waitFor }) => { await wait(waitFor); return 'I am slow'; }, }, }; export const yoga = createYoga({ schema: createSchema({ typeDefs, resolvers, }), plugins: [useDeferStream()], }); const server = createServer(yoga); server.listen(4000, () => { // eslint-disable-next-line no-console console.info('Server is running on http://localhost:4000/graphql'); }); ================================================ FILE: examples/react/apollo-client-defer/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true, "noUncheckedIndexedAccess": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/react/apollo-client-defer/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/react/apollo-client-defer/vite.config.ts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/react/apollo-client-swc-plugin/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* .swc ================================================ FILE: examples/react/apollo-client-swc-plugin/README.md ================================================ # Apollo Client Vite SWR Example Example of using the SWC plugin for smaller bundle size. ```bash yarn dev ``` ================================================ FILE: examples/react/apollo-client-swc-plugin/codegen.ts ================================================ import { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx', '!src/gql/**/*'], generates: { './src/gql/': { preset: 'client', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/react/apollo-client-swc-plugin/index.html ================================================ Vite App
    ================================================ FILE: examples/react/apollo-client-swc-plugin/package.json ================================================ { "name": "example-apollo-client-swc-plugin", "version": "0.1.0", "private": true, "dependencies": { "@apollo/client": "^3.7.10", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { "@graphql-codegen/client-preset-swc-plugin": "0.2.0", "@graphql-codegen/cli": "^6.2.1", "@vitejs/plugin-react-swc": "^3.3.0", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", "typescript": "5.5.4", "vite": "^6.0.0" }, "scripts": { "dev": "vite", "build": "vite build", "test": "node scripts/test.js", "test:end2end": "exit 0", "codegen": "graphql-codegen --config codegen.ts" } } ================================================ FILE: examples/react/apollo-client-swc-plugin/src/App.css ================================================ .App { text-align: center; } .App-logo { height: 40vmin; pointer-events: none; } @media (prefers-reduced-motion: no-preference) { .App-logo { animation: App-logo-spin infinite 20s linear; } } .App-header { background-color: #282c34; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; } .App-link { color: #61dafb; } @keyframes App-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ================================================ FILE: examples/react/apollo-client-swc-plugin/src/App.tsx ================================================ import { useQuery } from '@apollo/client'; import './App.css'; import Film from './Film'; import { graphql } from './gql'; const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `); function App() { const { data } = useQuery(allFilmsWithVariablesQueryDocument, { variables: { first: 10 } }); return (
    {data &&
      {data.allFilms?.edges?.map((e, i) => e?.node && )}
    }
    ); } export default App; ================================================ FILE: examples/react/apollo-client-swc-plugin/src/Film.tsx ================================================ import { FragmentType, useFragment } from './gql/fragment-masking'; import { graphql } from './gql'; export const FilmFragment = graphql(/* GraphQL */ ` fragment FilmItem on Film { id title releaseDate producers } `); const Film = (props: { film: FragmentType }) => { const film = useFragment(FilmFragment, props.film); return (

    {film.title}

    {film.releaseDate}

    ); }; export default Film; ================================================ FILE: examples/react/apollo-client-swc-plugin/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/react/apollo-client-swc-plugin/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': typeof types.AllFilmsWithVariablesQueryDocument; '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; }; const documents: Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': types.AllFilmsWithVariablesQueryDocument, '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/react/apollo-client-swc-plugin/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/react/apollo-client-swc-plugin/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/react/apollo-client-swc-plugin/src/main.css ================================================ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } ================================================ FILE: examples/react/apollo-client-swc-plugin/src/main.tsx ================================================ import React from 'react'; import ReactDOM from 'react-dom/client'; import './main.css'; import App from './App'; import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'; const client = new ApolloClient({ uri: 'https://graphql.org/graphql/', cache: new InMemoryCache(), }); const root = ReactDOM.createRoot(document.getElementById('app') as HTMLElement); root.render( ); ================================================ FILE: examples/react/apollo-client-swc-plugin/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/react/apollo-client-swc-plugin/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.mts"] } ================================================ FILE: examples/react/apollo-client-swc-plugin/vite.config.mts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [ react({ plugins: [ ['@graphql-codegen/client-preset-swc-plugin', { artifactDirectory: './src/gql', gqlTagName: 'graphql' }], ], }), ], }); ================================================ FILE: examples/react/http-executor/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: examples/react/http-executor/README.md ================================================ # Using GraphQL Code Generator with `graphql-request` and React This example illustrates how to use GraphQL Code Generator in a React application using the `graphql-request` GraphQL Client. You will find the TypeScript-based codegen configuration in [`codegen.ts`](./codegen.ts). This simple codegen configuration generates types and helpers in the [`src/gql`](./src/gql/) folder that help you to get typed GraphQL Queries and Mutations seamlessly ⚡️
    For a step-by-step implementation tutorial, please refer to the related guide: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular -- Please note that the `client` preset used in this example is compatible with `graphql-request` from `5.0`. ================================================ FILE: examples/react/http-executor/codegen.ts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/react/http-executor/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/react/http-executor/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/react/http-executor/cypress/support/e2e.ts ================================================ import './commands'; ================================================ FILE: examples/react/http-executor/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/react/http-executor/index.html ================================================ Vite App
    ================================================ FILE: examples/react/http-executor/package.json ================================================ { "name": "example-react-graphql-request", "version": "0.1.0", "private": true, "dependencies": { "@graphql-tools/executor-http": "^3.0.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@graphql-codegen/cli": "^6.2.1", "@vitejs/plugin-react": "^5.0.0", "@types/node": "^22.0.0", "@types/react": "^18.0.17", "@types/react-dom": "^18.0.10", "typescript": "5.5.4", "serve": "14.2.3", "cypress": "15.7.1", "start-server-and-test": "2.0.5", "vite": "^6.0.0" }, "scripts": { "dev": "vite", "build": "vite build", "start": "serve -s dist", "test": "cypress run", "test:end2end": "start-server-and-test start http://localhost:3000 test", "codegen": "graphql-codegen --config codegen.ts" } } ================================================ FILE: examples/react/http-executor/src/App.css ================================================ .App { text-align: center; } .App-logo { height: 40vmin; pointer-events: none; } @media (prefers-reduced-motion: no-preference) { .App-logo { animation: App-logo-spin infinite 20s linear; } } .App-header { background-color: #282c34; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; } .App-link { color: #61dafb; } @keyframes App-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ================================================ FILE: examples/react/http-executor/src/App.tsx ================================================ import { useEffect, useState } from 'react'; import { buildHTTPExecutor } from '@graphql-tools/executor-http'; import './App.css'; import Film from './Film'; import { graphql, DocumentType } from './gql'; const executor = buildHTTPExecutor({ endpoint: 'https://graphql.org/graphql/', }); const AllFilmsWithVariablesQuery = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `); // we could also define a client: // `const client = new GraphQLClient('https://graphql.org/graphql/')` // and use: // `client.request(allFilmsWithVariablesQueryDocument, { first: 10 })` function App() { const [data, setData] = useState>(); useEffect(() => { executor({ document: AllFilmsWithVariablesQuery, variables: { first: 10, }, }).then(result => { if ('data' in result) { setData(result.data!); } }); }, []); return (
    {data &&
      {data.allFilms?.edges?.map((e, i) => e?.node && )}
    }
    ); } export default App; ================================================ FILE: examples/react/http-executor/src/Film.tsx ================================================ import { FragmentType, useFragment, graphql } from './gql'; export const FilmFragment = graphql(/* GraphQL */ ` fragment FilmItem on Film { id title releaseDate producers } `); const Film = (props: { /* tweet property has the correct type 🎉 */ film: FragmentType; }) => { const film = useFragment(FilmFragment, props.film); return (

    {film.title}

    {film.releaseDate}

    ); }; export default Film; ================================================ FILE: examples/react/http-executor/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/react/http-executor/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': typeof types.AllFilmsWithVariablesQueryDocument; '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; }; const documents: Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': types.AllFilmsWithVariablesQueryDocument, '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/react/http-executor/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/react/http-executor/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/react/http-executor/src/main.css ================================================ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } ================================================ FILE: examples/react/http-executor/src/main.tsx ================================================ import React from 'react'; import ReactDOM from 'react-dom/client'; import './main.css'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('app') as HTMLElement); root.render( ); ================================================ FILE: examples/react/http-executor/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/react/http-executor/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/react/http-executor/vite.config.ts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/react/nextjs-swr/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # next.js /.next/ /out/ # production /build # misc .DS_Store *.pem # debug npm-debug.log* yarn-debug.log* yarn-error.log* .pnpm-debug.log* # local env files .env*.local # vercel .vercel # typescript *.tsbuildinfo next-env.d.ts ================================================ FILE: examples/react/nextjs-swr/README.md ================================================ # Using GraphQL Code Generator with SWR and React This example illustrates using GraphQL Code Generator in a React application using SWR with `graphql-request` as a GraphQL Client. You will find the TypeScript-based codegen configuration in [`codegen.ts`](./codegen.ts). This simple codegen configuration generates types and helpers in the [`src/gql`](./src/gql/) folder that help you to get typed GraphQL Queries and Mutations seamlessly ⚡️
    For a step-by-step implementation tutorial, please refer to the related guide: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular -- Please note that the `client` preset used in this example is compatible with `graphql-request` from `5.0` as SWR fetcher. For indications in writing your fetcher, [please refer to our documentation](https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular#appendix-i-react-query-with-a-custom-fetcher-setup). ================================================ FILE: examples/react/nextjs-swr/codegen.ts ================================================ import { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['components/**/*.tsx', 'pages/**/*.tsx'], generates: { './gql/': { preset: 'client', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/react/nextjs-swr/components/Film.tsx ================================================ import { FragmentType, useFragment } from '../gql/fragment-masking'; import { graphql } from '../gql/gql'; export const FilmFragment = graphql(/* GraphQL */ ` fragment FilmItem on Film { id title releaseDate producers } `); const Film = (props: { /* tweet property has the correct type 🎉 */ film: FragmentType; }) => { const film = useFragment(FilmFragment, props.film); return (

    {film.title}

    {film.releaseDate}

    ); }; export default Film; ================================================ FILE: examples/react/nextjs-swr/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); // lol, this is a hack to make the file a module and nextjs build happy export {}; ================================================ FILE: examples/react/nextjs-swr/cypress/support/commands.ts ================================================ /// export {}; ================================================ FILE: examples/react/nextjs-swr/cypress/support/e2e.ts ================================================ import './commands'; ================================================ FILE: examples/react/nextjs-swr/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/react/nextjs-swr/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/react/nextjs-swr/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': typeof types.AllFilmsWithVariablesQueryDocument; }; const documents: Documents = { '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': types.AllFilmsWithVariablesQueryDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/react/nextjs-swr/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/react/nextjs-swr/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/react/nextjs-swr/hooks/use-query.ts ================================================ import { buildHTTPExecutor } from '@graphql-tools/executor-http'; import { TypedDocumentNode } from '@graphql-typed-document-node/core'; import { ASTNode, ExecutionResult, Kind, OperationDefinitionNode } from 'graphql'; import useSWR from 'swr'; const executor = buildHTTPExecutor({ endpoint: 'https://graphql.org/graphql/', }); const isOperationDefinition = (def: ASTNode): def is OperationDefinitionNode => def.kind === Kind.OPERATION_DEFINITION; export function useGraphQL( document: TypedDocumentNode, ...[variables]: TVariables extends Record ? [] : [TVariables] ) { return useSWR( [ // This logic can be customized as desired document.definitions.find(isOperationDefinition)?.name, variables, ] as const, async ([_key, variables]: any) => executor({ document, variables, }) as Promise> ); } ================================================ FILE: examples/react/nextjs-swr/next.config.js ================================================ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, swcMinify: true, experimental: { swcPlugins: [['@graphql-codegen/client-preset-swc-plugin', { artifactDirectory: './gql', gqlTagName: 'graphql' }]], }, }; module.exports = nextConfig; ================================================ FILE: examples/react/nextjs-swr/package.json ================================================ { "name": "example-react-nextjs-swr", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "codegen": "graphql-codegen --config codegen.ts", "test": "cypress run", "test:end2end": "start-server-and-test start http://127.0.0.1:3000 test" }, "dependencies": { "@graphql-tools/executor-http": "^3.0.0", "next": "13.5.11", "react": "^18.2.0", "react-dom": "^18.2.0", "swr": "^2.0.0" }, "devDependencies": { "@graphql-codegen/cli": "^6.2.1", "@graphql-codegen/schema-ast": "5.0.1", "@graphql-codegen/client-preset-swc-plugin": "0.2.0", "@types/node": "^22.0.0", "@types/react": "^18.0.17", "@types/react-dom": "^18.0.10", "eslint": "^9.0.0", "eslint-config-next": "^13.0.0", "typescript": "5.5.4" } } ================================================ FILE: examples/react/nextjs-swr/pages/_app.tsx ================================================ import '../styles/globals.css'; import type { AppProps } from 'next/app'; function MyApp({ Component, pageProps }: AppProps) { return ; } export default MyApp; ================================================ FILE: examples/react/nextjs-swr/pages/api/hello.ts ================================================ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction import type { NextApiRequest, NextApiResponse } from 'next'; type Data = { name: string; }; export default function handler(req: NextApiRequest, res: NextApiResponse) { res.status(200).json({ name: 'John Doe' }); } ================================================ FILE: examples/react/nextjs-swr/pages/index.tsx ================================================ import type { NextPage } from 'next'; import { graphql } from '../gql'; import styles from '../styles/Home.module.css'; import Film from '../components/Film'; import { useGraphQL } from '../hooks/use-query'; const AllFilmsWithVariablesQuery = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `); const Home: NextPage = () => { const { data } = useGraphQL(AllFilmsWithVariablesQuery, { first: 10 }); return (
    {data && (
      {data.data?.allFilms?.edges?.map((e, i) => e?.node && )}
    )}
    ); }; export default Home; ================================================ FILE: examples/react/nextjs-swr/styles/Home.module.css ================================================ .container { padding: 0 2rem; } .main { min-height: 100vh; padding: 4rem 0; flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; } .footer { display: flex; flex: 1; padding: 2rem 0; border-top: 1px solid #eaeaea; justify-content: center; align-items: center; } .footer a { display: flex; justify-content: center; align-items: center; flex-grow: 1; } .title a { color: #0070f3; text-decoration: none; } .title a:hover, .title a:focus, .title a:active { text-decoration: underline; } .title { margin: 0; line-height: 1.15; font-size: 4rem; } .title, .description { text-align: center; } .description { margin: 4rem 0; line-height: 1.5; font-size: 1.5rem; } .code { background: #fafafa; border-radius: 5px; padding: 0.75rem; font-size: 1.1rem; font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace; } .grid { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; max-width: 800px; } .card { margin: 1rem; padding: 1.5rem; text-align: left; color: inherit; text-decoration: none; border: 1px solid #eaeaea; border-radius: 10px; transition: color 0.15s ease, border-color 0.15s ease; max-width: 300px; } .card:hover, .card:focus, .card:active { color: #0070f3; border-color: #0070f3; } .card h2 { margin: 0 0 1rem 0; font-size: 1.5rem; } .card p { margin: 0; font-size: 1.25rem; line-height: 1.5; } .logo { height: 1em; margin-left: 0.5rem; } @media (max-width: 600px) { .grid { width: 100%; flex-direction: column; } } @media (prefers-color-scheme: dark) { .card, .footer { border-color: #222; } .code { background: #111; } .logo img { filter: invert(1); } } ================================================ FILE: examples/react/nextjs-swr/styles/globals.css ================================================ html, body { padding: 0; margin: 0; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; } a { color: inherit; text-decoration: none; } * { box-sizing: border-box; } @media (prefers-color-scheme: dark) { html { color-scheme: dark; } body { color: white; background: black; } } ================================================ FILE: examples/react/nextjs-swr/tsconfig.json ================================================ { "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "skipLibCheck": true, "strict": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "allowJs": false }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"] } ================================================ FILE: examples/react/tanstack-react-query/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: examples/react/tanstack-react-query/README.md ================================================ # Using GraphQL Code Generator with React Query and React This example illustrates using GraphQL Code Generator in a React application using React Query with `graphql-request` as a GraphQL Client. You will find the TypeScript-based codegen configuration in [`codegen.ts`](./codegen.ts). This simple codegen configuration generates types and helpers in the [`src/gql`](./src/gql/) folder that help you to get typed GraphQL Queries and Mutations seamlessly ⚡️
    For a step-by-step implementation tutorial, please refer to the related guide: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular -- Please note that the `client` preset used in this example is compatible with `graphql-request` from `5.0` as React Query fetcher. For indications in writing your fetcher, [please refer to our documentation](https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular#appendix-i-react-query-with-a-custom-fetcher-setup). ================================================ FILE: examples/react/tanstack-react-query/codegen.ts ================================================ import { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx', '!src/gql/**/*'], generates: { './src/gql/': { preset: 'client', config: { documentMode: 'string', }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/react/tanstack-react-query/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/react/tanstack-react-query/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/react/tanstack-react-query/cypress/support/e2e.ts ================================================ import './commands'; ================================================ FILE: examples/react/tanstack-react-query/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/react/tanstack-react-query/index.html ================================================ Vite App
    ================================================ FILE: examples/react/tanstack-react-query/package.json ================================================ { "name": "example-react-tanstack-react-query", "version": "0.1.0", "private": true, "dependencies": { "@tanstack/react-query": "4.36.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@graphql-codegen/cli": "^6.2.1", "@vitejs/plugin-react": "^5.0.0", "@types/node": "^22.0.0", "@types/react": "^18.0.17", "@types/react-dom": "^18.0.10", "typescript": "5.5.4", "serve": "14.2.3", "cypress": "15.7.1", "start-server-and-test": "2.0.5", "vite": "^6.0.0" }, "scripts": { "dev": "vite", "build": "vite build", "start": "serve -s dist", "test": "cypress run", "test:end2end": "start-server-and-test start http://localhost:3000 test", "codegen": "graphql-codegen --config codegen.ts" } } ================================================ FILE: examples/react/tanstack-react-query/src/App.css ================================================ .App { text-align: center; } .App-logo { height: 40vmin; pointer-events: none; } @media (prefers-reduced-motion: no-preference) { .App-logo { animation: App-logo-spin infinite 20s linear; } } .App-header { background-color: #282c34; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; } .App-link { color: #61dafb; } @keyframes App-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ================================================ FILE: examples/react/tanstack-react-query/src/App.tsx ================================================ import './App.css'; import Film from './Film'; import { graphql } from './gql'; import { useGraphQL } from './use-graphql'; const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `); function App() { const { data } = useGraphQL(allFilmsWithVariablesQueryDocument, { first: 10 }); return (
    {data && (
      {data.data?.allFilms?.edges?.map((e, i) => e?.node && )}
    )}
    ); } export default App; ================================================ FILE: examples/react/tanstack-react-query/src/Film.tsx ================================================ import { graphql, FragmentType, useFragment } from './gql'; export const FilmFragment = graphql(/* GraphQL */ ` fragment FilmItem on Film { id title releaseDate producers } `); const Film = (props: { /* tweet property has the correct type 🎉 */ film: FragmentType; }) => { const film = useFragment(FilmFragment, props.film); return (

    {film.title}

    {film.releaseDate}

    ); }; export default Film; ================================================ FILE: examples/react/tanstack-react-query/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; import { Incremental, TypedDocumentString } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: TypedDocumentString, fragmentNode: TypedDocumentString, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = queryNode.__meta__?.deferredFields as Record; const fragName = fragmentNode.__meta__?.fragmentName as string | undefined; if (!deferredFields || !fragName) return true; const fields = deferredFields[fragName] ?? []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/react/tanstack-react-query/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': typeof types.AllFilmsWithVariablesQueryDocument; '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; }; const documents: Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': types.AllFilmsWithVariablesQueryDocument, '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n' ): typeof import('./graphql').AllFilmsWithVariablesQueryDocument; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): typeof import('./graphql').FilmItemFragmentDoc; export function graphql(source: string) { return (documents as any)[source] ?? {}; } ================================================ FILE: examples/react/tanstack-react-query/src/gql/graphql.ts ================================================ /* eslint-disable */ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export class TypedDocumentString extends String implements DocumentTypeDecoration { __apiType?: NonNullable['__apiType']>; private value: string; public __meta__?: Record | undefined; constructor(value: string, __meta__?: Record | undefined) { super(value); this.value = value; this.__meta__ = __meta__; } override toString(): string & DocumentTypeDecoration { return this.value; } } export const FilmItemFragmentDoc = new TypedDocumentString( ` fragment FilmItem on Film { id title releaseDate producers } `, { fragmentName: 'FilmItem' } ) as unknown as TypedDocumentString; export const AllFilmsWithVariablesQueryDocument = new TypedDocumentString(` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } fragment FilmItem on Film { id title releaseDate producers }`) as unknown as TypedDocumentString; ================================================ FILE: examples/react/tanstack-react-query/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/react/tanstack-react-query/src/main.css ================================================ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } ================================================ FILE: examples/react/tanstack-react-query/src/main.tsx ================================================ import React from 'react'; import ReactDOM from 'react-dom/client'; import './main.css'; import App from './App'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; const queryClient = new QueryClient(); const root = ReactDOM.createRoot(document.getElementById('app') as HTMLElement); root.render( ); ================================================ FILE: examples/react/tanstack-react-query/src/use-graphql.ts ================================================ import { ExecutionResult } from 'graphql'; import { useQuery } from '@tanstack/react-query'; import { TypedDocumentString } from './gql/graphql'; export function useGraphQL( document: TypedDocumentString, ...[variables]: TVariables extends Record ? [] : [TVariables] ) { return useQuery( [ // This logic can be customized as desired document, variables, ] as const, async ({ queryKey }) => { return fetch('https://graphql.org/graphql/', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ query: queryKey[0].toString(), variables: queryKey[1], }), }).then(response => response.json()) as Promise>; } ); } ================================================ FILE: examples/react/tanstack-react-query/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/react/tanstack-react-query/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/react/tanstack-react-query/vite.config.ts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/react/urql/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: examples/react/urql/README.md ================================================ # Using GraphQL Code Generator with URQL and React This example illustrates using GraphQL Code Generator in a React application using the URQL GraphQL Client. You will find the TypeScript-based codegen configuration in [`codegen.ts`](./codegen.ts). This simple codegen configuration generates types and helpers in the [`src/gql`](./src/gql/) folder that help you to get typed GraphQL Queries and Mutations seamlessly ⚡️
    For a step-by-step implementation tutorial, please refer to the related guide: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular -- Please note that the `client` preset used in this example is compatible with `@urql/core` (since `1.15.0`), `@urql/preact` (since `1.4.0`) and `urql` (since `1.11.0`). ================================================ FILE: examples/react/urql/codegen.ts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx', '!src/gql/**/*'], generates: { './src/gql/': { preset: 'client', config: { documentMode: 'string', }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/react/urql/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/react/urql/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/react/urql/cypress/support/e2e.ts ================================================ import './commands'; ================================================ FILE: examples/react/urql/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/react/urql/index.html ================================================ Vite App
    ================================================ FILE: examples/react/urql/package.json ================================================ { "name": "example-react-urql", "version": "0.1.0", "private": true, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", "urql": "^3.0.0" }, "devDependencies": { "@types/react": "^18.0.17", "@types/react-dom": "^18.0.10", "@graphql-codegen/cli": "^6.2.1", "@vitejs/plugin-react": "^5.0.0", "typescript": "5.5.4", "serve": "14.2.3", "cypress": "15.7.1", "start-server-and-test": "2.0.5", "vite": "^6.0.0" }, "scripts": { "dev": "vite", "build": "vite build", "start": "serve -s dist", "test": "cypress run", "test:end2end": "start-server-and-test start http://localhost:3000 test", "codegen": "graphql-codegen --config codegen.ts" } } ================================================ FILE: examples/react/urql/src/App.css ================================================ .App { text-align: center; } .App-logo { height: 40vmin; pointer-events: none; } @media (prefers-reduced-motion: no-preference) { .App-logo { animation: App-logo-spin infinite 20s linear; } } .App-header { background-color: #282c34; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; } .App-link { color: #61dafb; } @keyframes App-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ================================================ FILE: examples/react/urql/src/App.tsx ================================================ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; import { AnyVariables, OperationContext, RequestPolicy, useQuery, UseQueryResponse } from 'urql'; import type { DocumentNode } from 'graphql'; import './App.css'; import Film from './Film'; import { graphql } from './gql'; const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery199($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `); declare module 'urql' { // @ts-expect-error this is just temporary until we update types in urql export type UseQueryArgs = { query: string | DocumentNode | DocumentTypeDecoration; requestPolicy?: RequestPolicy; context?: Partial; pause?: boolean; } & (Variables extends void ? { variables?: Variables; } : Variables extends { [P in keyof Variables]: Variables[P] | null; } ? { variables?: Variables; } : { variables: Variables; }); export function useQuery( args: UseQueryArgs ): UseQueryResponse; } function App() { const [{ data }] = useQuery({ query: allFilmsWithVariablesQueryDocument.toString(), variables: { first: 10, }, }); return (
    {data &&
      {data.allFilms?.edges?.map((e, i) => e?.node && )}
    }
    ); } export default App; ================================================ FILE: examples/react/urql/src/Film.tsx ================================================ import { FragmentType, useFragment } from './gql/fragment-masking'; import { graphql } from './gql'; export const FilmFragment = graphql(/* GraphQL */ ` fragment FilmItem on Film { id title releaseDate producers } `); const Film = (props: { /* tweet property has the correct type 🎉 */ film: FragmentType; }) => { const film = useFragment(FilmFragment, props.film); return (

    {film.title}

    {film.releaseDate}

    ); }; export default Film; ================================================ FILE: examples/react/urql/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; import { Incremental, TypedDocumentString } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: TypedDocumentString, fragmentNode: TypedDocumentString, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = queryNode.__meta__?.deferredFields as Record; const fragName = fragmentNode.__meta__?.fragmentName as string | undefined; if (!deferredFields || !fragName) return true; const fields = deferredFields[fragName] ?? []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/react/urql/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query allFilmsWithVariablesQuery199($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': typeof types.AllFilmsWithVariablesQuery199Document; '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; }; const documents: Documents = { '\n query allFilmsWithVariablesQuery199($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': types.AllFilmsWithVariablesQuery199Document, '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery199($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n' ): typeof import('./graphql').AllFilmsWithVariablesQuery199Document; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): typeof import('./graphql').FilmItemFragmentDoc; export function graphql(source: string) { return (documents as any)[source] ?? {}; } ================================================ FILE: examples/react/urql/src/gql/graphql.ts ================================================ /* eslint-disable */ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllFilmsWithVariablesQuery199QueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQuery199Query = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export class TypedDocumentString extends String implements DocumentTypeDecoration { __apiType?: NonNullable['__apiType']>; private value: string; public __meta__?: Record | undefined; constructor(value: string, __meta__?: Record | undefined) { super(value); this.value = value; this.__meta__ = __meta__; } override toString(): string & DocumentTypeDecoration { return this.value; } } export const FilmItemFragmentDoc = new TypedDocumentString( ` fragment FilmItem on Film { id title releaseDate producers } `, { fragmentName: 'FilmItem' } ) as unknown as TypedDocumentString; export const AllFilmsWithVariablesQuery199Document = new TypedDocumentString(` query allFilmsWithVariablesQuery199($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } fragment FilmItem on Film { id title releaseDate producers }`) as unknown as TypedDocumentString; ================================================ FILE: examples/react/urql/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/react/urql/src/main.css ================================================ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } ================================================ FILE: examples/react/urql/src/main.tsx ================================================ import React from 'react'; import ReactDOM from 'react-dom/client'; import { createClient, Provider } from 'urql'; import './main.css'; import App from './App'; const client = createClient({ url: 'https://graphql.org/graphql/', }); const root = ReactDOM.createRoot(document.getElementById('app') as HTMLElement); root.render( ); ================================================ FILE: examples/react/urql/src/vite-env.d.ts ================================================ /// ================================================ FILE: examples/react/urql/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/react/urql/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/react/urql/vite.config.ts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/typescript-esm/README.md ================================================ # GraphQL Code Generator usage with TypeScript and ESM ## Usage ``` # generate code yarn codegen # run tsc yarn build # run the tsc output yarn start ``` ## Explanation In ESM the file extension must be appended to named imports. This can be achieved by setting the codegen config `importExtension` to `'.js'` or `'.ts'` (see `codegen.yml`). TypeScript introduced a new module resolution algorithm for ESM in version 4.7. We set the `moduleResolution` to `node16` and the (output) module type to `node16` (see `tsconfig.json`). Additionally, within the `package.json` we specify the `type` property with the value `module` in order to instruct Node.js, bundlers and other tools that all `.js` files within this folder should be treated as ESM modules. ## Useful resources - [ECMAScript Module Support in Node.js - TypeScript 4.7 Changelog](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) - [package.json type module - Node.js documentation](https://nodejs.org/api/packages.html#type) - [Named Imports - import MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#named_import) ================================================ FILE: examples/typescript-esm/codegen.cjs ================================================ // @ts-check /** @type {import("@graphql-codegen/cli").CodegenConfig} */ const config = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.ts'], emitLegacyCommonJSImports: false, generates: { './src/gql/': { preset: 'client-preset', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; module.exports = config; ================================================ FILE: examples/typescript-esm/package.json ================================================ { "name": "example-typescript-esm", "version": "0.0.0", "private": true, "devDependencies": { "@graphql-codegen/cli": "6.2.1" }, "dependencies": { "@graphql-typed-document-node/core": "3.2.0", "graphql": "16.9.0" }, "scripts": { "codegen": "graphql-codegen-esm --config codegen.cjs", "build": "tsc", "start": "node dist/main.js", "test:end2end": "yarn start" }, "type": "module", "bob": false } ================================================ FILE: examples/typescript-esm/src/executeOperation.ts ================================================ import * as https from 'node:https'; import type { TypedDocumentNode } from '@graphql-typed-document-node/core'; import type { ExecutionResult } from 'graphql'; import { print } from 'graphql'; export function executeOperation( url: string, operation: TypedDocumentNode, ...[variables]: TVariables extends Record ? [] : [TVariables] ): Promise> { return new Promise((resolve, reject) => { const request = https.request( url, { method: 'POST', headers: { 'content-type': 'application/json' } }, response => { let data = ''; response.on('data', chunk => { data += chunk; }); response.on('end', () => { resolve(JSON.parse(data)); }); response.on('error', reject); } ); request.write( JSON.stringify({ query: print(operation), variables: variables == null ? undefined : variables, }) ); request.end(); }); } ================================================ FILE: examples/typescript-esm/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql.js'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/typescript-esm/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql.js'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query AllPeopleQuery {\n allPeople(first: 5) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n': typeof types.AllPeopleQueryDocument; '\n query AllPeopleWithVariablesQuery($first: Int!) {\n allPeople(first: $first) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n': typeof types.AllPeopleWithVariablesQueryDocument; }; const documents: Documents = { '\n query AllPeopleQuery {\n allPeople(first: 5) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n': types.AllPeopleQueryDocument, '\n query AllPeopleWithVariablesQuery($first: Int!) {\n allPeople(first: $first) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n': types.AllPeopleWithVariablesQueryDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query AllPeopleQuery {\n allPeople(first: 5) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n' ): (typeof documents)['\n query AllPeopleQuery {\n allPeople(first: 5) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query AllPeopleWithVariablesQuery($first: Int!) {\n allPeople(first: $first) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n' ): (typeof documents)['\n query AllPeopleWithVariablesQuery($first: Int!) {\n allPeople(first: $first) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/typescript-esm/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllPeopleQueryQueryVariables = Exact<{ [key: string]: never }>; export type AllPeopleQueryQuery = { __typename?: 'Root'; allPeople?: { __typename?: 'PeopleConnection'; edges?: Array<{ __typename?: 'PeopleEdge'; node?: { __typename?: 'Person'; name?: string | null; homeworld?: { __typename?: 'Planet'; name?: string | null } | null; } | null; } | null> | null; } | null; }; export type AllPeopleWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllPeopleWithVariablesQueryQuery = { __typename?: 'Root'; allPeople?: { __typename?: 'PeopleConnection'; edges?: Array<{ __typename?: 'PeopleEdge'; node?: { __typename?: 'Person'; name?: string | null; homeworld?: { __typename?: 'Planet'; name?: string | null } | null; } | null; } | null> | null; } | null; }; export const AllPeopleQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'AllPeopleQuery' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allPeople' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'IntValue', value: '5' } }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'name' } }, { kind: 'Field', name: { kind: 'Name', value: 'homeworld' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'name' } }], }, }, ], }, }, ], }, }, ], }, }, ], }, }, ], } as unknown as DocumentNode; export const AllPeopleWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'AllPeopleWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allPeople' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'name' } }, { kind: 'Field', name: { kind: 'Name', value: 'homeworld' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'name' } }], }, }, ], }, }, ], }, }, ], }, }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/typescript-esm/src/gql/index.ts ================================================ export * from './fragment-masking.js'; export * from './gql.js'; ================================================ FILE: examples/typescript-esm/src/main.ts ================================================ /* eslint-disable no-console */ import { executeOperation } from './executeOperation.js'; import { graphql } from './gql/index.js'; const AllPeopleQueryDocument = graphql(/* GraphQL */ ` query AllPeopleQuery { allPeople(first: 5) { edges { node { name homeworld { name } } } } } `); const AllPeopleWithVariablesQueryDocument = graphql(/* GraphQL */ ` query AllPeopleWithVariablesQuery($first: Int!) { allPeople(first: $first) { edges { node { name homeworld { name } } } } } `); const apiUrl = 'https://graphql.org/graphql/'; executeOperation(apiUrl, AllPeopleQueryDocument).then(res => { if (res.errors) { console.error(res.errors); process.exit(1); } console.log(res.data?.allPeople.edges); }); executeOperation(apiUrl, AllPeopleWithVariablesQueryDocument, { first: 10 }).then(res => { if (res.errors) { console.error(res.errors); process.exit(1); } console.log(res.data?.allPeople.edges); }); ================================================ FILE: examples/typescript-esm/tsconfig.json ================================================ { "compilerOptions": { "target": "ES2018", "moduleResolution": "node16", "module": "node16", "outDir": "dist", "skipLibCheck": true }, "include": ["src/**/*"] } ================================================ FILE: examples/typescript-graphql-request/README.md ================================================ # GraphQL Request Example This example showcases how to use GraphQL Code Generator for building a type-safe GraphQL schema utilizing the schema definition language first workflow. ## Usage ``` # generate code yarn codegen # run the server yarn dev ``` ================================================ FILE: examples/typescript-graphql-request/babel.config.js ================================================ module.exports = { presets: [ ['@babel/preset-env', { targets: { node: process.versions.node.split('.')[0] } }], '@babel/preset-typescript', ], }; ================================================ FILE: examples/typescript-graphql-request/codegen.ts ================================================ import { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.ts'], generates: { './src/gql/': { preset: 'client', config: { documentMode: 'string', }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/typescript-graphql-request/package.json ================================================ { "name": "example-typescript-graphql-request", "version": "0.0.0", "private": true, "devDependencies": { "@graphql-codegen/cli": "6.2.1" }, "dependencies": { "graphql": "16.9.0", "graphql-yoga": "5.7.0", "graphql-request": "5.2.0" }, "scripts": { "codegen": "graphql-codegen --config codegen.ts", "build": "tsc", "dev": "ts-node src/main.ts", "test:end2end": "vitest --no-watch" }, "type": "commonjs", "bob": false } ================================================ FILE: examples/typescript-graphql-request/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; import { Incremental, TypedDocumentString } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: TypedDocumentString, fragmentNode: TypedDocumentString, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = queryNode.__meta__?.deferredFields as Record; const fragName = fragmentNode.__meta__?.fragmentName as string | undefined; if (!deferredFields || !fragName) return true; const fields = deferredFields[fragName] ?? []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/typescript-graphql-request/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query AllPeopleQuery {\n allPeople(first: 5) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n': typeof types.AllPeopleQueryDocument; '\n query AllPeopleWithVariablesQuery($first: Int!) {\n allPeople(first: $first) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n': typeof types.AllPeopleWithVariablesQueryDocument; }; const documents: Documents = { '\n query AllPeopleQuery {\n allPeople(first: 5) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n': types.AllPeopleQueryDocument, '\n query AllPeopleWithVariablesQuery($first: Int!) {\n allPeople(first: $first) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n': types.AllPeopleWithVariablesQueryDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query AllPeopleQuery {\n allPeople(first: 5) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n' ): typeof import('./graphql').AllPeopleQueryDocument; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query AllPeopleWithVariablesQuery($first: Int!) {\n allPeople(first: $first) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n }\n' ): typeof import('./graphql').AllPeopleWithVariablesQueryDocument; export function graphql(source: string) { return (documents as any)[source] ?? {}; } ================================================ FILE: examples/typescript-graphql-request/src/gql/graphql.ts ================================================ /* eslint-disable */ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllPeopleQueryQueryVariables = Exact<{ [key: string]: never }>; export type AllPeopleQueryQuery = { __typename?: 'Root'; allPeople?: { __typename?: 'PeopleConnection'; edges?: Array<{ __typename?: 'PeopleEdge'; node?: { __typename?: 'Person'; name?: string | null; homeworld?: { __typename?: 'Planet'; name?: string | null } | null; } | null; } | null> | null; } | null; }; export type AllPeopleWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllPeopleWithVariablesQueryQuery = { __typename?: 'Root'; allPeople?: { __typename?: 'PeopleConnection'; edges?: Array<{ __typename?: 'PeopleEdge'; node?: { __typename?: 'Person'; name?: string | null; homeworld?: { __typename?: 'Planet'; name?: string | null } | null; } | null; } | null> | null; } | null; }; export class TypedDocumentString extends String implements DocumentTypeDecoration { __apiType?: NonNullable['__apiType']>; private value: string; public __meta__?: Record | undefined; constructor(value: string, __meta__?: Record | undefined) { super(value); this.value = value; this.__meta__ = __meta__; } override toString(): string & DocumentTypeDecoration { return this.value; } } export const AllPeopleQueryDocument = new TypedDocumentString(` query AllPeopleQuery { allPeople(first: 5) { edges { node { name homeworld { name } } } } } `) as unknown as TypedDocumentString; export const AllPeopleWithVariablesQueryDocument = new TypedDocumentString(` query AllPeopleWithVariablesQuery($first: Int!) { allPeople(first: $first) { edges { node { name homeworld { name } } } } } `) as unknown as TypedDocumentString; ================================================ FILE: examples/typescript-graphql-request/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/typescript-graphql-request/src/main.spec.ts ================================================ import { describe, it, expect } from 'vitest'; import { getPeople } from './main'; describe('TypeScript GraphQL Request tests', () => { it('works without variables', async () => { const result = await getPeople(); expect(result?.map(o => o?.node?.name)).toContain('Luke Skywalker'); }); it('returns first 3 entries', async () => { const result = await getPeople(3); expect(result).toHaveLength(3); }); }); ================================================ FILE: examples/typescript-graphql-request/src/main.ts ================================================ import { GraphQLClient } from 'graphql-request'; import { graphql } from './gql'; import { AllPeopleQueryQuery } from './gql/graphql'; const AllPeopleQueryDocument = graphql(/* GraphQL */ ` query AllPeopleQuery { allPeople(first: 5) { edges { node { name homeworld { name } } } } } `); const AllPeopleWithVariablesQueryDocument = graphql(/* GraphQL */ ` query AllPeopleWithVariablesQuery($first: Int!) { allPeople(first: $first) { edges { node { name homeworld { name } } } } } `); const apiUrl = 'https://graphql.org/graphql/'; const client = new GraphQLClient(apiUrl); export const getPeople = async (first?: number) => { let res: AllPeopleQueryQuery; if (first) { res = await client.request(AllPeopleWithVariablesQueryDocument.toString(), { first }); } else { res = await client.request(AllPeopleQueryDocument.toString()); } return res?.allPeople?.edges; }; ================================================ FILE: examples/typescript-graphql-request/tsconfig.json ================================================ { "compilerOptions": { "target": "es2020", "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "outDir": "dist" }, "include": ["src/**/*.ts"] } ================================================ FILE: examples/typescript-graphql-request/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'examples-typescript-graphql-request', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: examples/typescript-resolvers/README.md ================================================ # Typescript Resolvers Example This example showcases how to use GraphQL Code Generator for building a type-safe GraphQL schema utilizing the schema definition language first workflow. ## Usage ``` # generate code yarn codegen # run the server yarn dev ``` ================================================ FILE: examples/typescript-resolvers/codegen.ts ================================================ import { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: './src/main.ts', generates: { './src/type-defs.d.ts': { plugins: ['typescript', 'typescript-resolvers'], }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/typescript-resolvers/package.json ================================================ { "name": "example-typescript-resolvers", "version": "0.0.0", "private": true, "devDependencies": { "@graphql-codegen/cli": "6.2.1", "@graphql-codegen/typescript": "5.0.9", "@graphql-codegen/typescript-resolvers": "5.1.7" }, "dependencies": { "graphql": "16.9.0", "graphql-yoga": "5.7.0" }, "scripts": { "codegen": "graphql-codegen --config codegen.ts", "build": "tsc", "dev": "ts-node src/main.ts", "test": "exit 0", "test:end2end": "exit 0" }, "type": "commonjs", "bob": false } ================================================ FILE: examples/typescript-resolvers/src/main.ts ================================================ import { createYoga, createSchema } from 'graphql-yoga'; import { createServer } from 'http'; import type { Resolvers } from './type-defs.d'; const typeDefs = /* GraphQL */ ` type Query { hello: String! } input SumInput { a: Float! b: Float! } type Mutation { echoString(str: String!): String! calculateSum(input: SumInput!): Float! } `; const resolvers: Resolvers = { Query: { hello: () => 'world', }, Mutation: { echoString: (_, args) => { return args.str; }, calculateSum: (_, args) => { return args.input.a + args.input.b; }, }, }; const yoga = createYoga({ schema: createSchema({ typeDefs, resolvers, }), }); const server = createServer(yoga); server.listen(3000); ================================================ FILE: examples/typescript-resolvers/src/type-defs.d.ts ================================================ import { GraphQLResolveInfo } from 'graphql'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Mutation = { __typename?: 'Mutation'; calculateSum: Scalars['Float']['output']; echoString: Scalars['String']['output']; }; export type MutationCalculateSumArgs = { input: SumInput; }; export type MutationEchoStringArgs = { str: Scalars['String']['input']; }; export type Query = { __typename?: 'Query'; hello: Scalars['String']['output']; }; export type SumInput = { a: Scalars['Float']['input']; b: Scalars['Float']['input']; }; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver< TResult, TParent = Record, TContext = Record, TArgs = Record > = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver< TResult, TKey extends string, TParent = Record, TContext = Record, TArgs = Record > = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = ( obj: T, context: TContext, info: GraphQLResolveInfo ) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn< TResult = Record, TParent = Record, TContext = Record, TArgs = Record > = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Boolean: ResolverTypeWrapper; Float: ResolverTypeWrapper; Mutation: ResolverTypeWrapper>; Query: ResolverTypeWrapper>; String: ResolverTypeWrapper; SumInput: SumInput; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Boolean: Scalars['Boolean']['output']; Float: Scalars['Float']['output']; Mutation: Record; Query: Record; String: Scalars['String']['output']; SumInput: SumInput; }; export type MutationResolvers< ContextType = any, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation'] > = { calculateSum?: Resolver< ResolversTypes['Float'], ParentType, ContextType, RequireFields >; echoString?: Resolver< ResolversTypes['String'], ParentType, ContextType, RequireFields >; }; export type QueryResolvers< ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'] > = { hello?: Resolver; }; export type Resolvers = { Mutation?: MutationResolvers; Query?: QueryResolvers; }; ================================================ FILE: examples/typescript-resolvers/tsconfig.json ================================================ { "compilerOptions": { "target": "es2020", "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "outDir": "dist" }, "include": ["src/**/*.ts"] } ================================================ FILE: examples/vite/vite-react-cts/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* node_modules dist dist-ssr *.local # Editor directories and files .vscode/* !.vscode/extensions.json .idea .DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? ================================================ FILE: examples/vite/vite-react-cts/codegen.cts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/vite/vite-react-cts/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/vite/vite-react-cts/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/vite/vite-react-cts/cypress/support/e2e.ts ================================================ // Import commands.js using ES2015 syntax: import './commands'; ================================================ FILE: examples/vite/vite-react-cts/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/vite/vite-react-cts/index.html ================================================ Vite + React + TS
    ================================================ FILE: examples/vite/vite-react-cts/package.json ================================================ { "name": "example-vite-react-cts", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "tsc && vite build", "start": "vite preview --port 3000", "codegen": "graphql-codegen --config codegen.cts", "test": "cypress run", "test:end2end": "start-server-and-test start http://localhost:3000 test" }, "dependencies": { "@apollo/client": "^3.7.10", "@graphql-typed-document-node/core": "3.2.0", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.9.0", "react": "^18.2.0", "react-dom": "^18.2.0", "vite": "^6.0.0" }, "devDependencies": { "@graphql-codegen/cli": "6.2.1", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "cypress": "15.7.1", "start-server-and-test": "2.0.5", "typescript": "^5.0.0" }, "bob": false, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ================================================ FILE: examples/vite/vite-react-cts/src/Film.tsx ================================================ import { FragmentType, useFragment } from './gql/fragment-masking'; import { graphql } from './gql'; export const FilmFragment = graphql(/* GraphQL */ ` fragment FilmItem on Film { id title releaseDate producers } `); const Film = (props: { /* tweet property has the correct type 🎉 */ film: FragmentType; }) => { const film = useFragment(FilmFragment, props.film); return (

    {film.title}

    {film.releaseDate}

    ); }; export default Film; ================================================ FILE: examples/vite/vite-react-cts/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/vite/vite-react-cts/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': typeof types.AllFilmsWithVariablesQueryDocument; }; const documents: Documents = { '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': types.AllFilmsWithVariablesQueryDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/vite/vite-react-cts/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/vite/vite-react-cts/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/vite/vite-react-cts/src/main.tsx ================================================ import React from 'react'; import ReactDOM from 'react-dom/client'; import Film from './Film'; import { graphql } from './gql'; import { ApolloClient, InMemoryCache, ApolloProvider, useQuery } from '@apollo/client'; const client = new ApolloClient({ uri: 'https://graphql.org/graphql/', cache: new InMemoryCache(), }); const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `); function App() { const { data } = useQuery(allFilmsWithVariablesQueryDocument, { variables: { first: 10 } }); return (
    {data &&
      {data.allFilms?.edges?.map((e, i) => e?.node && )}
    }
    ); } ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( ); ================================================ FILE: examples/vite/vite-react-cts/src/vite-env.d.ts ================================================ /// ================================================ FILE: examples/vite/vite-react-cts/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": false, "skipLibCheck": true, "esModuleInterop": false, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "module": "ESNext", "moduleResolution": "Node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/vite/vite-react-cts/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/vite/vite-react-cts/vite.config.ts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/vite/vite-react-mts/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* node_modules dist dist-ssr *.local # Editor directories and files .vscode/* !.vscode/extensions.json .idea .DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? ================================================ FILE: examples/vite/vite-react-mts/codegen.mts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/vite/vite-react-mts/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/vite/vite-react-mts/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/vite/vite-react-mts/cypress/support/e2e.ts ================================================ // Import commands.js using ES2015 syntax: import './commands'; ================================================ FILE: examples/vite/vite-react-mts/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/vite/vite-react-mts/index.html ================================================ Vite + React + TS
    ================================================ FILE: examples/vite/vite-react-mts/package.json ================================================ { "name": "example-vite-react-mts", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "tsc && vite build", "start": "vite preview --port 3000", "codegen": "graphql-codegen --config codegen.mts", "test": "cypress run", "test:end2end": "start-server-and-test start http://localhost:3000 test" }, "dependencies": { "@apollo/client": "^3.7.10", "@graphql-typed-document-node/core": "3.2.0", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.9.0", "react": "^18.2.0", "react-dom": "^18.2.0", "vite": "^6.0.0" }, "devDependencies": { "@graphql-codegen/cli": "6.2.1", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "cypress": "15.7.1", "start-server-and-test": "2.0.5", "typescript": "^5.0.0" }, "bob": false, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ================================================ FILE: examples/vite/vite-react-mts/src/Film.tsx ================================================ import { FragmentType, useFragment } from './gql/fragment-masking'; import { graphql } from './gql'; export const FilmFragment = graphql(/* GraphQL */ ` fragment FilmItem on Film { id title releaseDate producers } `); const Film = (props: { /* tweet property has the correct type 🎉 */ film: FragmentType; }) => { const film = useFragment(FilmFragment, props.film); return (

    {film.title}

    {film.releaseDate}

    ); }; export default Film; ================================================ FILE: examples/vite/vite-react-mts/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/vite/vite-react-mts/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': typeof types.AllFilmsWithVariablesQueryDocument; }; const documents: Documents = { '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': types.AllFilmsWithVariablesQueryDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/vite/vite-react-mts/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/vite/vite-react-mts/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/vite/vite-react-mts/src/main.tsx ================================================ import React from 'react'; import ReactDOM from 'react-dom/client'; import Film from './Film'; import { graphql } from './gql'; import { ApolloClient, InMemoryCache, ApolloProvider, useQuery } from '@apollo/client'; const client = new ApolloClient({ uri: 'https://graphql.org/graphql/', cache: new InMemoryCache(), }); const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `); function App() { const { data } = useQuery(allFilmsWithVariablesQueryDocument, { variables: { first: 10 } }); return (
    {data &&
      {data.allFilms?.edges?.map((e, i) => e?.node && )}
    }
    ); } ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( ); ================================================ FILE: examples/vite/vite-react-mts/src/vite-env.d.ts ================================================ /// ================================================ FILE: examples/vite/vite-react-mts/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": false, "skipLibCheck": true, "esModuleInterop": false, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "module": "ESNext", "moduleResolution": "Node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/vite/vite-react-mts/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/vite/vite-react-mts/vite.config.ts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/vite/vite-react-ts/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* node_modules dist dist-ssr *.local # Editor directories and files .vscode/* !.vscode/extensions.json .idea .DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? ================================================ FILE: examples/vite/vite-react-ts/codegen.ts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/vite/vite-react-ts/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/vite/vite-react-ts/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/vite/vite-react-ts/cypress/support/e2e.ts ================================================ // Import commands.js using ES2015 syntax: import './commands'; ================================================ FILE: examples/vite/vite-react-ts/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/vite/vite-react-ts/index.html ================================================ Vite + React + TS
    ================================================ FILE: examples/vite/vite-react-ts/package.json ================================================ { "name": "example-vite-react-ts", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "tsc && vite build", "start": "vite preview --port 3000", "codegen": "graphql-codegen --config codegen.ts", "test": "cypress run", "test:end2end": "start-server-and-test start http://localhost:3000 test" }, "dependencies": { "@apollo/client": "^3.7.10", "@graphql-typed-document-node/core": "3.2.0", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.9.0", "react": "^18.2.0", "react-dom": "^18.2.0", "vite": "^6.0.0" }, "devDependencies": { "@graphql-codegen/cli": "6.2.1", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "cypress": "15.7.1", "start-server-and-test": "2.0.5", "typescript": "^5.0.0" }, "bob": false, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ================================================ FILE: examples/vite/vite-react-ts/src/Film.tsx ================================================ import { FragmentType, useFragment } from './gql/fragment-masking'; import { graphql } from './gql'; export const FilmFragment = graphql(/* GraphQL */ ` fragment FilmItem on Film { id title releaseDate producers } `); const Film = (props: { /* tweet property has the correct type 🎉 */ film: FragmentType; }) => { const film = useFragment(FilmFragment, props.film); return (

    {film.title}

    {film.releaseDate}

    ); }; export default Film; ================================================ FILE: examples/vite/vite-react-ts/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/vite/vite-react-ts/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': typeof types.AllFilmsWithVariablesQueryDocument; }; const documents: Documents = { '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': types.AllFilmsWithVariablesQueryDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/vite/vite-react-ts/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/vite/vite-react-ts/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/vite/vite-react-ts/src/main.tsx ================================================ import React from 'react'; import ReactDOM from 'react-dom/client'; import Film from './Film'; import { graphql } from './gql'; import { ApolloClient, InMemoryCache, ApolloProvider, useQuery } from '@apollo/client'; const client = new ApolloClient({ uri: 'https://graphql.org/graphql/', cache: new InMemoryCache(), }); const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `); function App() { const { data } = useQuery(allFilmsWithVariablesQueryDocument, { variables: { first: 10 } }); return (
    {data &&
      {data.allFilms?.edges?.map((e, i) => e?.node && )}
    }
    ); } ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( ); ================================================ FILE: examples/vite/vite-react-ts/src/vite-env.d.ts ================================================ /// ================================================ FILE: examples/vite/vite-react-ts/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": false, "skipLibCheck": true, "esModuleInterop": false, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "module": "ESNext", "moduleResolution": "Node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/vite/vite-react-ts/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/vite/vite-react-ts/vite.config.ts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/vue/apollo-composable/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* node_modules .DS_Store dist dist-ssr coverage *.local /cypress/videos/ /cypress/screenshots/ # Editor directories and files .vscode/* !.vscode/extensions.json .idea *.suo *.ntvs* *.njsproj *.sln *.sw? ================================================ FILE: examples/vue/apollo-composable/.vscode/extensions.json ================================================ { "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] } ================================================ FILE: examples/vue/apollo-composable/README.md ================================================ # Using GraphQL Code Generator with Apollo Composable and Vue 3 This example illustrates using GraphQL Code Generator in a Vue 3 application using the Apollo Composable GraphQL Client. You will find the TypeScript-based codegen configuration in [`codegen.ts`](./codegen.ts). This simple codegen configuration generates types and helpers in the [`src/gql`](./src/gql/) folder that help you to get typed GraphQL Queries and Mutations seamlessly ⚡️
    For a step-by-step implementation tutorial, please refer to the related guide: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular -- Please note that the `client` preset used in this example is compatible with `@vue/apollo-composable` (since `4.0.0-alpha.13`). ================================================ FILE: examples/vue/apollo-composable/codegen.ts ================================================ import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.vue', '!src/gql/**/*'], generates: { './src/gql/': { preset: 'client', config: { useTypeImports: true, }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/vue/apollo-composable/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/vue/apollo-composable/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/vue/apollo-composable/cypress/support/e2e.ts ================================================ // Import commands.js using ES2015 syntax: import './commands'; ================================================ FILE: examples/vue/apollo-composable/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/vue/apollo-composable/env.d.ts ================================================ /// ================================================ FILE: examples/vue/apollo-composable/index.html ================================================ Vite App
    ================================================ FILE: examples/vue/apollo-composable/package.json ================================================ { "name": "example-vue-apollo-composable", "version": "0.0.0", "private": true, "scripts": { "dev": "vite", "build": "vite build", "codegen": "graphql-codegen --config codegen.ts", "test": "cypress run", "start": "serve -s dist", "test:end2end": "start-server-and-test start http://localhost:3000 test" }, "dependencies": { "@apollo/client": "^3.7.10", "@vue/apollo-composable": "4.1.0", "graphql": "^16.6.0", "vue": "^3.2.37" }, "devDependencies": { "@graphql-codegen/cli": "^6.2.1", "@vitejs/plugin-vue": "^5.0.0", "typescript": "^5.0.0", "vite": "^6.0.0", "vue-tsc": "^2.0.0", "serve": "14.2.3", "cypress": "15.7.1", "start-server-and-test": "2.0.5" } } ================================================ FILE: examples/vue/apollo-composable/src/App.vue ================================================ ================================================ FILE: examples/vue/apollo-composable/src/assets/base.css ================================================ /* color palette from */ :root { --vt-c-white: #ffffff; --vt-c-white-soft: #f8f8f8; --vt-c-white-mute: #f2f2f2; --vt-c-black: #181818; --vt-c-black-soft: #222222; --vt-c-black-mute: #282828; --vt-c-indigo: #2c3e50; --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); --vt-c-text-light-1: var(--vt-c-indigo); --vt-c-text-light-2: rgba(60, 60, 60, 0.66); --vt-c-text-dark-1: var(--vt-c-white); --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); } /* semantic color variables for this project */ :root { --color-background: var(--vt-c-white); --color-background-soft: var(--vt-c-white-soft); --color-background-mute: var(--vt-c-white-mute); --color-border: var(--vt-c-divider-light-2); --color-border-hover: var(--vt-c-divider-light-1); --color-heading: var(--vt-c-text-light-1); --color-text: var(--vt-c-text-light-1); --section-gap: 160px; } @media (prefers-color-scheme: dark) { :root { --color-background: var(--vt-c-black); --color-background-soft: var(--vt-c-black-soft); --color-background-mute: var(--vt-c-black-mute); --color-border: var(--vt-c-divider-dark-2); --color-border-hover: var(--vt-c-divider-dark-1); --color-heading: var(--vt-c-text-dark-1); --color-text: var(--vt-c-text-dark-2); } } *, *::before, *::after { box-sizing: border-box; margin: 0; position: relative; font-weight: normal; } body { min-height: 100vh; color: var(--color-text); background: var(--color-background); transition: color 0.5s, background-color 0.5s; line-height: 1.6; font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 15px; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } ================================================ FILE: examples/vue/apollo-composable/src/assets/main.css ================================================ @import './base.css'; #app { max-width: 1280px; margin: 0 auto; padding: 2rem; font-weight: normal; } a, .green { text-decoration: none; color: hsla(160, 100%, 37%, 1); transition: 0.4s; } @media (hover: hover) { a:hover { background-color: hsla(160, 100%, 37%, 0.2); } } @media (min-width: 1024px) { body { display: flex; place-items: center; } #app { display: grid; grid-template-columns: 1fr 1fr; padding: 0 2rem; } } ================================================ FILE: examples/vue/apollo-composable/src/components/FilmItem.vue ================================================ ================================================ FILE: examples/vue/apollo-composable/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import type { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import type { FragmentDefinitionNode } from 'graphql'; import type { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/vue/apollo-composable/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ': typeof types.AllFilmsWithVariablesQueryDocument; '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; }; const documents: Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ': types.AllFilmsWithVariablesQueryDocument, '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/vue/apollo-composable/src/gql/graphql.ts ================================================ /* eslint-disable */ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/vue/apollo-composable/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/vue/apollo-composable/src/main.ts ================================================ import { createApp, provide, h } from 'vue'; import './assets/main.css'; import { DefaultApolloClient } from '@vue/apollo-composable'; import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core'; import App from './App.vue'; const httpLink = new HttpLink({ uri: 'https://graphql.org/graphql/', }); // Create the apollo client const apolloClient = new ApolloClient({ link: httpLink, cache: new InMemoryCache(), connectToDevTools: true, }); createApp({ setup() { provide(DefaultApolloClient, apolloClient); }, render: () => h(App), }).mount('#app'); ================================================ FILE: examples/vue/apollo-composable/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/vue/apollo-composable/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/vue/apollo-composable/vite.config.ts ================================================ import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], }); ================================================ FILE: examples/vue/urql/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* node_modules .DS_Store dist dist-ssr coverage *.local /cypress/videos/ /cypress/screenshots/ # Editor directories and files .vscode/* !.vscode/extensions.json .idea *.suo *.ntvs* *.njsproj *.sln *.sw? ================================================ FILE: examples/vue/urql/README.md ================================================ # Using GraphQL Code Generator with URQL and Vue 3 This example illustrates using GraphQL Code Generator in a Vue 3 application using the URQL GraphQL Client. You will find the TypeScript-based codegen configuration in [`codegen.ts`](./codegen.ts). This simple codegen configuration generates types and helpers in the [`src/gql`](./src/gql/) folder that help you to get typed GraphQL Queries and Mutations seamlessly ⚡️
    For a step-by-step implementation tutorial, please refer to the related guide: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular -- Please note that the `client` preset used in this example is compatible with `@urql/vue` (since `1.11.0`). ================================================ FILE: examples/vue/urql/codegen.ts ================================================ import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.vue', '!src/gql/**/*'], generates: { './src/gql/': { preset: 'client', config: { useTypeImports: true, }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/vue/urql/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/vue/urql/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/vue/urql/cypress/support/e2e.ts ================================================ // Import commands.js using ES2015 syntax: import './commands'; ================================================ FILE: examples/vue/urql/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/vue/urql/env.d.ts ================================================ /// ================================================ FILE: examples/vue/urql/index.html ================================================ Vite App
    ================================================ FILE: examples/vue/urql/package.json ================================================ { "name": "example-vue-urql", "private": true, "version": "0.0.0", "scripts": { "dev": "vite", "build": "vite build", "codegen": "graphql-codegen --config codegen.ts", "test": "cypress run", "start": "serve -s dist", "test:end2end": "start-server-and-test start http://localhost:3000 test" }, "dependencies": { "@urql/vue": "^1.0.0", "graphql": "^16.6.0", "vue": "^3.2.45" }, "devDependencies": { "@graphql-codegen/cli": "^6.2.1", "@vitejs/plugin-vue": "^5.0.0", "typescript": "^5.0.0", "vite": "^6.0.0", "vue-tsc": "^2.0.0", "serve": "14.2.3", "cypress": "15.7.1", "start-server-and-test": "2.0.5" } } ================================================ FILE: examples/vue/urql/src/App.vue ================================================ ================================================ FILE: examples/vue/urql/src/assets/base.css ================================================ /* color palette from */ :root { --vt-c-white: #ffffff; --vt-c-white-soft: #f8f8f8; --vt-c-white-mute: #f2f2f2; --vt-c-black: #181818; --vt-c-black-soft: #222222; --vt-c-black-mute: #282828; --vt-c-indigo: #2c3e50; --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); --vt-c-text-light-1: var(--vt-c-indigo); --vt-c-text-light-2: rgba(60, 60, 60, 0.66); --vt-c-text-dark-1: var(--vt-c-white); --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); } /* semantic color variables for this project */ :root { --color-background: var(--vt-c-white); --color-background-soft: var(--vt-c-white-soft); --color-background-mute: var(--vt-c-white-mute); --color-border: var(--vt-c-divider-light-2); --color-border-hover: var(--vt-c-divider-light-1); --color-heading: var(--vt-c-text-light-1); --color-text: var(--vt-c-text-light-1); --section-gap: 160px; } @media (prefers-color-scheme: dark) { :root { --color-background: var(--vt-c-black); --color-background-soft: var(--vt-c-black-soft); --color-background-mute: var(--vt-c-black-mute); --color-border: var(--vt-c-divider-dark-2); --color-border-hover: var(--vt-c-divider-dark-1); --color-heading: var(--vt-c-text-dark-1); --color-text: var(--vt-c-text-dark-2); } } *, *::before, *::after { box-sizing: border-box; margin: 0; position: relative; font-weight: normal; } body { min-height: 100vh; color: var(--color-text); background: var(--color-background); transition: color 0.5s, background-color 0.5s; line-height: 1.6; font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 15px; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } ================================================ FILE: examples/vue/urql/src/assets/main.css ================================================ @import './base.css'; #app { max-width: 1280px; margin: 0 auto; padding: 2rem; font-weight: normal; } a, .green { text-decoration: none; color: hsla(160, 100%, 37%, 1); transition: 0.4s; } @media (hover: hover) { a:hover { background-color: hsla(160, 100%, 37%, 0.2); } } @media (min-width: 1024px) { body { display: flex; place-items: center; } #app { display: grid; grid-template-columns: 1fr 1fr; padding: 0 2rem; } } ================================================ FILE: examples/vue/urql/src/components/FilmItem.vue ================================================ ================================================ FILE: examples/vue/urql/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import type { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import type { FragmentDefinitionNode } from 'graphql'; import type { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/vue/urql/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ': typeof types.AllFilmsWithVariablesQueryDocument; '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; }; const documents: Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ': types.AllFilmsWithVariablesQueryDocument, '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/vue/urql/src/gql/graphql.ts ================================================ /* eslint-disable */ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/vue/urql/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/vue/urql/src/main.ts ================================================ import { createApp } from 'vue'; import urql, { cacheExchange, fetchExchange } from '@urql/vue'; import App from './App.vue'; const app = createApp(App); app.use(urql, { url: 'https://graphql.org/graphql/', exchanges: [cacheExchange, fetchExchange], }); app.mount('#app'); ================================================ FILE: examples/vue/urql/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/vue/urql/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/vue/urql/vite.config.ts ================================================ import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], }); ================================================ FILE: examples/vue/villus/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* node_modules .DS_Store dist dist-ssr coverage *.local /cypress/videos/ /cypress/screenshots/ # Editor directories and files .vscode/* !.vscode/extensions.json .idea *.suo *.ntvs* *.njsproj *.sln *.sw? ================================================ FILE: examples/vue/villus/.vscode/extensions.json ================================================ { "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] } ================================================ FILE: examples/vue/villus/README.md ================================================ # Using GraphQL Code Generator with Villus and Vue 3 This example illustrates using GraphQL Code Generator in a Vue 3 application using the Villus GraphQL Client. You will find the TypeScript-based codegen configuration in [`codegen.ts`](./codegen.ts). This simple codegen configuration generates types and helpers in the [`src/gql`](./src/gql/) folder that help you to get typed GraphQL Queries and Mutations seamlessly ⚡️
    For a step-by-step implementation tutorial, please refer to the related guide: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue-angular -- Please note that the `client` preset used in this example is compatible with `villus` (since `1.0.0-beta.8`). ================================================ FILE: examples/vue/villus/codegen.ts ================================================ import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.vue', '!src/gql/**/*'], generates: { './src/gql/': { preset: 'client', config: { useTypeImports: true, }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/vue/villus/cypress/e2e/end2end.cy.ts ================================================ describe('template spec', () => { it('renders everything correctly', () => { cy.visit('http://localhost:3000'); cy.get('h3').should('contain', 'A New Hope'); }); }); ================================================ FILE: examples/vue/villus/cypress/support/commands.ts ================================================ /// ================================================ FILE: examples/vue/villus/cypress/support/e2e.ts ================================================ // Import commands.js using ES2015 syntax: import './commands'; ================================================ FILE: examples/vue/villus/cypress.config.ts ================================================ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { setupNodeEvents(_on, _config) { // implement node event listeners here }, }, }); ================================================ FILE: examples/vue/villus/env.d.ts ================================================ /// ================================================ FILE: examples/vue/villus/index.html ================================================ Vite App
    ================================================ FILE: examples/vue/villus/package.json ================================================ { "name": "example-vue-villus", "version": "0.0.0", "private": true, "scripts": { "dev": "vite", "build": "vite build", "codegen": "graphql-codegen --config codegen.ts", "test": "cypress run", "start": "serve -s dist", "test:end2end": "start-server-and-test start http://localhost:3000 test" }, "dependencies": { "graphql": "^16.6.0", "villus": "^3.0.0", "vue": "^3.2.37" }, "devDependencies": { "@graphql-codegen/cli": "^6.2.1", "@vitejs/plugin-vue": "^5.0.0", "typescript": "^5.0.0", "vite": "^6.0.0", "vue-tsc": "^2.0.0", "serve": "14.2.3", "cypress": "15.7.1", "start-server-and-test": "2.0.5" } } ================================================ FILE: examples/vue/villus/src/App.vue ================================================ ================================================ FILE: examples/vue/villus/src/assets/base.css ================================================ /* color palette from */ :root { --vt-c-white: #ffffff; --vt-c-white-soft: #f8f8f8; --vt-c-white-mute: #f2f2f2; --vt-c-black: #181818; --vt-c-black-soft: #222222; --vt-c-black-mute: #282828; --vt-c-indigo: #2c3e50; --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); --vt-c-text-light-1: var(--vt-c-indigo); --vt-c-text-light-2: rgba(60, 60, 60, 0.66); --vt-c-text-dark-1: var(--vt-c-white); --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); } /* semantic color variables for this project */ :root { --color-background: var(--vt-c-white); --color-background-soft: var(--vt-c-white-soft); --color-background-mute: var(--vt-c-white-mute); --color-border: var(--vt-c-divider-light-2); --color-border-hover: var(--vt-c-divider-light-1); --color-heading: var(--vt-c-text-light-1); --color-text: var(--vt-c-text-light-1); --section-gap: 160px; } @media (prefers-color-scheme: dark) { :root { --color-background: var(--vt-c-black); --color-background-soft: var(--vt-c-black-soft); --color-background-mute: var(--vt-c-black-mute); --color-border: var(--vt-c-divider-dark-2); --color-border-hover: var(--vt-c-divider-dark-1); --color-heading: var(--vt-c-text-dark-1); --color-text: var(--vt-c-text-dark-2); } } *, *::before, *::after { box-sizing: border-box; margin: 0; position: relative; font-weight: normal; } body { min-height: 100vh; color: var(--color-text); background: var(--color-background); transition: color 0.5s, background-color 0.5s; line-height: 1.6; font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 15px; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } ================================================ FILE: examples/vue/villus/src/assets/main.css ================================================ @import './base.css'; #app { max-width: 1280px; margin: 0 auto; padding: 2rem; font-weight: normal; } a, .green { text-decoration: none; color: hsla(160, 100%, 37%, 1); transition: 0.4s; } @media (hover: hover) { a:hover { background-color: hsla(160, 100%, 37%, 0.2); } } @media (min-width: 1024px) { body { display: flex; place-items: center; } #app { display: grid; grid-template-columns: 1fr 1fr; padding: 0 2rem; } } ================================================ FILE: examples/vue/villus/src/components/FilmItem.vue ================================================ ================================================ FILE: examples/vue/villus/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import type { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import type { FragmentDefinitionNode } from 'graphql'; import type { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/vue/villus/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ': typeof types.AllFilmsWithVariablesQueryDocument; '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': typeof types.FilmItemFragmentDoc; }; const documents: Documents = { '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ': types.AllFilmsWithVariablesQueryDocument, '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n': types.FilmItemFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ' ): (typeof documents)['\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n ']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n' ): (typeof documents)['\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/vue/villus/src/gql/graphql.ts ================================================ /* eslint-disable */ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; /** A single film. */ export type Film = Node & { __typename?: 'Film'; characterConnection?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The name of the director of this film. */ director?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** The episode number of this film. */ episodeID?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The opening paragraphs at the beginning of this film. */ openingCrawl?: Maybe; planetConnection?: Maybe; /** The name(s) of the producer(s) of this film. */ producers?: Maybe>>; /** The ISO 8601 date format of film release at original creator country. */ releaseDate?: Maybe; speciesConnection?: Maybe; starshipConnection?: Maybe; /** The title of this film. */ title?: Maybe; vehicleConnection?: Maybe; }; /** A single film. */ export type FilmCharacterConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmPlanetConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmSpeciesConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single film. */ export type FilmVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type FilmCharactersConnection = { __typename?: 'FilmCharactersConnection'; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ characters?: Maybe>>; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmCharactersEdge = { __typename?: 'FilmCharactersEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmPlanetsConnection = { __typename?: 'FilmPlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmPlanetsEdge = { __typename?: 'FilmPlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmSpeciesConnection = { __typename?: 'FilmSpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmSpeciesEdge = { __typename?: 'FilmSpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmStarshipsConnection = { __typename?: 'FilmStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmStarshipsEdge = { __typename?: 'FilmStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmVehiclesConnection = { __typename?: 'FilmVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type FilmVehiclesEdge = { __typename?: 'FilmVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type FilmsConnection = { __typename?: 'FilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type FilmsEdge = { __typename?: 'FilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An object with an ID */ export type Node = { /** The id of the object. */ id: Scalars['ID']['output']; }; /** Information about pagination in a connection. */ export type PageInfo = { __typename?: 'PageInfo'; /** When paginating forwards, the cursor to continue. */ endCursor?: Maybe; /** When paginating forwards, are there more items? */ hasNextPage: Scalars['Boolean']['output']; /** When paginating backwards, are there more items? */ hasPreviousPage: Scalars['Boolean']['output']; /** When paginating backwards, the cursor to continue. */ startCursor?: Maybe; }; /** A connection to a list of items. */ export type PeopleConnection = { __typename?: 'PeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PeopleEdge = { __typename?: 'PeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type Person = Node & { __typename?: 'Person'; /** * The birth year of the person, using the in-universe standard of BBY or ABY - * Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is * a battle that occurs at the end of Star Wars episode IV: A New Hope. */ birthYear?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * The eye color of this person. Will be "unknown" if not known or "n/a" if the * person does not have an eye. */ eyeColor?: Maybe; filmConnection?: Maybe; /** * The gender of this person. Either "Male", "Female" or "unknown", * "n/a" if the person does not have a gender. */ gender?: Maybe; /** * The hair color of this person. Will be "unknown" if not known or "n/a" if the * person does not have hair. */ hairColor?: Maybe; /** The height of the person in centimeters. */ height?: Maybe; /** A planet that this person was born on or inhabits. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The mass of the person in kilograms. */ mass?: Maybe; /** The name of this person. */ name?: Maybe; /** The skin color of this person. */ skinColor?: Maybe; /** The species that this person belongs to, or null if unknown. */ species?: Maybe; starshipConnection?: Maybe; vehicleConnection?: Maybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonStarshipConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** An individual person or character within the Star Wars universe. */ export type PersonVehicleConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PersonFilmsConnection = { __typename?: 'PersonFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonFilmsEdge = { __typename?: 'PersonFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonStarshipsConnection = { __typename?: 'PersonStarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PersonStarshipsEdge = { __typename?: 'PersonStarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PersonVehiclesConnection = { __typename?: 'PersonVehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type PersonVehiclesEdge = { __typename?: 'PersonVehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type Planet = Node & { __typename?: 'Planet'; /** The climates of this planet. */ climates?: Maybe>>; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The diameter of this planet in kilometers. */ diameter?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** * A number denoting the gravity of this planet, where "1" is normal or 1 standard * G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. */ gravity?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The name of this planet. */ name?: Maybe; /** * The number of standard days it takes for this planet to complete a single orbit * of its local star. */ orbitalPeriod?: Maybe; /** The average population of sentient beings inhabiting this planet. */ population?: Maybe; residentConnection?: Maybe; /** * The number of standard hours it takes for this planet to complete a single * rotation on its axis. */ rotationPeriod?: Maybe; /** * The percentage of the planet surface that is naturally occurring water or bodies * of water. */ surfaceWater?: Maybe; /** The terrains of this planet. */ terrains?: Maybe>>; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** * A large mass, planet or planetoid in the Star Wars Universe, at the time of * 0 ABY. */ export type PlanetResidentConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type PlanetFilmsConnection = { __typename?: 'PlanetFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetFilmsEdge = { __typename?: 'PlanetFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetResidentsConnection = { __typename?: 'PlanetResidentsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ residents?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetResidentsEdge = { __typename?: 'PlanetResidentsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type PlanetsConnection = { __typename?: 'PlanetsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ planets?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type PlanetsEdge = { __typename?: 'PlanetsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type Root = { __typename?: 'Root'; allFilms?: Maybe; allPeople?: Maybe; allPlanets?: Maybe; allSpecies?: Maybe; allStarships?: Maybe; allVehicles?: Maybe; film?: Maybe; /** Fetches an object given its ID */ node?: Maybe; person?: Maybe; planet?: Maybe; species?: Maybe; starship?: Maybe; vehicle?: Maybe; }; export type RootAllFilmsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPeopleArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllPlanetsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllSpeciesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllStarshipsArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootAllVehiclesArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; export type RootFilmArgs = { filmID?: InputMaybe; id?: InputMaybe; }; export type RootNodeArgs = { id: Scalars['ID']['input']; }; export type RootPersonArgs = { id?: InputMaybe; personID?: InputMaybe; }; export type RootPlanetArgs = { id?: InputMaybe; planetID?: InputMaybe; }; export type RootSpeciesArgs = { id?: InputMaybe; speciesID?: InputMaybe; }; export type RootStarshipArgs = { id?: InputMaybe; starshipID?: InputMaybe; }; export type RootVehicleArgs = { id?: InputMaybe; vehicleID?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type Species = Node & { __typename?: 'Species'; /** The average height of this species in centimeters. */ averageHeight?: Maybe; /** The average lifespan of this species in years, null if unknown. */ averageLifespan?: Maybe; /** The classification of this species, such as "mammal" or "reptile". */ classification?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The designation of this species, such as "sentient". */ designation?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; /** * Common eye colors for this species, null if this species does not typically * have eyes. */ eyeColors?: Maybe>>; filmConnection?: Maybe; /** * Common hair colors for this species, null if this species does not typically * have hair. */ hairColors?: Maybe>>; /** A planet that this species originates from. */ homeworld?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The language commonly spoken by this species. */ language?: Maybe; /** The name of this species. */ name?: Maybe; personConnection?: Maybe; /** * Common skin colors for this species, null if this species does not typically * have skin. */ skinColors?: Maybe>>; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A type of person or character within the Star Wars Universe. */ export type SpeciesPersonConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type SpeciesConnection = { __typename?: 'SpeciesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ species?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesEdge = { __typename?: 'SpeciesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesFilmsConnection = { __typename?: 'SpeciesFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesFilmsEdge = { __typename?: 'SpeciesFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type SpeciesPeopleConnection = { __typename?: 'SpeciesPeopleConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ people?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type SpeciesPeopleEdge = { __typename?: 'SpeciesPeopleEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type Starship = Node & { __typename?: 'Starship'; /** * The Maximum number of Megalights this starship can travel in a standard hour. * A "Megalight" is a standard unit of distance and has never been defined before * within the Star Wars universe. This figure is only really useful for measuring * the difference in speed of starships. We can assume it is similar to AU, the * distance between our Sun (Sol) and Earth. */ MGLT?: Maybe; /** The maximum number of kilograms that this starship can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this starship can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this starship new, in galactic credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this starship. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The class of this starships hyperdrive. */ hyperdriveRating?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this starship in meters. */ length?: Maybe; /** The manufacturers of this starship. */ manufacturers?: Maybe>>; /** * The maximum speed of this starship in atmosphere. null if this starship is * incapable of atmosphering flight. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 * Orbital Battle Station". */ model?: Maybe; /** The name of this starship. The common name, such as "Death Star". */ name?: Maybe; /** The number of non-essential people this starship can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** * The class of this starship, such as "Starfighter" or "Deep Space Mobile * Battlestation" */ starshipClass?: Maybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that has hyperdrive capability. */ export type StarshipPilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type StarshipFilmsConnection = { __typename?: 'StarshipFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipFilmsEdge = { __typename?: 'StarshipFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipPilotsConnection = { __typename?: 'StarshipPilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipPilotsEdge = { __typename?: 'StarshipPilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type StarshipsConnection = { __typename?: 'StarshipsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ starships?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type StarshipsEdge = { __typename?: 'StarshipsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type Vehicle = Node & { __typename?: 'Vehicle'; /** The maximum number of kilograms that this vehicle can transport. */ cargoCapacity?: Maybe; /** * The maximum length of time that this vehicle can provide consumables for its * entire crew without having to resupply. */ consumables?: Maybe; /** The cost of this vehicle new, in Galactic Credits. */ costInCredits?: Maybe; /** The ISO 8601 date format of the time that this resource was created. */ created?: Maybe; /** The number of personnel needed to run or pilot this vehicle. */ crew?: Maybe; /** The ISO 8601 date format of the time that this resource was edited. */ edited?: Maybe; filmConnection?: Maybe; /** The ID of an object */ id: Scalars['ID']['output']; /** The length of this vehicle in meters. */ length?: Maybe; /** The manufacturers of this vehicle. */ manufacturers?: Maybe>>; /** The maximum speed of this vehicle in atmosphere. */ maxAtmospheringSpeed?: Maybe; /** * The model or official name of this vehicle. Such as "All-Terrain Attack * Transport". */ model?: Maybe; /** * The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder * bike". */ name?: Maybe; /** The number of non-essential people this vehicle can transport. */ passengers?: Maybe; pilotConnection?: Maybe; /** The class of this vehicle, such as "Wheeled" or "Repulsorcraft". */ vehicleClass?: Maybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehicleFilmConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A single transport craft that does not have hyperdrive capability */ export type VehiclePilotConnectionArgs = { after?: InputMaybe; before?: InputMaybe; first?: InputMaybe; last?: InputMaybe; }; /** A connection to a list of items. */ export type VehicleFilmsConnection = { __typename?: 'VehicleFilmsConnection'; /** A list of edges. */ edges?: Maybe>>; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ films?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehicleFilmsEdge = { __typename?: 'VehicleFilmsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclePilotsConnection = { __typename?: 'VehiclePilotsConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ pilots?: Maybe>>; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; }; /** An edge in a connection. */ export type VehiclePilotsEdge = { __typename?: 'VehiclePilotsEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; /** A connection to a list of items. */ export type VehiclesConnection = { __typename?: 'VehiclesConnection'; /** A list of edges. */ edges?: Maybe>>; /** Information to aid in pagination. */ pageInfo: PageInfo; /** * A count of the total number of objects in this connection, ignoring pagination. * This allows a client to fetch the first five objects by passing "5" as the * argument to "first", then fetch the total count so it could display "5 of 83", * for example. */ totalCount?: Maybe; /** * A list of all of the objects returned in the connection. This is a convenience * field provided for quickly exploring the API; rather than querying for * "{ edges { node } }" when no edge data is needed, this field can be be used * instead. Note that when clients like Relay need to fetch the "cursor" field on * the edge to enable efficient pagination, this shortcut cannot be used, and the * full "{ edges { node } }" version should be used instead. */ vehicles?: Maybe>>; }; /** An edge in a connection. */ export type VehiclesEdge = { __typename?: 'VehiclesEdge'; /** A cursor for use in pagination */ cursor: Scalars['String']['output']; /** The item at the end of the edge */ node?: Maybe; }; export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ first: Scalars['Int']['input']; }>; export type AllFilmsWithVariablesQueryQuery = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; edges?: Array<{ __typename?: 'FilmsEdge'; node?: ({ __typename?: 'Film' } & { ' $fragmentRefs'?: { FilmItemFragment: FilmItemFragment } }) | null; } | null> | null; } | null; }; export type FilmItemFragment = { __typename?: 'Film'; id: string; title?: string | null; releaseDate?: string | null; producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; export const FilmItemFragmentDoc = { kind: 'Document', definitions: [ { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; export const AllFilmsWithVariablesQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'allFilmsWithVariablesQuery' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'allFilms' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'first' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'first' } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'edges' }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'node' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'FragmentSpread', name: { kind: 'Name', value: 'FilmItem' } }], }, }, ], }, }, ], }, }, ], }, }, { kind: 'FragmentDefinition', name: { kind: 'Name', value: 'FilmItem' }, typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Film' } }, selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'title' } }, { kind: 'Field', name: { kind: 'Name', value: 'releaseDate' } }, { kind: 'Field', name: { kind: 'Name', value: 'producers' } }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/vue/villus/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/vue/villus/src/main.ts ================================================ import { createApp, h } from 'vue'; import App from './App.vue'; import './assets/main.css'; createApp({ render: () => h(App), }).mount('#app'); ================================================ FILE: examples/vue/villus/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ================================================ FILE: examples/vue/villus/tsconfig.node.json ================================================ { "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Node", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] } ================================================ FILE: examples/vue/villus/vite.config.ts ================================================ import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], }); ================================================ FILE: examples/yoga-tests/README.md ================================================ # Yoga Testing Setup Example for executing typed GraphQL operations against your Yoga instance within tests using GraphQL Code Generator. [Learn more about Yoga - The GraphQL Server.](https://the-guild.dev/graphql/yoga-server) ## Usage Run `yarn codegen --watch` for starting GraphQL Code Generator in watch mode. Run `yarn test` for running a tests located within `yoga.spec.ts`. ================================================ FILE: examples/yoga-tests/babel.config.js ================================================ module.exports = { presets: [ ['@babel/preset-env', { targets: { node: process.versions.node.split('.')[0] } }], '@babel/preset-typescript', ], }; ================================================ FILE: examples/yoga-tests/codegen.ts ================================================ import { type CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: './src/yoga.ts', documents: ['src/**/*.ts'], generates: { './src/gql/': { preset: 'client-preset', }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, }; export default config; ================================================ FILE: examples/yoga-tests/package.json ================================================ { "name": "example-yoga-tests", "version": "0.0.0", "private": true, "dependencies": { "graphql-yoga": "5.7.0" }, "devDependencies": { "@graphql-typed-document-node/core": "3.2.0", "@graphql-codegen/cli": "6.2.1", "@babel/core": "7.25.2", "@babel/preset-env": "7.25.3", "@babel/preset-typescript": "7.28.5" }, "scripts": { "test": "vitest --no-watch", "codegen": "graphql-codegen --config codegen.ts", "build": "tsc", "test:end2end": "yarn test" }, "bob": false } ================================================ FILE: examples/yoga-tests/src/gql/fragment-masking.ts ================================================ /* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, fragmentType: | FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } ================================================ FILE: examples/yoga-tests/src/gql/gql.ts ================================================ /* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { '\n query HelloQuery {\n hello\n }\n ': typeof types.HelloQueryDocument; '\n mutation EchoMutation($message: String!) {\n echo(message: $message)\n }\n ': typeof types.EchoMutationDocument; }; const documents: Documents = { '\n query HelloQuery {\n hello\n }\n ': types.HelloQueryDocument, '\n mutation EchoMutation($message: String!) {\n echo(message: $message)\n }\n ': types.EchoMutationDocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * ```ts * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`); * ``` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n query HelloQuery {\n hello\n }\n ' ): (typeof documents)['\n query HelloQuery {\n hello\n }\n ']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( source: '\n mutation EchoMutation($message: String!) {\n echo(message: $message)\n }\n ' ): (typeof documents)['\n mutation EchoMutation($message: String!) {\n echo(message: $message)\n }\n ']; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; ================================================ FILE: examples/yoga-tests/src/gql/graphql.ts ================================================ /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string }; String: { input: string; output: string }; Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; }; export type Mutation = { __typename?: 'Mutation'; echo: Scalars['String']['output']; }; export type MutationEchoArgs = { message: Scalars['String']['input']; }; export type Query = { __typename?: 'Query'; hello: Scalars['String']['output']; }; export type HelloQueryQueryVariables = Exact<{ [key: string]: never }>; export type HelloQueryQuery = { __typename?: 'Query'; hello: string }; export type EchoMutationMutationVariables = Exact<{ message: Scalars['String']['input']; }>; export type EchoMutationMutation = { __typename?: 'Mutation'; echo: string }; export const HelloQueryDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'query', name: { kind: 'Name', value: 'HelloQuery' }, selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'hello' } }] }, }, ], } as unknown as DocumentNode; export const EchoMutationDocument = { kind: 'Document', definitions: [ { kind: 'OperationDefinition', operation: 'mutation', name: { kind: 'Name', value: 'EchoMutation' }, variableDefinitions: [ { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'message' } }, type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } } }, }, ], selectionSet: { kind: 'SelectionSet', selections: [ { kind: 'Field', name: { kind: 'Name', value: 'echo' }, arguments: [ { kind: 'Argument', name: { kind: 'Name', value: 'message' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'message' } }, }, ], }, ], }, }, ], } as unknown as DocumentNode; ================================================ FILE: examples/yoga-tests/src/gql/index.ts ================================================ export * from './fragment-masking'; export * from './gql'; ================================================ FILE: examples/yoga-tests/src/main.ts ================================================ import { createServer } from 'http'; import { yoga } from './yoga.js'; const server = createServer(yoga); // Start the server and you're done! server.listen(4000, () => { // eslint-disable-next-line no-console console.info('Server is running on http://localhost:4000/graphql'); }); ================================================ FILE: examples/yoga-tests/src/yoga.spec.ts ================================================ import { describe, it, expect } from 'vitest'; import type { TypedDocumentNode } from '@graphql-typed-document-node/core'; import { type ExecutionResult, print } from 'graphql'; import { graphql } from './gql'; import { yoga } from './yoga'; function executeOperation( operation: TypedDocumentNode, ...[variables]: TVariables extends Record ? [] : [TVariables] ): Promise> { return Promise.resolve( yoga.fetch('http://yoga/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify({ query: print(operation), variables: variables ?? undefined, }), }) ).then(response => response.json()); } describe('Yoga Tests', () => { it('execute query operation', async () => { const HelloQuery = graphql(/* GraphQL */ ` query HelloQuery { hello } `); const result = await executeOperation(HelloQuery); expect(result.data?.hello).toEqual('Hello world!'); }); it('execute mutation operation', async () => { const EchoMutation = graphql(/* GraphQL */ ` mutation EchoMutation($message: String!) { echo(message: $message) } `); const result = await executeOperation(EchoMutation, { message: 'Ohayoo!', }); expect(result.data?.echo).toEqual('Ohayoo!'); }); it('execute mutation operation (variant)', async () => { const EchoMutation = graphql(/* GraphQL */ ` mutation EchoMutation($message: String!) { echo(message: $message) } `); const result = await executeOperation(EchoMutation, { message: 'Konbanwa', }); expect(result.data?.echo).toEqual('Konbanwa'); }); }); ================================================ FILE: examples/yoga-tests/src/yoga.ts ================================================ import { createSchema, createYoga } from 'graphql-yoga'; const schema = createSchema({ typeDefs: /* GraphQL */ ` type Query { hello: String! } type Mutation { echo(message: String!): String! } `, resolvers: { Query: { hello: () => 'Hello world!', }, Mutation: { echo: (_, args) => args.message, }, }, }); export const yoga = createYoga({ schema, }); ================================================ FILE: examples/yoga-tests/tsconfig.json ================================================ { "compilerOptions": { "target": "ES2018", "module": "Node16", "outDir": "dist", "skipLibCheck": true }, "include": ["src/**/*"] } ================================================ FILE: examples/yoga-tests/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'examples-yoga-tests', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: package.json ================================================ { "name": "graphql-code-generator", "private": true, "engines": { "node": ">= 16.0.0" }, "packageManager": "yarn@1.22.22", "scripts": { "postinstall": "patch-package && husky install", "fix-bins": "node scripts/fix-bin.js", "clean": "rimraf node_modules/", "prebuild": "rimraf dist/ .bob/ tsconfig.tsbuildinfo", "build": "bob build", "postbuild": "yarn fix-bins", "watch-build": "npx tsc-watch --project tsconfig.json --onSuccess \"bob build\"", "rebuild": "bob build --incremental", "test": "vitest", "lint": "cross-env \"ESLINT_USE_FLAT_CONFIG=false\" eslint --cache --ignore-path .gitignore .", "prettier": "prettier --cache --write --list-different .", "prettier:check": "prettier --cache --check .", "types:check": "tsc --noEmit", "test-and-build": "yarn build && yarn test", "ci:lint": "cross-env \"ESLINT_USE_FLAT_CONFIG=false\" eslint --cache --ignore-path .gitignore --output-file eslint_report.json --format json .", "prerelease": "yarn build", "release": "changeset publish", "generate:examples:esm": "node packages/graphql-codegen-cli/dist/esm/bin.js --require dotenv/config --config ./dev-test/codegen.ts dotenv_config_path=dev-test/.env", "generate:examples:cjs": "node packages/graphql-codegen-cli/dist/cjs/bin.js --require dotenv/config --config ./dev-test/codegen.ts dotenv_config_path=dev-test/.env", "generate:examples": "yarn generate:examples:cjs", "watch:examples:esm": "node packages/graphql-codegen-cli/dist/esm/bin.js --require dotenv/config --watch --config ./dev-test/codegen.ts dotenv_config_path=dev-test/.env", "watch:examples:cjs": "node packages/graphql-codegen-cli/dist/cjs/bin.js --require dotenv/config --watch --config ./dev-test/codegen.ts dotenv_config_path=dev-test/.env", "watch:examples": "yarn watch:examples:cjs", "examples:codegen": "set -o xtrace && eval $(node scripts/print-example-ci-command.js codegen)", "examples:build": "set -o xtrace && eval $(node scripts/print-example-ci-command.js build)", "examples:test:end2end": "set -o xtrace && eval $(node scripts/print-example-ci-command.js test:end2end)" }, "workspaces": [ "packages/*", "packages/utils/*", "packages/plugins/typescript/*", "packages/plugins/other/*", "packages/presets/*", "website", "examples/**/*" ], "devDependencies": { "@babel/core": "7.25.2", "@babel/preset-env": "7.25.3", "@babel/preset-typescript": "7.28.5", "@changesets/changelog-github": "0.6.0", "@changesets/cli": "2.30.0", "@theguild/eslint-config": "0.13.3", "@theguild/prettier-config": "0.1.1", "bob-the-bundler": "7.0.1", "cross-env": "10.1.0", "eslint": "9.9.0", "eslint-plugin-tailwindcss": "npm:@hasparus/eslint-plugin-tailwindcss@3.17.5", "graphql": "16.9.0", "husky": "9.1.7", "jest-diff": "30.0.5", "lint-staged": "15.2.9", "memfs": "4.36.3", "patch-package": "8.0.0", "prettier": "2.8.8", "prettier-plugin-svelte": "2.10.1", "rimraf": "6.0.1", "ts-node": "10.9.2", "tslib": "2.6.3", "tsx": "4.17.0", "typescript": "5.5.4", "vite-tsconfig-paths": "6.1.1", "vitest": "4.0.4", "wrangler": "4.1.0" }, "lint-staged": { "packages/**/src/**/*.{ts,tsx}": [ "cross-env \"ESLINT_USE_FLAT_CONFIG=false\" eslint --fix" ], "**/*.{js,jsx,cjs,mjs,ts,tsx,graphql,gql,yml,yaml,json,md}": [ "prettier --write" ], "yarn.lock": [ "npx yarn-deduplicate" ] }, "resolutions": { "typescript": "5.5.4", "eslint-plugin-promise": "7.1.0" }, "version": "0.0.0" } ================================================ FILE: packages/graphql-cli-codegen-plugin/README.md ================================================ # GraphQL Code Generator plugin for GraphQL CLI

    Live demo and full documentation: [the-guild.dev/graphql/codegen](https://the-guild.dev/graphql/codegen) Project repository: [graphql-code-generator](https://github.com/dotansimha/graphql-code-generator) The plugin `@graphql-cli/codegen` is deprecated, and no longer maintained. Please visit [Migrating from GraphQL-CLI to Inspector CLI](https://the-guild.dev/graphql/inspector/docs/migration-guides/from-graphql-cli) documentation to get more information about migration from `GraphQL-CLI` to `Inspector CLI` or visit [GraphQL-CLI documentation](../../website/src/pages/docs/guides/graphql-cli.mdx) in GraphQL Code Generator. ================================================ FILE: packages/graphql-codegen-cli/CHANGELOG.md ================================================ # @graphql-codegen/cli ## 6.2.1 ### Patch Changes - [#10618](https://github.com/dotansimha/graphql-code-generator/pull/10618) [`e804925`](https://github.com/dotansimha/graphql-code-generator/commit/e804925361f326fe2fc7a2ee3f6db950bcd79dab) Thanks [@PalmerTurley34](https://github.com/PalmerTurley34)! - Honor per-output preset `importExtension` and `emitLegacyCommonJSImports` config instead of always using the root config values. ## 6.2.0 ### Minor Changes - [#10617](https://github.com/dotansimha/graphql-code-generator/pull/10617) [`8c4db2a`](https://github.com/dotansimha/graphql-code-generator/commit/8c4db2abd0578d7b1c9b4197dfa41dae3ef6252b) Thanks [@ikusakov2](https://github.com/ikusakov2)! - Allow GraphQLSchema to be passed directly to generate({schema: ...}) function ### Patch Changes - Updated dependencies [[`8c4db2a`](https://github.com/dotansimha/graphql-code-generator/commit/8c4db2abd0578d7b1c9b4197dfa41dae3ef6252b)]: - @graphql-codegen/plugin-helpers@6.2.0 ## 6.1.3 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-tools/apollo-engine-loader@^8.0.28` ↗︎](https://www.npmjs.com/package/@graphql-tools/apollo-engine-loader/v/8.0.28) (from `^8.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/code-file-loader@^8.1.28` ↗︎](https://www.npmjs.com/package/@graphql-tools/code-file-loader/v/8.1.28) (from `^8.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/git-loader@^8.0.32` ↗︎](https://www.npmjs.com/package/@graphql-tools/git-loader/v/8.0.32) (from `^8.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/github-loader@^9.0.6` ↗︎](https://www.npmjs.com/package/@graphql-tools/github-loader/v/9.0.6) (from `^9.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/graphql-file-loader@^8.1.11` ↗︎](https://www.npmjs.com/package/@graphql-tools/graphql-file-loader/v/8.1.11) (from `^8.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/json-file-loader@^8.0.26` ↗︎](https://www.npmjs.com/package/@graphql-tools/json-file-loader/v/8.0.26) (from `^8.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/load@^8.1.8` ↗︎](https://www.npmjs.com/package/@graphql-tools/load/v/8.1.8) (from `^8.1.0`, in `dependencies`) - Updated dependency [`@graphql-tools/url-loader@^9.0.6` ↗︎](https://www.npmjs.com/package/@graphql-tools/url-loader/v/9.0.6) (from `^9.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/utils@^11.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/11.0.0) (from `^10.0.0`, in `dependencies`) - Updated dependency [`graphql-config@^5.1.6` ↗︎](https://www.npmjs.com/package/graphql-config/v/5.1.6) (from `^5.1.1`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/client-preset@5.2.4 - @graphql-codegen/core@5.0.1 - @graphql-codegen/plugin-helpers@6.1.1 ## 6.1.2 ### Patch Changes - [#10590](https://github.com/dotansimha/graphql-code-generator/pull/10590) [`e173e11`](https://github.com/dotansimha/graphql-code-generator/commit/e173e113331cd279fb9dec51203d8c5a34915999) Thanks [@ya2s](https://github.com/ya2s)! - Fix GraphQL Config loading to forward nested `extensions.codegen.config` options when loading schemas/documents, matching `codegen.ts` behavior. ## 6.1.1 ### Patch Changes - [#10569](https://github.com/dotansimha/graphql-code-generator/pull/10569) [`8cb7d43`](https://github.com/dotansimha/graphql-code-generator/commit/8cb7d4369d35bc6b71750d53385949ffddd072a7) Thanks [@etr2460](https://github.com/etr2460)! - fix(graphql-codegen-cli): Don't hang when 0 CPUs are found Fixes generation when 0 CPUs are returned by os.cpus(), which occurs in sandbox environments. ## 6.1.0 ### Minor Changes - [#10510](https://github.com/dotansimha/graphql-code-generator/pull/10510) [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670) Thanks [@nickmessing](https://github.com/nickmessing)! - add importExtension configuration option ### Patch Changes - Updated dependencies [[`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/plugin-helpers@6.1.0 - @graphql-codegen/client-preset@5.2.0 ## 6.0.2 ### Patch Changes - [#10430](https://github.com/dotansimha/graphql-code-generator/pull/10430) [`aad7f03`](https://github.com/dotansimha/graphql-code-generator/commit/aad7f03bf812d671d3c60ff21be0b3b8da55d79f) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-tools/github-loader@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/github-loader/v/9.0.0) (from `^8.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/url-loader@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/url-loader/v/9.0.0) (from `^8.0.0`, in `dependencies`) - Updated dependencies []: - @graphql-codegen/client-preset@5.1.2 ## 6.0.1 ### Patch Changes - [#10468](https://github.com/dotansimha/graphql-code-generator/pull/10468) [`cb1b9d9`](https://github.com/dotansimha/graphql-code-generator/commit/cb1b9d99c413a96fde6c9af0b2315b3ad721ee4e) Thanks [@eddeee888](https://github.com/eddeee888)! - In watch mode, do not write output on failure Previously, on partial or full failure, watch mode still write to output. However, since the output'd be an empty array, it will then call `removeStaleFiles` internally to remove all previously generated files. This patch puts a temporary fix to avoid writing output on any failure to fix the described behaviour. This also means the `config.allowPartialOutputs` does not work in watch mode for now. ## 6.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop @graphql-tools/prisma-loader - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Add `allowPartialOutputs` flag to partially write successful generation to files - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Migrate inquirer to @inquirer/prompts - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Bump dependencies major versions: - cosmiconfig v9 - debounce v2 - jiti v2.3 - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Bump listr2 to v9 - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/plugin-helpers@6.0.0 - @graphql-codegen/client-preset@5.0.0 - @graphql-codegen/core@5.0.0 ## 5.0.7 ### Patch Changes - [#10150](https://github.com/dotansimha/graphql-code-generator/pull/10150) [`e324382`](https://github.com/dotansimha/graphql-code-generator/commit/e3243824cfe0d7ab463cf0d5a6455715510959be) Thanks [@ArminWiebigke](https://github.com/ArminWiebigke)! - Allow functions to be passed as valid values for `UrlSchemaOptions.customFetch`. This was already possible, but the type definitions did not reflect that correctly. - [#10358](https://github.com/dotansimha/graphql-code-generator/pull/10358) [`157c823`](https://github.com/dotansimha/graphql-code-generator/commit/157c8236320f00b06c470e2289315179119d4504) Thanks [@eddeee888](https://github.com/eddeee888)! - Remove extraneous error stacktrace if fails to load `@parcel/watcher` - Updated dependencies [[`e324382`](https://github.com/dotansimha/graphql-code-generator/commit/e3243824cfe0d7ab463cf0d5a6455715510959be), [`98392fc`](https://github.com/dotansimha/graphql-code-generator/commit/98392fc5d91035b5b5b0ffdefd78d0398762a523)]: - @graphql-codegen/plugin-helpers@5.1.1 - @graphql-codegen/client-preset@4.8.2 ## 5.0.6 ### Patch Changes - [#10338](https://github.com/dotansimha/graphql-code-generator/pull/10338) [`5d1c4e1`](https://github.com/dotansimha/graphql-code-generator/commit/5d1c4e127d860ff89590fd3a1d01493b3289ad00) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix ignoreNoDocuments=true swallowing all errors - [#10333](https://github.com/dotansimha/graphql-code-generator/pull/10333) [`10ab58d`](https://github.com/dotansimha/graphql-code-generator/commit/10ab58dbc183dff460c410ffc7cc759186f91d4c) Thanks [@eddeee888](https://github.com/eddeee888)! - Improve syntax error messages whilst loading schema/document - Updated dependencies [[`c5efba3`](https://github.com/dotansimha/graphql-code-generator/commit/c5efba34a7b422720be9ce32937dd19fb0784bae)]: - @graphql-codegen/client-preset@4.8.1 ## 5.0.5 ### Patch Changes - [#10282](https://github.com/dotansimha/graphql-code-generator/pull/10282) [`7d7760d`](https://github.com/dotansimha/graphql-code-generator/commit/7d7760d55c21a99417c38ce5e77a6de22b5effcc) Thanks [@oprypkhantc](https://github.com/oprypkhantc)! - Fix watcher watching project root when schema URL is used ## 5.0.4 ### Patch Changes - [#10248](https://github.com/dotansimha/graphql-code-generator/pull/10248) [`72eb86f`](https://github.com/dotansimha/graphql-code-generator/commit/72eb86f49bd86da6308d80f9401bcc09478ca886) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@whatwg-node/fetch@^0.10.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/0.10.0) (from `^0.9.20`, in `dependencies`) - [#10227](https://github.com/dotansimha/graphql-code-generator/pull/10227) [`6f1741a`](https://github.com/dotansimha/graphql-code-generator/commit/6f1741af03689f8146178637ecabec18347e9331) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix schema pointers type to allow an array of pointers - Updated dependencies [[`8737dd8`](https://github.com/dotansimha/graphql-code-generator/commit/8737dd86b4ce3d14234a515fa494736bf7ec35dd), [`ed71811`](https://github.com/dotansimha/graphql-code-generator/commit/ed71811ace083be61c575609e361c629ed7c1740)]: - @graphql-codegen/client-preset@4.6.0 ## 5.0.3 ### Patch Changes - [#10069](https://github.com/dotansimha/graphql-code-generator/pull/10069) [`8bb34e7`](https://github.com/dotansimha/graphql-code-generator/commit/8bb34e7cd23a8891313828291c9f2edd6a3b67bc) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@whatwg-node/fetch@^0.9.20` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/0.9.20) (from `^0.8.0`, in `dependencies`) - Updated dependency [`graphql-config@^5.1.1` ↗︎](https://www.npmjs.com/package/graphql-config/v/5.1.1) (from `^5.0.2`, in `dependencies`) - [`e0092b5`](https://github.com/dotansimha/graphql-code-generator/commit/e0092b548f51c95be19c232515cf9a72873e7b83) Thanks [@ardatan](https://github.com/ardatan)! - Bump whatwg-node and graphql-config - Updated dependencies [[`8471a18`](https://github.com/dotansimha/graphql-code-generator/commit/8471a180cd61dc03dedace87876c5973b09b35f8), [`67e7556`](https://github.com/dotansimha/graphql-code-generator/commit/67e75561a3e862f26cfbb40e8ec5a08f821f9ddf)]: - @graphql-codegen/client-preset@4.4.0 ## 5.0.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/client-preset@4.2.2 - @graphql-codegen/core@4.0.2 - @graphql-codegen/plugin-helpers@5.0.3 ## 5.0.1 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Added dependency [`@graphql-codegen/client-preset@^4.1.0` ↗︎](https://www.npmjs.com/package/@graphql-codegen/client-preset/v/4.1.0) (to `dependencies`) - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - ignore events in `.git` directory - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - Surface error occurring during import of @parcel/watcher - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - Include @graphql-codegen/client-preset in @graphql-codegen/cli by default - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - fix watcher unable to find highest common directory on Windows - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/client-preset@4.2.0 - @graphql-codegen/core@4.0.1 - @graphql-codegen/plugin-helpers@5.0.2 ## 5.0.0 ### Major Changes - [#9506](https://github.com/dotansimha/graphql-code-generator/pull/9506) [`dd9c7e148`](https://github.com/dotansimha/graphql-code-generator/commit/dd9c7e14872f48592e530ff0d646449a5cb722b4) Thanks [@valkum](https://github.com/valkum)! - Make @parcel/watcher optional ### Patch Changes - [#9513](https://github.com/dotansimha/graphql-code-generator/pull/9513) [`fdd19d24d`](https://github.com/dotansimha/graphql-code-generator/commit/fdd19d24df21d3257f3e969b79856d18b6f73123) Thanks [@cichelero](https://github.com/cichelero)! - Update yaml dependency to 2.3.1 - Updated dependencies [[`bb1e0e96e`](https://github.com/dotansimha/graphql-code-generator/commit/bb1e0e96ed9d519684630cd7ea53869b48b4632e)]: - @graphql-codegen/plugin-helpers@5.0.1 ## 4.0.1 ### Patch Changes - [#9479](https://github.com/dotansimha/graphql-code-generator/pull/9479) [`0aa444b5d`](https://github.com/dotansimha/graphql-code-generator/commit/0aa444b5d092565c321643a55fb05c7301e303bf) Thanks [@gilgardosh](https://github.com/gilgardosh)! - dependencies updates: - Updated dependency [`graphql-config@^5.0.2` ↗︎](https://www.npmjs.com/package/graphql-config/v/5.0.2) (from `^5.0.1`, in `dependencies`) - [#9479](https://github.com/dotansimha/graphql-code-generator/pull/9479) [`0aa444b5d`](https://github.com/dotansimha/graphql-code-generator/commit/0aa444b5d092565c321643a55fb05c7301e303bf) Thanks [@gilgardosh](https://github.com/gilgardosh)! - Update graphql-config to v^5.0.2 ## 4.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`graphql-config@^5.0.0` ↗︎](https://www.npmjs.com/package/graphql-config/v/5.0.0) (from `^4.5.0`, in `dependencies`) - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-tools/apollo-engine-loader@^8.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/apollo-engine-loader/v/8.0.0) (from `^7.3.6`, in `dependencies`) - Updated dependency [`@graphql-tools/code-file-loader@^8.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/code-file-loader/v/8.0.0) (from `^7.3.17`, in `dependencies`) - Updated dependency [`@graphql-tools/git-loader@^8.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/git-loader/v/8.0.0) (from `^7.2.13`, in `dependencies`) - Updated dependency [`@graphql-tools/github-loader@^8.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/github-loader/v/8.0.0) (from `^7.3.28`, in `dependencies`) - Updated dependency [`@graphql-tools/graphql-file-loader@^8.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/graphql-file-loader/v/8.0.0) (from `^7.5.0`, in `dependencies`) - Updated dependency [`@graphql-tools/json-file-loader@^8.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/json-file-loader/v/8.0.0) (from `^7.4.1`, in `dependencies`) - Updated dependency [`@graphql-tools/load@^8.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/load/v/8.0.0) (from `^7.8.0`, in `dependencies`) - Updated dependency [`@graphql-tools/prisma-loader@^8.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/prisma-loader/v/8.0.0) (from `^7.2.69`, in `dependencies`) - Updated dependency [`@graphql-tools/url-loader@^8.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/url-loader/v/8.0.0) (from `^7.17.17`, in `dependencies`) - Updated dependency [`@graphql-tools/utils@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/10.0.0) (from `^9.0.0`, in `dependencies`) - Updated dependency [`cosmiconfig@^8.1.3` ↗︎](https://www.npmjs.com/package/cosmiconfig/v/8.1.3) (from `^7.0.0`, in `dependencies`) - Updated dependency [`graphql-config@^5.0.1` ↗︎](https://www.npmjs.com/package/graphql-config/v/5.0.1) (from `^4.5.0`, in `dependencies`) - [#9371](https://github.com/dotansimha/graphql-code-generator/pull/9371) [`d431f426e`](https://github.com/dotansimha/graphql-code-generator/commit/d431f426eb594b820ac712b9f5c616f4badf6bff) Thanks [@Axxxx0n](https://github.com/Axxxx0n)! - Fixed option ignoreNoDocuments when using graphql configs - [#9275](https://github.com/dotansimha/graphql-code-generator/pull/9275) [`2a5da5894`](https://github.com/dotansimha/graphql-code-generator/commit/2a5da589468eb5970587187adae9892ff1f13134) Thanks [@milesrichardson](https://github.com/milesrichardson)! - Trigger rebuilds in watch mode while respecting rules of precedence and negation, both in terms of global (top-level) config vs. local (per-output target) config, and in terms of watch patterns (higher priority) vs. documents/schemas (lower priority). This fixes an issue with overly-aggressive rebuilds during watch mode. - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0)]: - @graphql-codegen/core@4.0.0 - @graphql-codegen/plugin-helpers@5.0.0 ## 3.3.1 ### Patch Changes - [#9267](https://github.com/dotansimha/graphql-code-generator/pull/9267) [`183749346`](https://github.com/dotansimha/graphql-code-generator/commit/1837493464e0b661520deb38c1e5cbd5ed46f978) Thanks [@milesrichardson](https://github.com/milesrichardson)! - Fix watch mode to listen to longest common directory prefix of relevant files, rather than only files below the current working directory (fixes #9266). - [#9280](https://github.com/dotansimha/graphql-code-generator/pull/9280) [`ca1d72c40`](https://github.com/dotansimha/graphql-code-generator/commit/ca1d72c408a5f45ecdb17d556e1a3f7d6811cdf4) Thanks [@saihaj](https://github.com/saihaj)! - fix the default output directory for init command ## 3.3.0 ### Minor Changes - [#9151](https://github.com/dotansimha/graphql-code-generator/pull/9151) [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29) Thanks [@'./user/schema.mappers#UserMapper',](https://github.com/'./user/schema.mappers#UserMapper',)! - Add `watchPattern` config option for `generates` sections. By default, `watch` mode automatically watches all GraphQL schema and document files. This means when a change is detected, Codegen CLI is run. A user may want to run Codegen CLI when non-schema and non-document files are changed. Each `generates` section now has a `watchPattern` option to allow more file patterns to be added to the list of patterns to watch. In the example below, mappers are exported from `schema.mappers.ts` files. We want to re-run Codegen if the content of `*.mappers.ts` files change because they change the generated types file. To solve this, we can add mapper file patterns to watch using the glob pattern used for schema and document files. ```ts // codegen.ts const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { mappers: { Book: './book/schema.mappers#BookMapper', }, } watchPattern: 'src/schema/**/*.mappers.ts', // Watches mapper files in `watch` mode. Use an array for multiple patterns e.g. `['src/*.pattern1.ts','src/*.pattern2.ts']` }, }, }; ``` Then, run Codegen CLI in `watch` mode: ```shell yarn graphql-codegen --watch ``` Now, updating `*.mappers.ts` files re-runs Codegen! 🎉 Note: `watchPattern` is only used in `watch` mode i.e. running CLI with `--watch` flag. ### Patch Changes - Updated dependencies [[`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087)]: - @graphql-codegen/plugin-helpers@4.2.0 ## 3.2.2 ### Patch Changes - [#9086](https://github.com/dotansimha/graphql-code-generator/pull/9086) [`a34cef35b`](https://github.com/dotansimha/graphql-code-generator/commit/a34cef35b4cbbe83c54bd92f88882b325df173fd) Thanks [@beerose](https://github.com/beerose)! - dependencies updates: - Updated dependency [`graphql-config@^4.5.0` ↗︎](https://www.npmjs.com/package/graphql-config/v/4.5.0) (from `^4.4.0`, in `dependencies`) - Added dependency [`jiti@^1.17.1` ↗︎](https://www.npmjs.com/package/jiti/v/1.17.1) (to `dependencies`) - Removed dependency [`cosmiconfig-typescript-loader@^4.3.0` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-loader/v/4.3.0) (from `dependencies`) - Removed dependency [`ts-node@^10.9.1` ↗︎](https://www.npmjs.com/package/ts-node/v/10.9.1) (from `dependencies`) - [#9086](https://github.com/dotansimha/graphql-code-generator/pull/9086) [`a34cef35b`](https://github.com/dotansimha/graphql-code-generator/commit/a34cef35b4cbbe83c54bd92f88882b325df173fd) Thanks [@beerose](https://github.com/beerose)! - Support `codegen.ts` in ESM projects ## 3.2.1 ### Patch Changes - [#9051](https://github.com/dotansimha/graphql-code-generator/pull/9051) [`f7313f7ca`](https://github.com/dotansimha/graphql-code-generator/commit/f7313f7cabd81ee708e3345b2934aeeb978f65a3) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Added dependency [`micromatch@^4.0.5` ↗︎](https://www.npmjs.com/package/micromatch/v/4.0.5) (to `dependencies`) - [#9051](https://github.com/dotansimha/graphql-code-generator/pull/9051) [`f7313f7ca`](https://github.com/dotansimha/graphql-code-generator/commit/f7313f7cabd81ee708e3345b2934aeeb978f65a3) Thanks [@saihaj](https://github.com/saihaj)! - only run generate for files that users have listed in config to avoid running this over every change that codegen is not supposed to execute ## 3.2.0 ### Minor Changes - [#9009](https://github.com/dotansimha/graphql-code-generator/pull/9009) [`288ed0977`](https://github.com/dotansimha/graphql-code-generator/commit/288ed097745f9c06dd74a9398a050866caa3942a) Thanks [@saihaj](https://github.com/saihaj)! - use @parcel/watcher for improved watch functionality ### Patch Changes - [#9009](https://github.com/dotansimha/graphql-code-generator/pull/9009) [`288ed0977`](https://github.com/dotansimha/graphql-code-generator/commit/288ed097745f9c06dd74a9398a050866caa3942a) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Added dependency [`@parcel/watcher@^2.1.0` ↗︎](https://www.npmjs.com/package/@parcel/watcher/v/2.1.0) (to `dependencies`) - Removed dependency [`chokidar@^3.5.2` ↗︎](https://www.npmjs.com/package/chokidar/v/3.5.2) (from `dependencies`) ## 3.1.0 ### Minor Changes - [#8893](https://github.com/dotansimha/graphql-code-generator/pull/8893) [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c) Thanks [@n1ru4l](https://github.com/n1ru4l)! - It is no longer mandatory to declare an empty plugins array when using a preset - [#8723](https://github.com/dotansimha/graphql-code-generator/pull/8723) [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15) Thanks [@kazekyo](https://github.com/kazekyo)! - Introduce a new feature called DocumentTransform. DocumentTransform is a functionality that allows you to modify `documents` before they are processed by plugins. You can use functions passed to the `documentTransforms` option to make changes to GraphQL documents. To use this feature, you can write `documentTransforms` as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { // Make some changes to the documents return documents } } ] } } } export default config ``` For instance, to remove a `@localOnlyDirective` directive from `documents`, you can write the following code: ```js import type { CodegenConfig } from '@graphql-codegen/cli' import { visit } from 'graphql' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { return documents.map(documentFile => { documentFile.document = visit(documentFile.document, { Directive: { leave(node) { if (node.name.value === 'localOnlyDirective') return null } } }) return documentFile }) } } ] } } } export default config ``` DocumentTransform can also be specified by file name. You can create a custom file for a specific transformation and pass it to `documentTransforms`. Let's create the document transform as a file: ```js module.exports = { transform: ({ documents }) => { // Make some changes to the documents return documents } } ``` Then, you can specify the file name as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: ['./my-document-transform.js'] } } } export default config ``` ### Patch Changes - [#9000](https://github.com/dotansimha/graphql-code-generator/pull/9000) [`4c422ccf6`](https://github.com/dotansimha/graphql-code-generator/commit/4c422ccf6384cfb0d0949ebe5567923973b1a044) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@whatwg-node/fetch@^0.8.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/0.8.0) (from `^0.6.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/core@3.1.0 - @graphql-codegen/plugin-helpers@4.1.0 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - [#8883](https://github.com/dotansimha/graphql-code-generator/pull/8883) [`321d5112e`](https://github.com/dotansimha/graphql-code-generator/commit/321d5112e802fd1d96daf556095b102a81763804) Thanks [@Solo-steven](https://github.com/Solo-steven)! - Fix PluckConfig overwrite problem. - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/core@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 ## 2.16.5 ### Patch Changes - [#8865](https://github.com/dotansimha/graphql-code-generator/pull/8865) [`e4d073b16`](https://github.com/dotansimha/graphql-code-generator/commit/e4d073b16f904e0879a3d15774ddc9826b0ab5e5) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-codegen/core@^2.6.8` ↗︎](https://www.npmjs.com/package/@graphql-codegen/core/v/2.6.8) (from `2.6.8`, in `dependencies`) - Updated dependency [`@graphql-tools/load@^7.8.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/load/v/7.8.0) (from `7.8.0`, in `dependencies`) - Updated dependency [`cosmiconfig-typescript-loader@^4.3.0` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-loader/v/4.3.0) (from `4.3.0`, in `dependencies`) - Updated dependency [`graphql-config@^4.4.0` ↗︎](https://www.npmjs.com/package/graphql-config/v/4.4.0) (from `4.4.0`, in `dependencies`) - Added dependency [`ts-node@^10.9.1` ↗︎](https://www.npmjs.com/package/ts-node/v/10.9.1) (to `dependencies`) - Removed dependency [`ts-node@>=10` ↗︎](https://www.npmjs.com/package/ts-node/v/10.0.0) (from `peerDependencies`) - [#8808](https://github.com/dotansimha/graphql-code-generator/pull/8808) [`884d25c4e`](https://github.com/dotansimha/graphql-code-generator/commit/884d25c4edb099a46bffb23ffd935abec7d14f80) Thanks [@rwu823](https://github.com/rwu823)! - fix: `gqlMagicComment` type - [#8865](https://github.com/dotansimha/graphql-code-generator/pull/8865) [`e4d073b16`](https://github.com/dotansimha/graphql-code-generator/commit/e4d073b16f904e0879a3d15774ddc9826b0ab5e5) Thanks [@n1ru4l](https://github.com/n1ru4l)! - move ts-node from peer dependencies to dependencies ## 2.16.4 ### Patch Changes - [#8770](https://github.com/dotansimha/graphql-code-generator/pull/8770) [`4774247e9`](https://github.com/dotansimha/graphql-code-generator/commit/4774247e9d29838075660d0e08c6b3c6ea57689f) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`graphql-config@4.4.0` ↗︎](https://www.npmjs.com/package/graphql-config/v/4.4.0) (from `4.3.6`, in `dependencies`) - [#8790](https://github.com/dotansimha/graphql-code-generator/pull/8790) [`fe12b4826`](https://github.com/dotansimha/graphql-code-generator/commit/fe12b4826d666ef69c38cd72bdd44f1bb262caf6) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@whatwg-node/fetch@^0.6.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/0.6.0) (from `^0.5.0`, in `dependencies`) ## 2.16.3 ### Patch Changes - [#8779](https://github.com/dotansimha/graphql-code-generator/pull/8779) [`ad5d83313`](https://github.com/dotansimha/graphql-code-generator/commit/ad5d83313fe146f0593df7ae2efa3c35459e577a) Thanks [@louisscruz](https://github.com/louisscruz)! - add ts-node as a peerDependency ## 2.16.2 ### Patch Changes - [#8715](https://github.com/dotansimha/graphql-code-generator/pull/8715) [`b1512a59a`](https://github.com/dotansimha/graphql-code-generator/commit/b1512a59a0195c1f67a7e87d6a450e98d115df39) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`cosmiconfig-typescript-loader@4.2.0` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-loader/v/4.2.0) (from `4.1.1`, in `dependencies`) - [#8729](https://github.com/dotansimha/graphql-code-generator/pull/8729) [`e6ff224fb`](https://github.com/dotansimha/graphql-code-generator/commit/e6ff224fb70cab38e30a963eb9135b2f6257e46c) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`cosmiconfig-typescript-loader@4.3.0` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-loader/v/4.3.0) (from `4.2.0`, in `dependencies`) - [#8771](https://github.com/dotansimha/graphql-code-generator/pull/8771) [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.9.0`, in `dependencies`) - [#8765](https://github.com/dotansimha/graphql-code-generator/pull/8765) [`a9c5414d2`](https://github.com/dotansimha/graphql-code-generator/commit/a9c5414d2ca4d0138eed3d14b0c22046128607dc) Thanks [@aniketdd](https://github.com/aniketdd)! - update @graphql-tools/prisma-loader - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 ## 2.16.1 ### Patch Changes - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/core@2.6.8 ## 2.16.0 ### Minor Changes - [#8662](https://github.com/dotansimha/graphql-code-generator/pull/8662) [`c0183810f`](https://github.com/dotansimha/graphql-code-generator/commit/c0183810f0178aec6f49ab8a6f35f7adc4d9f13e) Thanks [@jantimon](https://github.com/jantimon)! - the life cycle hook beforeOneFileWrite is now able to modify the generated content ### Patch Changes - Updated dependencies [[`c0183810f`](https://github.com/dotansimha/graphql-code-generator/commit/c0183810f0178aec6f49ab8a6f35f7adc4d9f13e)]: - @graphql-codegen/plugin-helpers@3.1.0 ## 2.15.1 ### Patch Changes - [#8673](https://github.com/dotansimha/graphql-code-generator/pull/8673) [`a07b6d6c1`](https://github.com/dotansimha/graphql-code-generator/commit/a07b6d6c1b05b2f77efb398b05d29130bae429e9) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Removed dependency [`ansi-escapes@^4.3.1` ↗︎](https://www.npmjs.com/package/ansi-escapes/v/4.3.1) (from `dependencies`) - [#8706](https://github.com/dotansimha/graphql-code-generator/pull/8706) [`8ff9b41bd`](https://github.com/dotansimha/graphql-code-generator/commit/8ff9b41bd9323b6f3dde2014fecc4fd39c6a26fc) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@whatwg-node/fetch@^0.5.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/0.5.0) (from `^0.3.0`, in `dependencies`) - [#8661](https://github.com/dotansimha/graphql-code-generator/pull/8661) [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482) Thanks [@jantimon](https://github.com/jantimon)! - refactor hook execution - [#8652](https://github.com/dotansimha/graphql-code-generator/pull/8652) [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84) Thanks [@jantimon](https://github.com/jantimon)! - improve typings for life cycle hooks - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/core@2.6.7 ## 2.15.0 ### Minor Changes - [#8590](https://github.com/dotansimha/graphql-code-generator/pull/8590) [`2c7fa51c6`](https://github.com/dotansimha/graphql-code-generator/commit/2c7fa51c628a0337f2abfe1b91fe00c6d5fbe749) Thanks [@Diizzayy](https://github.com/Diizzayy)! - register TypeScriptLoader when needed ## 2.14.1 ### Patch Changes - [#8642](https://github.com/dotansimha/graphql-code-generator/pull/8642) [`5afa923e8`](https://github.com/dotansimha/graphql-code-generator/commit/5afa923e8e4e8db9bbd602e8abf6a193761a282d) Thanks [@jantimon](https://github.com/jantimon)! - faster type generation - [#8653](https://github.com/dotansimha/graphql-code-generator/pull/8653) [`d0bc51283`](https://github.com/dotansimha/graphql-code-generator/commit/d0bc51283bb7e496f8933511a8ff5ac2ba547bc8) Thanks [@saihaj](https://github.com/saihaj)! - fix bad concurrency config ## 2.14.0 ### Minor Changes - [#8647](https://github.com/dotansimha/graphql-code-generator/pull/8647) [`40a6761a6`](https://github.com/dotansimha/graphql-code-generator/commit/40a6761a602fca592c6f4f0653c819e8debe007b) Thanks [@charlypoly](https://github.com/charlypoly)! - Enable support for loading TS files with import assertions ### Patch Changes - [#8647](https://github.com/dotansimha/graphql-code-generator/pull/8647) [`40a6761a6`](https://github.com/dotansimha/graphql-code-generator/commit/40a6761a602fca592c6f4f0653c819e8debe007b) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Updated dependency [`@graphql-tools/code-file-loader@^7.3.13` ↗︎](https://www.npmjs.com/package/@graphql-tools/code-file-loader/v/7.3.13) (from `^7.3.1`, in `dependencies`) - Updated dependency [`@graphql-tools/git-loader@^7.2.13` ↗︎](https://www.npmjs.com/package/@graphql-tools/git-loader/v/7.2.13) (from `^7.2.1`, in `dependencies`) - Updated dependency [`@graphql-tools/github-loader@^7.3.20` ↗︎](https://www.npmjs.com/package/@graphql-tools/github-loader/v/7.3.20) (from `^7.3.6`, in `dependencies`) ## 2.13.12 ### Patch Changes - Updated dependencies [[`45eb2b18a`](https://github.com/dotansimha/graphql-code-generator/commit/45eb2b18adf25366248bf8d67ef696431db5ee0e), [`45eb2b18a`](https://github.com/dotansimha/graphql-code-generator/commit/45eb2b18adf25366248bf8d67ef696431db5ee0e)]: - @graphql-codegen/core@2.6.6 ## 2.13.11 ### Patch Changes - [#8556](https://github.com/dotansimha/graphql-code-generator/pull/8556) [`64e553c3f`](https://github.com/dotansimha/graphql-code-generator/commit/64e553c3f62618a2aedf122d292e2700fd93d6e1) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Updated dependency [`@graphql-codegen/core@2.6.4` ↗︎](https://www.npmjs.com/package/@graphql-codegen/core/v/2.6.4) (from `2.6.3`, in `dependencies`) - Updated dependencies [[`64e553c3f`](https://github.com/dotansimha/graphql-code-generator/commit/64e553c3f62618a2aedf122d292e2700fd93d6e1)]: - @graphql-codegen/core@2.6.5 ## 2.13.10 ### Patch Changes - Updated dependencies [[`516170ef6`](https://github.com/dotansimha/graphql-code-generator/commit/516170ef6cb636c950d560ddf12fa1d2f7ee1c57), [`516170ef6`](https://github.com/dotansimha/graphql-code-generator/commit/516170ef6cb636c950d560ddf12fa1d2f7ee1c57)]: - @graphql-codegen/core@2.6.4 ## 2.13.9 ### Patch Changes - [#8525](https://github.com/dotansimha/graphql-code-generator/pull/8525) [`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127) Thanks [@charlypoly](https://github.com/charlypoly)! - remove `DetailledError`, not supported by Listr renderer - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/core@2.6.3 - @graphql-codegen/plugin-helpers@2.7.2 ## 2.13.8 ### Patch Changes - [#8535](https://github.com/dotansimha/graphql-code-generator/pull/8535) [`88aa38ff9`](https://github.com/dotansimha/graphql-code-generator/commit/88aa38ff9eb94b66d783a4af3116d9d3313fdbfd) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Updated dependency [`@graphql-tools/load@7.8.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/load/v/7.8.0) (from `^7.7.1`, in `dependencies`) - [#8535](https://github.com/dotansimha/graphql-code-generator/pull/8535) [`88aa38ff9`](https://github.com/dotansimha/graphql-code-generator/commit/88aa38ff9eb94b66d783a4af3116d9d3313fdbfd) Thanks [@charlypoly](https://github.com/charlypoly)! - Upgrade `@graphql-tools/load` to get benefits of debug mode ## 2.13.7 ### Patch Changes - [#8481](https://github.com/dotansimha/graphql-code-generator/pull/8481) [`8473682c4`](https://github.com/dotansimha/graphql-code-generator/commit/8473682c48559382b0a3edd4a494aeaf1c5b99ff) Thanks [@charlypoly](https://github.com/charlypoly)! - ensure to generate `codegen.ts` in a typescript setup ## 2.13.6 ### Patch Changes - [#8383](https://github.com/dotansimha/graphql-code-generator/pull/8383) [`c4d9566c7`](https://github.com/dotansimha/graphql-code-generator/commit/c4d9566c792413fa26a537bce268a547c61e5f13) Thanks [@vhenzl](https://github.com/vhenzl)! - Fix `executeHooks` to quote args for shell command ## 2.13.5 ### Patch Changes - [#8452](https://github.com/dotansimha/graphql-code-generator/pull/8452) [`cb1f93618`](https://github.com/dotansimha/graphql-code-generator/commit/cb1f93618b3c92cd092b740973d2469c232c2c00) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Updated dependency [`graphql-config@4.3.6` ↗︎](https://www.npmjs.com/package/graphql-config/v/4.3.6) (from `^4.3.5`, in `dependencies`) - [#8452](https://github.com/dotansimha/graphql-code-generator/pull/8452) [`cb1f93618`](https://github.com/dotansimha/graphql-code-generator/commit/cb1f93618b3c92cd092b740973d2469c232c2c00) Thanks [@charlypoly](https://github.com/charlypoly)! - conflict with `graphql-config` also using TypeScriptLoader(), causing a double `ts-node` register. ## 2.13.4 ### Patch Changes - [#8441](https://github.com/dotansimha/graphql-code-generator/pull/8441) [`6785f7f0d`](https://github.com/dotansimha/graphql-code-generator/commit/6785f7f0df6b3eb14d30abf37924791c45a4d586) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Added dependency [`cosmiconfig-typescript-loader@4.1.1` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-loader/v/4.1.1) (to `dependencies`) - Removed dependency [`cosmiconfig-typescript-swc-loader@0.0.2` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-swc-loader/v/0.0.2) (from `dependencies`) - [#8441](https://github.com/dotansimha/graphql-code-generator/pull/8441) [`6785f7f0d`](https://github.com/dotansimha/graphql-code-generator/commit/6785f7f0df6b3eb14d30abf37924791c45a4d586) Thanks [@charlypoly](https://github.com/charlypoly)! - fix(cli): revert to `cosmiconfig-typescript-loader` ## 2.13.3 ### Patch Changes - [#8415](https://github.com/dotansimha/graphql-code-generator/pull/8415) [`15d500776`](https://github.com/dotansimha/graphql-code-generator/commit/15d50077680ff96a8d09cc65acd2f82683e67fb5) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Added dependency [`cosmiconfig-typescript-swc-loader@0.0.2` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-swc-loader/v/0.0.2) (to `dependencies`) - Removed dependency [`cosmiconfig-typescript-loader@4.0.0` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-loader/v/4.0.0) (from `dependencies`) - [#8415](https://github.com/dotansimha/graphql-code-generator/pull/8415) [`15d500776`](https://github.com/dotansimha/graphql-code-generator/commit/15d50077680ff96a8d09cc65acd2f82683e67fb5) Thanks [@charlypoly](https://github.com/charlypoly)! - feat(cli): drop peerDep on "typescript" by using `cosmiconfig-typescript-swc-loader` ## 2.13.2 ### Patch Changes - [#8427](https://github.com/dotansimha/graphql-code-generator/pull/8427) [`5524ac447`](https://github.com/dotansimha/graphql-code-generator/commit/5524ac447612ff05bfd68f4b758dfcd0fa9e7356) Thanks [@charlypoly](https://github.com/charlypoly)! - Fix issue with `graphql-codegen init` installation wizard ## 2.13.1 ### Patch Changes - [#8405](https://github.com/dotansimha/graphql-code-generator/pull/8405) [`7f7e52bc2`](https://github.com/dotansimha/graphql-code-generator/commit/7f7e52bc22749d1dd6946510856103ab683a1807) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Removed dependency [`@graphql-codegen/client-preset@1.0.1` ↗︎](https://www.npmjs.com/package/@graphql-codegen/client-preset/v/1.0.1) (from `dependencies`) - [#8405](https://github.com/dotansimha/graphql-code-generator/pull/8405) [`7f7e52bc2`](https://github.com/dotansimha/graphql-code-generator/commit/7f7e52bc22749d1dd6946510856103ab683a1807) Thanks [@charlypoly](https://github.com/charlypoly)! - remove `@graphql-codegen/client-preset` direct dependency ## 2.13.0 ### Minor Changes - [#8302](https://github.com/dotansimha/graphql-code-generator/pull/8302) [`876844e76`](https://github.com/dotansimha/graphql-code-generator/commit/876844e7644a917172f09b3c4eb54a2f4c90e4c6) Thanks [@charlypoly](https://github.com/charlypoly)! - **`@graphql-codegen/gql-tag-operations` and `@graphql-codegen/gql-tag-operations-preset`** Introduce a `gqlTagName` configuration option *** **`@graphql-codegen/client-preset`** New preset for GraphQL Code Generator v3, more information on the RFC: https://github.com/dotansimha/graphql-code-generator/issues/8296 *** **`@graphql-codegen/cli`** Update init wizard with 3.0 recommendations (`codegen.ts`, `client` preset) ### Patch Changes - [#8302](https://github.com/dotansimha/graphql-code-generator/pull/8302) [`876844e76`](https://github.com/dotansimha/graphql-code-generator/commit/876844e7644a917172f09b3c4eb54a2f4c90e4c6) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Updated dependency [`@graphql-codegen/plugin-helpers@^2.6.2` ↗︎](https://www.npmjs.com/package/@graphql-codegen/plugin-helpers/v/2.6.2) (from `^2.7.1`, in `dependencies`) - Updated dependency [`@whatwg-node/fetch@^0.3.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/0.3.0) (from `^0.4.0`, in `dependencies`) - Updated dependency [`cosmiconfig-typescript-loader@4.0.0` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-loader/v/4.0.0) (from `^4.0.0`, in `dependencies`) - Added dependency [`@babel/generator@^7.18.13` ↗︎](https://www.npmjs.com/package/@babel/generator/v/7.18.13) (to `dependencies`) - Added dependency [`@babel/template@^7.18.10` ↗︎](https://www.npmjs.com/package/@babel/template/v/7.18.10) (to `dependencies`) - Added dependency [`@babel/types@^7.18.13` ↗︎](https://www.npmjs.com/package/@babel/types/v/7.18.13) (to `dependencies`) - Added dependency [`@graphql-codegen/client-preset@1.0.1-alpha-20220823170145-c93d8aee3` ↗︎](https://www.npmjs.com/package/@graphql-codegen/client-preset/v/1.0.1) (to `dependencies`) - Updated dependencies [[`876844e76`](https://github.com/dotansimha/graphql-code-generator/commit/876844e7644a917172f09b3c4eb54a2f4c90e4c6)]: - @graphql-codegen/client-preset@1.0.1 ## 2.12.2 ### Patch Changes - [#8384](https://github.com/dotansimha/graphql-code-generator/pull/8384) [`9d3eedaea`](https://github.com/dotansimha/graphql-code-generator/commit/9d3eedaea6a5a505a8f693378bed44a1648a3a37) Thanks [@charlypoly](https://github.com/charlypoly)! - CLI: properly print error that occurred during hook execution ## 2.12.1 ### Patch Changes - [#8335](https://github.com/dotansimha/graphql-code-generator/pull/8335) [`3e121d92e`](https://github.com/dotansimha/graphql-code-generator/commit/3e121d92ebd563a82dbc367cd3e9194ebe5ca1ee) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@whatwg-node/fetch@^0.4.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/null) (from `^0.3.0`, in `dependencies`) - [#8368](https://github.com/dotansimha/graphql-code-generator/pull/8368) [`4113b1bd3`](https://github.com/dotansimha/graphql-code-generator/commit/4113b1bd39f3d32759c68a292e8492a0dd4f7371) Thanks [@charlypoly](https://github.com/charlypoly)! - fix(cli): support ApolloEngine loader in TypeScript config - Updated dependencies [[`4113b1bd3`](https://github.com/dotansimha/graphql-code-generator/commit/4113b1bd39f3d32759c68a292e8492a0dd4f7371)]: - @graphql-codegen/plugin-helpers@2.7.1 ## 2.12.0 ### Minor Changes - [#8301](https://github.com/dotansimha/graphql-code-generator/pull/8301) [`2ed21a471`](https://github.com/dotansimha/graphql-code-generator/commit/2ed21a471f8de58ecafebf4bf64b3c32cee24d2f) Thanks [@charlypoly](https://github.com/charlypoly)! - Introduces support for TypeScript config file and a new preset lifecycle (required for `client-preset`) ### Patch Changes - [#8291](https://github.com/dotansimha/graphql-code-generator/pull/8291) [`d8b4012e1`](https://github.com/dotansimha/graphql-code-generator/commit/d8b4012e1fdbdcff6f9e62365b57426cef578d9a) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`graphql-config@^4.3.5` ↗︎](https://www.npmjs.com/package/graphql-config/v/null) (from `^4.3.4`, in `dependencies`) - [#8301](https://github.com/dotansimha/graphql-code-generator/pull/8301) [`2ed21a471`](https://github.com/dotansimha/graphql-code-generator/commit/2ed21a471f8de58ecafebf4bf64b3c32cee24d2f) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Added dependency [`cosmiconfig-typescript-loader@^4.0.0` ↗︎](https://www.npmjs.com/package/cosmiconfig-typescript-loader/v/null) (to `dependencies`) - Updated dependencies [[`2ed21a471`](https://github.com/dotansimha/graphql-code-generator/commit/2ed21a471f8de58ecafebf4bf64b3c32cee24d2f)]: - @graphql-codegen/plugin-helpers@2.7.0 ## 2.11.8 ### Patch Changes - [#8289](https://github.com/dotansimha/graphql-code-generator/pull/8289) [`b5897fcad`](https://github.com/dotansimha/graphql-code-generator/commit/b5897fcad2832d9ffbed0eb2f59e6b7535f4b61c) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`graphql-config@^4.3.4` ↗︎](https://www.npmjs.com/package/graphql-config/v/null) (from `^4.3.1`, in `dependencies`) - [#8289](https://github.com/dotansimha/graphql-code-generator/pull/8289) [`b5897fcad`](https://github.com/dotansimha/graphql-code-generator/commit/b5897fcad2832d9ffbed0eb2f59e6b7535f4b61c) Thanks [@n1ru4l](https://github.com/n1ru4l)! - resolve issue for loading typescript configs ## 2.11.7 ### Patch Changes - [#8274](https://github.com/dotansimha/graphql-code-generator/pull/8274) [`b18a0319f`](https://github.com/dotansimha/graphql-code-generator/commit/b18a0319f5f24f2675df8d12d9b440b67b0445bf) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@whatwg-node/fetch@^0.3.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/null) (from `^0.2.3`, in `dependencies`) ## 2.11.6 ### Patch Changes - Updated dependencies [[`6c7d3e54b`](https://github.com/dotansimha/graphql-code-generator/commit/6c7d3e54bb3cb53d8bbbd25e31c45b66f29f4640)]: - @graphql-codegen/core@2.6.2 ## 2.11.5 ### Patch Changes - [#8198](https://github.com/dotansimha/graphql-code-generator/pull/8198) [`1c7a8c0ad`](https://github.com/dotansimha/graphql-code-generator/commit/1c7a8c0ade2cd1f505b303c742aa31b4489cc12d) Thanks [@charlypoly](https://github.com/charlypoly)! - fix(ci): regression on error output ## 2.11.4 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f)]: - @graphql-codegen/core@2.6.1 - @graphql-codegen/plugin-helpers@2.6.2 ## 2.11.3 ### Patch Changes - b75ca4b48: Prevent cli from early returning when run init command. ## 2.11.2 ### Patch Changes - 8cd1526c4: chore(deps): update `@whatwg-node/fetch` to fix vulnerability ## 2.11.1 ### Patch Changes - 20bf4b225: support for path containing "&" characters ## 2.11.0 ### Minor Changes - fd6be805b: feat(cli): add a dry-run mode with `--check` cli flag ### Patch Changes - 6a2e328e6: feat(cli): `--verbose` and `--debug` flags - Updated dependencies [6a2e328e6] - @graphql-codegen/plugin-helpers@2.6.1 ## 2.10.0 ### Minor Changes - 273ad602f: Replace cross-undici-fetch with @whatwg-node/fetch to fix security vulnerability from undici ### Patch Changes - cc18923d3: feat(hooks): forward hooks logs to debug logs ## 2.9.1 ### Patch Changes - e2cfc5c36: fix(cli): prevent duplicated error messages on fail (without watcher) ## 2.9.0 ### Minor Changes - 2cbcbb371: Add new flag to emit legacy common js imports. Default it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065). You can use the option in your config: ```yaml schema: 'schema.graphql' documents: - 'src/**/*.graphql' emitLegacyCommonJSImports: true ``` Alternative you can use the CLI to set this option: ```bash $ codegen --config-file=config.yml --emit-legacy-common-js-imports ``` ### Patch Changes - 32c1560f1: getPluginByName fails unexpectedly when plugin is not prefixed with @graphq-codegen in ESM context MODULE_NOT_FOUND is the error code you receive in a CommonJS context when you require() a module and it does not exist. ERR_MODULE_NOT_FOUND is the error code you receive in an ESM context when you import or import() ad module that does not exist. - Updated dependencies [2cbcbb371] - @graphql-codegen/plugin-helpers@2.6.0 ## 2.8.1 ### Patch Changes - 147e801bf: Add `tslib` as a dependency. See https://github.com/dotansimha/graphql-code-generator/issues/8075 ## 2.8.0 ### Minor Changes - d84afec09: Add bin CLI command for running `graphql-code-generator` in ESM mode. You can now use `graphql-codegen-esm` instead of `graphql-codegen`. GraphQL Code Generator will continue supporting both ESM and CommonJS in parallel. - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) - 8e44df58b: Add new config option to not exit with non-zero exit code when there are no documents. You can use this option in your config: ```yaml schema: 'schema.graphql' documents: - 'src/**/*.graphql' ignoreNoDocuments: true ``` Alternative you can use the CLI to set this option: ```bash $ codegen --config-file=config.yml --ignore-no-documents ``` ### Patch Changes - e7870ac28: Fix security vulnerability by removing `latest-version` dependency. - dce40edeb: Allow to disable watch mode from CLI to overwrite the config. Now you can do: ```bash $ graphql-codegen --watch=false ``` - 2e86ecb65: ### Summary - Migrate to [`listr2`](https://listr2.kilic.dev) - Remove custom renderer for `listr` - Remove unused dependencies ### Why [`listr`](https://github.com/SamVerschueren/listr) is not actively maintained and we have to maintain our custom renderer for it to display errors. Migrating to `listr2` it just works out of the almost similar to how it was working in past and is a actively maintained. ### Dev notes Big change for us is how errors were collected. In `listr` errors were thrown and were caught in the `end` function of our custom `listr` Renderer but with `listr2` we don't really get `Error` in `end` function always so instead we use the [context](https://listr2.kilic.dev/getting-started/the-concept-of-context) to collect errors from all the tasks and then show them after all the tasks are finished. - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/core@2.6.0 - @graphql-codegen/plugin-helpers@2.5.0 ## 2.7.0 ### Minor Changes - e050230c0: Remove unnecessary browser check ### Patch Changes - dfd9f07dc: Fix/multi project - 2fb1d8b87: Remove unused `tryToBuildSchema` function - 4dce44263: Bumps `@graphql-tools/url-loader` to the latest `cross-undici-fetch` version that has pinned `undici` to `~5.5.0` in order to fix a bug/breaking-change introduced with `undici@5.6.0` that causes a `GET/HEAD requests cannot have 'body'` error. See https://github.com/ardatan/graphql-tools/pull/4559#issue-1292915844 for more details. ## 2.6.4 ### Patch Changes - 92f714278: Revert "Upgrade latest version" ## 2.6.3 ### Patch Changes - c1fe7758a: Remove unused deps - 52b41e90e: bump latest-version to patch vuln ## 2.6.2 ### Patch Changes - 1e3d37a34: resolve local presets ## 2.6.1 ### Patch Changes - cb9adeb96: Cache validation of documents - Updated dependencies [cb9adeb96] - @graphql-codegen/core@2.5.1 - @graphql-codegen/plugin-helpers@2.4.1 ## 2.6.0 ### Minor Changes - 35566a02c: Use os.cpus to calculate concurrency limit - acc62e548: fix(deps): remove unnecessary `dotenv` main dependency - 35566a02c: Async File System ## 2.5.0 ### Minor Changes - 754a33715: Performance Profiler --profile ### Patch Changes - f13d3554e: #5064 Display detailed errors from CLI - be7cb3a82: Performance work: resolvers plugins, documents loading - Updated dependencies [754a33715] - @graphql-codegen/core@2.5.0 - @graphql-codegen/plugin-helpers@2.4.0 ## 2.4.0 ### Minor Changes - 4c42e2a71: Performance optimizations in schema and documents loading (shared promises) ## 2.3.1 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [8643b3bf3] - Updated dependencies [b61dc57cf] - Updated dependencies [6002feb3d] - @graphql-codegen/core@2.4.0 - @graphql-codegen/plugin-helpers@2.3.2 ## 2.3.0 ### Minor Changes - 50c1d3247: feat(cli): export loadCodegenConfig to load codegen configuration files ### Patch Changes - 04e2d833b: export generateSearchPlaces ## 2.2.2 ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/core@2.3.0 - @graphql-codegen/plugin-helpers@2.3.0 ## 2.2.1 ### Patch Changes - Updated dependencies [7c60e5acc] - @graphql-codegen/core@2.2.0 - @graphql-codegen/plugin-helpers@2.2.0 ## 2.2.0 ### Minor Changes - 3e38de399: enhance: sort the schema before processing to have more consistent results. You can disable it with `sort: false`. ### Patch Changes - 3e38de399: fix: handle convertExtensions properly with schema definitions ## 2.1.1 ### Patch Changes - d3c556f8e: fix: do not alter the indentation of documents ## 2.1.0 ### Minor Changes - 39773f59b: enhance(plugins): use getDocumentNodeFromSchema and other utilities from @graphql-tools/utils - 440172cfe: support ESM ### Patch Changes - 24185985a: bump graphql-tools package versions - 72044c1bd: fix: do not alter the indentation of documents loaded via graphql-config - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/core@2.1.0 - @graphql-codegen/plugin-helpers@2.1.0 ## 2.0.1 ### Patch Changes - edd029e87: fix(graphql-modules-preset): do not parse SDL and use extendedSources that have parsed document already ## 2.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [b0cb13df4] - Updated dependencies [d80efdec4] - @graphql-codegen/core@2.0.0 - @graphql-codegen/plugin-helpers@2.0.0 ## 1.21.8 ### Patch Changes - e1643e6d4: Fix exception `loader.loaderId is not a function` caused by conflict with an internal dependency of Codegen. ## 1.21.7 ### Patch Changes - 470336a1: don't require plugins for for config if preset provides plugin. Instead the preset should throw if no plugins were provided. - Updated dependencies [470336a1] - @graphql-codegen/plugin-helpers@1.18.8 ## 1.21.6 ### Patch Changes - 3b82d1bd: update chokidar ## 1.21.5 ### Patch Changes - dfd25caf: chore(deps): bump graphql-tools versions - Updated dependencies [dfd25caf] - @graphql-codegen/core@1.17.10 - @graphql-codegen/plugin-helpers@1.18.7 ## 1.21.4 ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - @graphql-codegen/plugin-helpers@1.18.5 ## 1.21.3 ### Patch Changes - 23862e7e: fix(naming-convention): revert and pin change-case-all dependency for workaround #3256 - Updated dependencies [23862e7e] - @graphql-codegen/plugin-helpers@1.18.4 ## 1.21.2 ### Patch Changes - 29b75b1e: enhance(namingConvention): use change-case-all instead of individual packages for naming convention - Updated dependencies [29b75b1e] - @graphql-codegen/plugin-helpers@1.18.3 ## 1.21.0 ### Minor Changes - dfef1c7c: feat(cli): pass parameters to loaders from plugin config ## 1.20.1 ### Patch Changes - f86365c2: Dependencies cleanup ## 1.20.0 ### Minor Changes - 0e9ddb5a: Add `merge` (`<<`) syntax for `yaml` configurations ### Patch Changes - bff3fa88: CLI with watch option will reload using new config on change - 9ebf1877: Fix wrong MODULE_NOT_FOUND for missing dependencies - aa955f15: fix hooks as single function ## 1.19.4 ### Patch Changes - 920d8e95: Allow loading configuration from package.json file ## 1.19.3 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/core@1.17.9 - @graphql-codegen/plugin-helpers@1.18.2 ## 1.19.2 ### Patch Changes - faa13973: Fix issues with missing sources in loadSchema - faa13973: fix(cli): use default options of codegen for graphql-config's load methods ## 1.19.1 ### Patch Changes - 4ad0319a: Resolve modules passed through the -r flag relative to the cwd - 93e49f89: Correctly resolve relative to the cwd - Updated dependencies [eaf45d1f] - @graphql-codegen/plugin-helpers@1.18.1 ## 1.19.0 ### Minor Changes - 857c603c: Adds the --errors-only flag to the cli to print errors only. ### Patch Changes - Updated dependencies [857c603c] - @graphql-codegen/plugin-helpers@1.18.0 ## 1.18.0 ### Minor Changes - ceb9fe0c: Changes watch mode to not use polling by default and adds configurable override ### Patch Changes - 186962c9: Use `fs.statSync` when creating custom require instead of `path.extname` ## 1.17.10 ### Patch Changes - 2900ee29: Check the error code instead of the error message to determine if a package wasn't found ## 1.17.9 ### Patch Changes - e7d56e32: fix issues with init command and missing versions - 398b094b: Load user provided things relative to the config - Updated dependencies [da8bdd17] - @graphql-codegen/plugin-helpers@1.17.9 ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - Updated dependencies [ac067ea0] - @graphql-codegen/core@1.17.8 - @graphql-codegen/plugin-helpers@1.17.8 ================================================ FILE: packages/graphql-codegen-cli/README.md ================================================ # GraphQL Code Generator

    Live demo and full documentation: [the-guild.dev/graphql/codegen](https://the-guild.dev/graphql/codegen) Project repository: [graphql-code-generator](https://github.com/dotansimha/graphql-code-generator) ================================================ FILE: packages/graphql-codegen-cli/package.json ================================================ { "name": "@graphql-codegen/cli", "version": "6.2.1", "license": "MIT", "bin": { "gql-gen": "dist/cjs/bin.js", "graphql-codegen": "dist/cjs/bin.js", "graphql-code-generator": "dist/cjs/bin.js", "graphql-codegen-esm": "dist/esm/bin.js" }, "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/graphql-codegen-cli" }, "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "keywords": [ "gql", "generator", "code", "types", "interfaces", "graphql", "codegen", "apollo", "node", "typescript", "ts", "flow", "types", "d.ts", "typings" ], "author": "Dotan Simha ", "bugs": { "url": "https://github.com/dotansimha/graphql-codegen/issues" }, "homepage": "https://github.com/dotansimha/graphql-code-generator#readme", "dependencies": { "@babel/generator": "^7.18.13", "@babel/template": "^7.18.10", "@babel/types": "^7.18.13", "@graphql-codegen/client-preset": "^5.2.4", "@graphql-codegen/core": "^5.0.1", "@graphql-codegen/plugin-helpers": "^6.2.0", "@graphql-tools/apollo-engine-loader": "^8.0.28", "@graphql-tools/code-file-loader": "^8.1.28", "@graphql-tools/git-loader": "^8.0.32", "@graphql-tools/github-loader": "^9.0.6", "@graphql-tools/graphql-file-loader": "^8.1.11", "@graphql-tools/json-file-loader": "^8.0.26", "@graphql-tools/load": "^8.1.8", "@graphql-tools/url-loader": "^9.0.6", "@graphql-tools/merge": "^9.0.6", "@graphql-tools/utils": "^11.0.0", "@inquirer/prompts": "^7.8.2", "@whatwg-node/fetch": "^0.10.0", "chalk": "^4.1.0", "cosmiconfig": "^9.0.0", "debounce": "^2.0.0", "detect-indent": "^6.0.0", "graphql-config": "^5.1.6", "is-glob": "^4.0.1", "jiti": "^2.3.0", "json-to-pretty-yaml": "^1.2.2", "listr2": "^9.0.0", "log-symbols": "^4.0.0", "micromatch": "^4.0.5", "shell-quote": "^1.7.3", "string-env-interpolation": "^1.0.1", "ts-log": "^2.2.3", "tslib": "^2.4.0", "yaml": "^2.3.1", "yargs": "^17.0.0" }, "devDependencies": { "@parcel/watcher": "^2.1.0", "@types/is-glob": "4.0.4", "@types/js-yaml": "4.0.9", "@types/micromatch": "^4.0.2", "@types/shell-quote": "1.7.5", "bdd-stdin": "0.2.0", "change-case-all": "1.0.15", "js-yaml": "4.1.0", "make-dir": "4.0.0", "prettier": "2.8.8" }, "peerDependencies": { "@parcel/watcher": "^2.1.0", "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "peerDependenciesMeta": { "@parcel/watcher": { "optional": true } }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/graphql-codegen-cli/src/bin.ts ================================================ #!/usr/bin/env node import { runCli } from './cli.js'; import { cliError } from './utils/cli-error.js'; const [, , cmd] = process.argv; runCli(cmd) .then(returnCode => { process.exit(returnCode); }) .catch(error => { cliError(error); }); ================================================ FILE: packages/graphql-codegen-cli/src/cli.ts ================================================ import { createContext } from './config.js'; import { generate } from './generate-and-save.js'; import { lifecycleHooks } from './hooks.js'; import { init } from './init/index.js'; export async function runCli(cmd: string): Promise { await ensureGraphQlPackage(); if (cmd === 'init') { await init(); return 0; } const context = await createContext(); try { await generate(context); if (context.checkMode && context.checkModeStaleFiles.length > 0) { // eslint-disable-next-line no-console console.log( `The following stale files were detected:\n${context.checkModeStaleFiles.map(file => ` - ${file}\n`)}` ); return 1; } return 0; } catch (error) { await lifecycleHooks(context.getConfig().hooks).onError(error.toString()); return 1; } } export async function ensureGraphQlPackage() { try { await import('graphql'); } catch { throw new Error( `Unable to load "graphql" package. Please make sure to install "graphql" as a dependency! \n To install "graphql", run: yarn add graphql Or, with NPM: npm install --save graphql` ); } } ================================================ FILE: packages/graphql-codegen-cli/src/codegen.ts ================================================ import fs from 'fs'; import { createRequire } from 'module'; import { cpus } from 'os'; import path from 'path'; import { codegen } from '@graphql-codegen/core'; import { CodegenPlugin, getCachedDocumentNodeFromSchema, normalizeConfig, normalizeImportExtension, normalizeInstanceOrArray, normalizeOutputParam, Types, } from '@graphql-codegen/plugin-helpers'; import { NoTypeDefinitionsFound } from '@graphql-tools/load'; import { buildASTSchema, DocumentNode, GraphQLError, GraphQLSchema, isSchema } from 'graphql'; import { mergeTypeDefs } from '@graphql-tools/merge'; import { Listr, ListrTask } from 'listr2'; import { CodegenContext, ensureContext } from './config.js'; import { getPluginByName } from './plugins.js'; import { getPresetByName } from './presets.js'; import { debugLog, printLogs } from './utils/debugging.js'; import { getDocumentTransform } from './documentTransforms.js'; /** * Poor mans ESM detection. * Looking at this and you have a better method? * Send a PR. */ const isESMModule = (typeof __dirname === 'string') === false; const makeDefaultLoader = (from: string) => { if (fs.statSync(from).isDirectory()) { from = path.join(from, '__fake.js'); } const relativeRequire = createRequire(from); return async (mod: string) => { return import( isESMModule ? /** * For ESM we currently have no "resolve path" solution * as import.meta is unavailable in a CommonJS context * and furthermore unavailable in stable Node.js. **/ mod : relativeRequire.resolve(mod) ); }; }; type Ctx = { errors: Error[] }; function createCache(): (namespace: string, key: string, factory: () => Promise) => Promise { const cache = new Map>(); return function ensure(namespace: string, key: string, factory: () => Promise): Promise { const cacheKey = `${namespace}:${key}`; const cachedValue = cache.get(cacheKey); if (cachedValue) { return cachedValue as Promise; } const value = factory(); cache.set(cacheKey, value); return value; }; } export async function executeCodegen( input: CodegenContext | Types.Config ): Promise<{ result: Types.FileOutput[]; error: Error | null }> { const context = ensureContext(input); const config = context.getConfig(); const pluginContext = context.getPluginContext(); const result: Types.FileOutput[] = []; let rootConfig: { [key: string]: any } = {}; let rootSchemas: Types.Schema[]; let rootDocuments: Types.OperationDocument[]; const generates: { [filename: string]: Types.ConfiguredOutput } = {}; const cache = createCache(); // We need a simple string to uniqually identify the provided GraphQLSchema objects for the above cache. // Because JavaScript does not provide access to its internal object ids, we need a workaround. // Below is a common way to get unique ids for objects in JavaScript, // by using a WeakMap and autoincrementing the id. const jsObjectIds = new WeakMap(); let jsObjectIdCounter = 0; function getJsObjectId(schema: GraphQLSchema): number { if (!jsObjectIds.has(schema)) { jsObjectIds.set(schema, jsObjectIdCounter++); } return jsObjectIds.get(schema)!; } function wrapTask(task: () => void | Promise, source: string, taskName: string, ctx: Ctx) { return () => context.profiler.run(async () => { try { await Promise.resolve().then(() => task()); } catch (error) { if (source && !(error instanceof GraphQLError)) { error.source = source; } ctx.errors.push(error); throw error; } }, taskName); } async function normalize() { /* Load Require extensions */ const requireExtensions = normalizeInstanceOrArray(config.require); const loader = makeDefaultLoader(context.cwd); for (const mod of requireExtensions) { await loader(mod); } /* Root plugin config */ rootConfig = config.config || {}; /* Normalize root "schema" field */ rootSchemas = normalizeInstanceOrArray(config.schema); /* Normalize root "documents" field */ rootDocuments = normalizeInstanceOrArray(config.documents); /* Normalize "generators" field */ const generateKeys = Object.keys(config.generates || {}); if (generateKeys.length === 0) { throw new Error( `Invalid Codegen Configuration! \n Please make sure that your codegen config file contains the "generates" field, with a specification for the plugins you need. It should looks like that: schema: - my-schema.graphql generates: my-file.ts: - plugin1 - plugin2 - plugin3` ); } for (const filename of generateKeys) { const output = (generates[filename] = normalizeOutputParam(config.generates[filename])); if (!output.preset && (!output.plugins || output.plugins.length === 0)) { throw new Error( `Invalid Codegen Configuration! \n Please make sure that your codegen config file has defined plugins list for output "${filename}". It should looks like that: schema: - my-schema.graphql generates: my-file.ts: - plugin1 - plugin2 - plugin3 ` ); } } if ( rootSchemas.length === 0 && Object.keys(generates).some( filename => !generates[filename].schema || (Array.isArray(generates[filename].schema === 'object') && (generates[filename].schema as unknown as any[]).length === 0) ) ) { throw new Error( `Invalid Codegen Configuration! \n Please make sure that your codegen config file contains either the "schema" field or every generated file has its own "schema" field. It should looks like that: schema: - my-schema.graphql or: generates: path/to/output: schema: my-schema.graphql ` ); } } const isTest = process.env.NODE_ENV === 'test'; const tasks = new Listr( [ { title: 'Parse Configuration', task: () => normalize(), }, { title: 'Generate outputs', task: (ctx, task) => { const generateTasks: ListrTask[] = Object.keys(generates).map(filename => { const outputConfig = generates[filename]; const hasPreset = !!outputConfig.preset; const title = `Generate to ${filename}`; return { title, async task(_, subTask) { let outputSchemaAst: GraphQLSchema; let outputSchema: DocumentNode; const outputFileTemplateConfig = outputConfig.config || {}; let outputDocuments: Types.DocumentFile[] = []; const outputSpecificSchemas = normalizeInstanceOrArray(outputConfig.schema); let outputSpecificDocuments = normalizeInstanceOrArray(outputConfig.documents); const preset: Types.OutputPreset | null = hasPreset ? typeof outputConfig.preset === 'string' ? await getPresetByName(outputConfig.preset, makeDefaultLoader(context.cwd)) : outputConfig.preset : null; if (preset?.prepareDocuments) { outputSpecificDocuments = await preset.prepareDocuments(filename, outputSpecificDocuments); } return subTask.newListr( [ { title: 'Load GraphQL schemas', task: wrapTask( async () => { debugLog(`[CLI] Loading Schemas`); const schemaPointerMap: any = {}; const parsedSchemas: GraphQLSchema[] = []; const allSchemaDenormalizedPointers = [...rootSchemas, ...outputSpecificSchemas]; for (const denormalizedPtr of allSchemaDenormalizedPointers) { if (isSchema(denormalizedPtr)) { parsedSchemas.push(denormalizedPtr); } else if (typeof denormalizedPtr === 'string') { schemaPointerMap[denormalizedPtr] = {}; } else if (typeof denormalizedPtr === 'object') { Object.assign(schemaPointerMap, denormalizedPtr); } } const hash = JSON.stringify(schemaPointerMap) + parsedSchemas.map(getJsObjectId).join(','); const result = await cache('schema', hash, async () => { // collect parsed schemas const schemasToMerge: GraphQLSchema[] = [...parsedSchemas]; // collect schemas, provided by pointers if (Object.keys(schemaPointerMap).length) { schemasToMerge.push(await context.loadSchema(schemaPointerMap)); } // merge all collected schemas into one const outputSchemaAst = schemasToMerge.length === 1 ? schemasToMerge[0] : buildASTSchema(mergeTypeDefs(schemasToMerge)); const outputSchema = getCachedDocumentNodeFromSchema(outputSchemaAst); return { outputSchemaAst, outputSchema, }; }); outputSchemaAst = result.outputSchemaAst; outputSchema = result.outputSchema; }, filename, `Load GraphQL schemas: ${filename}`, ctx ), }, { title: 'Load GraphQL documents', task: wrapTask( async () => { debugLog(`[CLI] Loading Documents`); const documentPointerMap: any = {}; const allDocumentsDenormalizedPointers = [...rootDocuments, ...outputSpecificDocuments]; for (const denormalizedPtr of allDocumentsDenormalizedPointers) { if (typeof denormalizedPtr === 'string') { documentPointerMap[denormalizedPtr] = {}; } else if (typeof denormalizedPtr === 'object') { Object.assign(documentPointerMap, denormalizedPtr); } } const hash = JSON.stringify(documentPointerMap); const result = await cache('documents', hash, async () => { try { const documents = await context.loadDocuments(documentPointerMap); return { documents, }; } catch (error) { if (error instanceof NoTypeDefinitionsFound && config.ignoreNoDocuments) { return { documents: [], }; } throw error; } }); outputDocuments = result.documents; }, filename, `Load GraphQL documents: ${filename}`, ctx ), }, { title: 'Generate', task: wrapTask( async () => { debugLog(`[CLI] Generating output`); const normalizedPluginsArray = normalizeConfig(outputConfig.plugins); const pluginLoader = config.pluginLoader || makeDefaultLoader(context.cwd); const pluginPackages = await Promise.all( normalizedPluginsArray.map(plugin => getPluginByName(Object.keys(plugin)[0], pluginLoader)) ); const pluginMap: { [name: string]: CodegenPlugin; } = Object.fromEntries( pluginPackages.map((pkg, i) => { const plugin = normalizedPluginsArray[i]; const name = Object.keys(plugin)[0]; return [name, pkg]; }) ); const rawMergedConfig = { ...rootConfig, emitLegacyCommonJSImports: config.emitLegacyCommonJSImports, importExtension: config.importExtension, ...(typeof outputFileTemplateConfig === 'string' ? { value: outputFileTemplateConfig } : outputFileTemplateConfig), }; const importExtension = normalizeImportExtension({ emitLegacyCommonJSImports: rawMergedConfig.emitLegacyCommonJSImports, importExtension: rawMergedConfig.importExtension, }); const mergedConfig = { ...rawMergedConfig, importExtension, emitLegacyCommonJSImports: rawMergedConfig.emitLegacyCommonJSImports ?? true, }; const documentTransforms = Array.isArray(outputConfig.documentTransforms) ? await Promise.all( outputConfig.documentTransforms.map(async (config, index) => { return await getDocumentTransform( config, makeDefaultLoader(context.cwd), `the element at index ${index} of the documentTransforms` ); }) ) : []; const outputs: Types.GenerateOptions[] = preset ? await context.profiler.run( async () => preset.buildGeneratesSection({ baseOutputDir: filename, presetConfig: outputConfig.presetConfig || {}, plugins: normalizedPluginsArray, schema: outputSchema, schemaAst: outputSchemaAst, documents: outputDocuments, config: mergedConfig, pluginMap, pluginContext, profiler: context.profiler, documentTransforms, }), `Build Generates Section: ${filename}` ) : [ { filename, plugins: normalizedPluginsArray, schema: outputSchema, schemaAst: outputSchemaAst, documents: outputDocuments, config: mergedConfig, pluginMap, pluginContext, profiler: context.profiler, documentTransforms, }, ]; const process = async (outputArgs: Types.GenerateOptions) => { const output = await codegen({ ...outputArgs, importExtension, emitLegacyCommonJSImports: rawMergedConfig.emitLegacyCommonJSImports ?? true, cache, }); result.push({ filename: outputArgs.filename, content: output, hooks: outputConfig.hooks || {}, }); }; await context.profiler.run(() => Promise.all(outputs.map(process)), `Codegen: ${filename}`); }, filename, `Generate: ${filename}`, ctx ), }, ], { /** * For each `generates` task, we must do the following in order: * * 1. Load schema * 2. Load documents * 3. Generate based on the schema + documents * * This way, the 3rd step has all the schema and documents loaded in previous steps to work correctly */ exitOnError: true, concurrent: false, } ); }, // It doesn't stop when one of tasks failed, to finish at least some of outputs exitOnError: false, }; }); return task.newListr(generateTasks, { concurrent: cpus().length || 1 }); }, }, ], { rendererOptions: { clearOutput: false, collapseSubtasks: true, formatOutput: 'wrap', removeEmptyLines: false, }, renderer: config.verbose ? 'verbose' : 'default', ctx: { errors: [] }, silentRendererCondition: isTest || config.silent, exitOnError: true, } ); // All the errors throw in `listr2` are collected in context // Running tasks doesn't throw anything const executedContext = await tasks.run(); if (config.debug) { // if we have debug logs, make sure to print them before throwing the errors printLogs(); } let error: Error | null = null; if (executedContext.errors.length > 0) { const errors = executedContext.errors.map(subErr => subErr.message || subErr.toString()); error = new AggregateError(executedContext.errors, String(errors.join('\n\n'))); // Best-effort to all stack traces for debugging error.stack = `${error.stack}\n\n${executedContext.errors.map(subErr => subErr.stack).join('\n\n')}`; } return { result, error }; } ================================================ FILE: packages/graphql-codegen-cli/src/config.ts ================================================ import { createHash, BinaryToTextEncoding } from 'crypto'; import { promises } from 'fs'; import { createRequire } from 'module'; import { resolve } from 'path'; import { createNoopProfiler, createProfiler, getCachedDocumentNodeFromSchema, Profiler, Types, } from '@graphql-codegen/plugin-helpers'; import { cosmiconfig, defaultLoaders } from 'cosmiconfig'; import { createJiti } from 'jiti'; import { GraphQLSchema, GraphQLSchemaExtensions, print } from 'graphql'; import { GraphQLConfig } from 'graphql-config'; import { env } from 'string-env-interpolation'; import yaml from 'yaml'; import yargs from 'yargs'; import { findAndLoadGraphQLConfig } from './graphql-config.js'; import { defaultDocumentsLoadOptions, defaultSchemaLoadOptions, loadDocuments, loadSchema } from './load.js'; const { lstat } = promises; export type CodegenConfig = Types.Config; export type YamlCliFlags = { config: string; watch: boolean | string | string[]; require: string[]; overwrite: boolean; project: string; silent: boolean; errorsOnly: boolean; profile: boolean; check?: boolean; verbose?: boolean; debug?: boolean; ignoreNoDocuments?: boolean; emitLegacyCommonJSImports?: boolean; importExtension?: '' | `.${string}`; }; export function generateSearchPlaces(moduleName: string) { const extensions = ['json', 'yaml', 'yml', 'js', 'ts', 'config.js']; // gives codegen.json... const regular = extensions.map(ext => `${moduleName}.${ext}`); // gives .codegenrc.json... but no .codegenrc.config.js const dot = extensions.filter(ext => ext !== 'config.js').map(ext => `.${moduleName}rc.${ext}`); return [...regular.concat(dot), 'package.json']; } function customLoader(ext: 'json' | 'yaml' | 'js' | 'ts' | 'mts' | 'cts'): CodegenConfigLoader { return async function loader(filepath, content) { if (typeof process !== 'undefined' && 'env' in process) { content = env(content); } if (ext === 'json') { return defaultLoaders['.json'](filepath, content); } if (ext === 'yaml') { try { const result = yaml.parse(content, { prettyErrors: true, merge: true }); return result; } catch (error) { error.message = `YAML Error in ${filepath}:\n${error.message}`; throw error; } } if (ext === 'js') { return defaultLoaders['.js'](filepath, content); } if (ext === 'ts') { const jitiLoader = createJiti(''); return jitiLoader.import(filepath, { default: true }); } }; } export type CodegenConfigLoader = (filepath: string, content: string) => Promise | Types.Config; export interface LoadCodegenConfigOptions { /** * The path to the config file or directory contains the config file. * @default process.cwd() */ configFilePath?: string; /** * The name of the config file * @default codegen */ moduleName?: string; /** * Additional search paths for the config file you want to check */ searchPlaces?: string[]; /** * @default codegen */ packageProp?: string; /** * Overrides or extends the loaders for specific file extensions */ loaders?: Record; } export interface LoadCodegenConfigResult { filepath: string; config: Types.Config; isEmpty?: boolean; } export async function loadCodegenConfig({ configFilePath, moduleName, searchPlaces: additionalSearchPlaces, packageProp, loaders: customLoaders, }: LoadCodegenConfigOptions): Promise { configFilePath ||= process.cwd(); moduleName ||= 'codegen'; packageProp ||= moduleName; const cosmi = cosmiconfig(moduleName, { searchPlaces: generateSearchPlaces(moduleName).concat(additionalSearchPlaces || []), packageProp, loaders: { '.json': customLoader('json'), '.yaml': customLoader('yaml'), '.yml': customLoader('yaml'), '.js': customLoader('js'), '.ts': customLoader('ts'), '.mts': customLoader('ts'), '.cts': customLoader('ts'), noExt: customLoader('yaml'), ...customLoaders, }, }); const pathStats = await lstat(configFilePath); return pathStats.isDirectory() ? cosmi.search(configFilePath) : cosmi.load(configFilePath); } export async function loadContext(configFilePath?: string): Promise | never { const graphqlConfig = await findAndLoadGraphQLConfig(configFilePath); if (graphqlConfig) { return new CodegenContext({ graphqlConfig }); } const result = await loadCodegenConfig({ configFilePath }); if (!result) { if (configFilePath) { throw new Error( ` Config ${configFilePath} does not exist. $ graphql-codegen --config ${configFilePath} Please make sure the --config points to a correct file. ` ); } throw new Error( `Unable to find Codegen config file! \n Please make sure that you have a configuration file under the current directory! ` ); } if (result.isEmpty) { throw new Error( `Found Codegen config file but it was empty! \n Please make sure that you have a valid configuration file under the current directory! ` ); } return new CodegenContext({ filepath: result.filepath, config: result.config as Types.Config, }); } function getCustomConfigPath(cliFlags: YamlCliFlags): string | null | never { const configFile = cliFlags.config; return configFile ? resolve(process.cwd(), configFile) : null; } export function buildOptions() { return { c: { alias: 'config', type: 'string' as const, describe: 'Path to GraphQL codegen YAML config file, defaults to "codegen.yml" on the current directory', }, w: { alias: 'watch', describe: 'Watch for changes and execute generation automatically. You can also specify a glob expression for custom watch list.', coerce(watch: any) { if (watch === 'false') { return false; } if (typeof watch === 'string' || Array.isArray(watch)) { return watch; } return !!watch; }, }, r: { alias: 'require', describe: 'Loads specific require.extensions before running the codegen and reading the configuration', type: 'array' as const, default: [], }, o: { alias: 'overwrite', describe: 'Overwrites existing files', type: 'boolean' as const, }, s: { alias: 'silent', describe: 'Suppresses printing errors', type: 'boolean' as const, }, e: { alias: 'errors-only', describe: 'Only print errors', type: 'boolean' as const, }, profile: { describe: 'Use profiler to measure performance', type: 'boolean' as const, }, p: { alias: 'project', describe: 'Name of a project in GraphQL Config', type: 'string' as const, }, v: { alias: 'verbose', describe: 'output more detailed information about performed tasks', type: 'boolean' as const, default: false, }, d: { alias: 'debug', describe: 'Print debug logs to stdout', type: 'boolean' as const, default: false, }, 'emit-legacy-common-js-imports': { describe: 'Emit legacy CommonJS imports (deprecated, use import-extension instead)', type: 'boolean' as const, }, 'import-extension': { describe: 'Extension to append to imports (e.g., .js, .mjs, or empty string for no extension)', type: 'string' as const, }, 'ignore-no-documents': { describe: 'Suppress errors for no documents', type: 'boolean' as const, }, }; } export function parseArgv(argv = process.argv): YamlCliFlags { return yargs(argv).options(buildOptions()).parse(argv) as any; } export async function createContext(cliFlags: YamlCliFlags = parseArgv(process.argv)): Promise { if (cliFlags.require && cliFlags.require.length > 0) { const relativeRequire = createRequire(process.cwd()); await Promise.all( cliFlags.require.map( mod => import( relativeRequire.resolve(mod, { paths: [process.cwd()], }) ) ) ); } const customConfigPath = getCustomConfigPath(cliFlags); const context = await loadContext(customConfigPath); updateContextWithCliFlags(context, cliFlags); return context; } export function updateContextWithCliFlags(context: CodegenContext, cliFlags: YamlCliFlags) { const config: Partial = { configFilePath: context.filepath, }; if (cliFlags.watch !== undefined) { config.watch = cliFlags.watch; } if (cliFlags.overwrite === true) { config.overwrite = cliFlags.overwrite; } if (cliFlags.silent === true) { config.silent = cliFlags.silent; } if (cliFlags.verbose === true || process.env.VERBOSE) { config.verbose = true; } if (cliFlags.debug === true || process.env.DEBUG) { config.debug = true; } if (cliFlags.errorsOnly === true) { config.errorsOnly = cliFlags.errorsOnly; } if (cliFlags['ignore-no-documents'] !== undefined) { // for some reason parsed value is `'false'` string so this ensure it always is a boolean. config.ignoreNoDocuments = cliFlags['ignore-no-documents'] === true; } if (cliFlags['emit-legacy-common-js-imports'] !== undefined) { // for some reason parsed value is `'false'` string so this ensure it always is a boolean. config.emitLegacyCommonJSImports = cliFlags['emit-legacy-common-js-imports'] === true; } if (cliFlags['import-extension'] !== undefined) { config.importExtension = cliFlags['import-extension']; } if (cliFlags.project) { context.useProject(cliFlags.project); } if (cliFlags.profile === true) { context.useProfiler(); } if (cliFlags.check === true) { context.enableCheckMode(); } context.updateConfig(config); } export class CodegenContext { private _config: Types.Config; private _graphqlConfig?: GraphQLConfig; private config: Types.Config; private _project?: string; private _checkMode = false; private _pluginContext: { [key: string]: any } = {}; cwd: string; filepath: string; profiler: Profiler; profilerOutput?: string; checkModeStaleFiles = []; constructor({ config, graphqlConfig, filepath, }: { config?: Types.Config; graphqlConfig?: GraphQLConfig; filepath?: string; }) { this._config = config; this._graphqlConfig = graphqlConfig; this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath; this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd(); this.profiler = createNoopProfiler(); } useProject(name?: string) { this._project = name; } getConfig(extraConfig?: T): T & Types.Config { if (!this.config) { if (this._graphqlConfig) { const project = this._graphqlConfig.getProject(this._project); this.config = { ...project.extension('codegen'), schema: project.schema, documents: project.documents, pluginContext: this._pluginContext, }; } else { this.config = { ...this._config, pluginContext: this._pluginContext }; } } return { ...extraConfig, ...this.config, }; } updateConfig(config: Partial): void { this.config = { ...this.getConfig(), ...config, }; } enableCheckMode() { this._checkMode = true; } get checkMode() { return this._checkMode; } useProfiler() { this.profiler = createProfiler(); const now = new Date(); // 2011-10-05T14:48:00.000Z const datetime = now.toISOString().split('.')[0]; // 2011-10-05T14:48:00 const datetimeNormalized = datetime.replace(/-|:/g, ''); // 20111005T144800 this.profilerOutput = `codegen-${datetimeNormalized}.json`; } getPluginContext(): { [key: string]: any } { return this._pluginContext; } async loadSchema(pointer: Types.Schema | Types.Schema[]): Promise { const config = this.getConfig(defaultSchemaLoadOptions); if (this._graphqlConfig) { // TODO: SchemaWithLoader won't work here return addHashToSchema( this._graphqlConfig .getProject(this._project) .loadSchema(pointer, 'GraphQLSchema', { ...config, ...config.config }) ); } return addHashToSchema(loadSchema(pointer, config)); } async loadDocuments(pointer: Types.OperationDocument[]): Promise { const config = this.getConfig(defaultDocumentsLoadOptions); if (this._graphqlConfig) { // TODO: pointer won't work here return addHashToDocumentFiles( this._graphqlConfig.getProject(this._project).loadDocuments(pointer, { ...config, ...config.config }) ); } return addHashToDocumentFiles(loadDocuments(pointer, config)); } } export function ensureContext(input: CodegenContext | Types.Config): CodegenContext { return input instanceof CodegenContext ? input : new CodegenContext({ config: input }); } function hashContent(content: string, encoding: BinaryToTextEncoding = 'hex'): string { return createHash('sha256').update(content).digest(encoding); } function hashSchema(schema: GraphQLSchema): string { return hashContent(print(getCachedDocumentNodeFromSchema(schema))); } function addHashToSchema(schemaPromise: Promise): Promise { return schemaPromise.then(schema => { // It's consumed later on. The general purpose is to use it for caching. if (!schema.extensions) { (schema.extensions as unknown as GraphQLSchemaExtensions) = {}; } (schema.extensions as unknown as GraphQLSchemaExtensions)['hash'] = hashSchema(schema); return schema; }); } function hashDocument(doc: Types.DocumentFile) { if (doc.rawSDL) { return hashContent(doc.rawSDL); } if (doc.document) { return hashContent(print(doc.document)); } return null; } function addHashToDocumentFiles(documentFilesPromise: Promise): Promise { return documentFilesPromise.then(documentFiles => documentFiles.map(doc => { doc.hash = hashDocument(doc); return doc; }) ); } ================================================ FILE: packages/graphql-codegen-cli/src/declarations.d.ts ================================================ declare module 'is-valid-path'; declare module 'listr-update-renderer'; declare module 'indent-string'; declare module 'json-to-pretty-yaml'; declare module 'bdd-stdin'; ================================================ FILE: packages/graphql-codegen-cli/src/documentTransforms.ts ================================================ import { resolve } from 'path'; import { Types } from '@graphql-codegen/plugin-helpers'; export async function getDocumentTransform( documentTransform: Types.OutputDocumentTransform, loader: Types.PackageLoaderFn, defaultName: string ): Promise { if (typeof documentTransform === 'string') { const transformObject = await getDocumentTransformByName(documentTransform, loader); return { name: documentTransform, transformObject }; } if (isTransformObject(documentTransform)) { return { name: defaultName, transformObject: documentTransform }; } if (isTransformFileConfig(documentTransform)) { const name = Object.keys(documentTransform)[0]; const transformObject = await getDocumentTransformByName(name, loader); return { name, transformObject, config: Object.values(documentTransform)[0] }; } throw new Error( ` An unknown format document transform: '${defaultName}'. ` ); } function isTransformObject(config: Types.OutputDocumentTransform): config is Types.DocumentTransformObject { return typeof config === 'object' && config.transform && typeof config.transform === 'function'; } function isTransformFileConfig(config: Types.OutputDocumentTransform): config is Types.DocumentTransformFileConfig { const keys = Object.keys(config); return keys.length === 1 && typeof keys[0] === 'string'; } export async function getDocumentTransformByName( name: string, loader: Types.PackageLoaderFn ): Promise { const possibleNames = [ `@graphql-codegen/${name}`, `@graphql-codegen/${name}-document-transform`, name, resolve(process.cwd(), name), ]; const possibleModules = possibleNames.concat(resolve(process.cwd(), name)); for (const moduleName of possibleModules) { try { return await loader(moduleName); } catch (err) { if (err.code !== 'MODULE_NOT_FOUND' && err.code !== 'ERR_MODULE_NOT_FOUND') { throw new Error( ` Unable to load document transform matching '${name}'. Reason: ${err.message} ` ); } } } const possibleNamesMsg = possibleNames .map(name => ` - ${name} `.trimEnd() ) .join(''); throw new Error( ` Unable to find document transform matching '${name}' Install one of the following packages: ${possibleNamesMsg} ` ); } ================================================ FILE: packages/graphql-codegen-cli/src/generate-and-save.ts ================================================ import { createHash } from 'crypto'; import { dirname, isAbsolute, join } from 'path'; import logSymbols from 'log-symbols'; import { Types } from '@graphql-codegen/plugin-helpers'; import { executeCodegen } from './codegen.js'; import { CodegenContext, ensureContext } from './config.js'; import { lifecycleHooks } from './hooks.js'; import { debugLog } from './utils/debugging.js'; import { mkdirp, readFile, unlinkFile, writeFile } from './utils/file-system.js'; import { createWatcher } from './utils/watcher.js'; import { getLogger } from './utils/logger.js'; const hash = (content: string): string => createHash('sha1').update(content).digest('base64'); export async function generate( input: CodegenContext | (Types.Config & { cwd?: string }), saveToFile = true ): Promise< | Types.FileOutput[] /** * When this function runs in watch mode, it'd return an empty promise that doesn't resolve until the watcher exits * FIXME: this effectively makes the result `any`, which loses type-hints */ | any > { const context = ensureContext(input); const config = context.getConfig(); await context.profiler.run(() => lifecycleHooks(config.hooks).afterStart(), 'Lifecycle: afterStart'); let previouslyGeneratedFilenames: string[] = []; function removeStaleFiles(config: Types.Config, generationResult: Types.FileOutput[]) { const filenames = generationResult.map(o => o.filename); // find stale files from previous build which are not present in current build const staleFilenames = previouslyGeneratedFilenames.filter(f => !filenames.includes(f)); for (const filename of staleFilenames) { if (shouldOverwrite(config, filename)) { unlinkFile(filename, err => { const prettyFilename = filename.replace(`${input.cwd || process.cwd()}/`, ''); if (err) { debugLog(`Cannot remove stale file: ${prettyFilename}\n${err}`); } else { debugLog(`Removed stale file: ${prettyFilename}`); } }); } } previouslyGeneratedFilenames = filenames; } const recentOutputHash = new Map(); async function writeOutput(generationResult: Types.FileOutput[]): Promise { if (!saveToFile) { return generationResult; } if (config.watch) { removeStaleFiles(config, generationResult); } await context.profiler.run(async () => { await lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename)); }, 'Lifecycle: beforeAllFileWrite'); await context.profiler.run( () => Promise.all( generationResult.map(async (result: Types.FileOutput) => { const previousHash = recentOutputHash.get(result.filename) || (await hashFile(result.filename)); const exists = previousHash !== null; // Store previous hash to avoid reading from disk again if (previousHash) { recentOutputHash.set(result.filename, previousHash); } if (!shouldOverwrite(config, result.filename) && exists) { return; } let content = result.content || ''; const currentHash = hash(content); if (previousHash && currentHash === previousHash) { debugLog(`Skipping file (${result.filename}) writing due to indentical hash...`); return; } // skip updating file in dry mode if (context.checkMode) { context.checkModeStaleFiles.push(result.filename); return; } if (content.length === 0) { return; } const absolutePath = isAbsolute(result.filename) ? result.filename : join(input.cwd || process.cwd(), result.filename); const basedir = dirname(absolutePath); await mkdirp(basedir); content = await lifecycleHooks(result.hooks).beforeOneFileWrite(absolutePath, content); content = await lifecycleHooks(config.hooks).beforeOneFileWrite(absolutePath, content); if (content !== result.content) { result.content = content; // compare the prettified content with the previous hash // to compare the content with an existing prettified file if (hash(content) === previousHash) { debugLog(`Skipping file (${result.filename}) writing due to indentical hash after prettier...`); // the modified content is NOT stored in recentOutputHash // so a diff can already be detected before executing the hook return; } } await writeFile(absolutePath, result.content); recentOutputHash.set(result.filename, currentHash); await lifecycleHooks(result.hooks).afterOneFileWrite(result.filename); await lifecycleHooks(config.hooks).afterOneFileWrite(result.filename); }) ), 'Write files' ); await context.profiler.run( () => lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: afterAllFileWrite' ); return generationResult; } // watch mode if (config.watch) { return createWatcher(context, writeOutput).runningWatcher; } const { result: outputFiles, error } = await context.profiler.run(() => executeCodegen(context), 'executeCodegen'); if (error) { // If all generation failed, just throw to return non-zero code. if (outputFiles.length === 0) { throw error; } // If partial success, but partial output is not allowed, throw to return non-zero code. if (!config.allowPartialOutputs) { getLogger().error( ` ${logSymbols.error} One or more errors occurred, no files were generated. To allow output on errors, set config.allowPartialOutputs=true` ); throw error; } // If partial success, and partial output is allowed, warn and proceed to write to files. getLogger().warn( ` ${logSymbols.warning} One or more errors occurred, some files were generated. To prevent any output on errors, set config.allowPartialOutputs=false` ); } await context.profiler.run(() => writeOutput(outputFiles), 'writeOutput'); await context.profiler.run(() => lifecycleHooks(config.hooks).beforeDone(), 'Lifecycle: beforeDone'); if (context.profilerOutput) { await writeFile(join(context.cwd, context.profilerOutput), JSON.stringify(context.profiler.collect())); } return outputFiles; } function shouldOverwrite(config: Types.Config, outputPath: string): boolean { const globalValue = config.overwrite === undefined ? true : !!config.overwrite; const outputConfig = config.generates[outputPath]; if (!outputConfig) { debugLog(`Couldn't find a config of ${outputPath}`); return globalValue; } if (isConfiguredOutput(outputConfig) && typeof outputConfig.overwrite === 'boolean') { return outputConfig.overwrite; } return globalValue; } function isConfiguredOutput(output: any): output is Types.ConfiguredOutput { return typeof output.plugins !== 'undefined'; } async function hashFile(filePath: string): Promise { try { return hash(await readFile(filePath)); } catch (err) { if (err && err.code === 'ENOENT') { // return null if file does not exist return null; } // rethrow unexpected errors throw err; } } ================================================ FILE: packages/graphql-codegen-cli/src/graphql-config.ts ================================================ import { ApolloEngineLoader } from '@graphql-tools/apollo-engine-loader'; import { CodeFileLoader } from '@graphql-tools/code-file-loader'; import { GitLoader } from '@graphql-tools/git-loader'; import { GithubLoader } from '@graphql-tools/github-loader'; import { GraphQLConfig, GraphQLExtensionDeclaration, loadConfig } from 'graphql-config'; export const CodegenExtension: GraphQLExtensionDeclaration = (api: any) => { // Schema api.loaders.schema.register( new CodeFileLoader({ pluckConfig: { skipIndent: true, }, }) ); api.loaders.schema.register(new GitLoader()); api.loaders.schema.register(new GithubLoader()); api.loaders.schema.register(new ApolloEngineLoader()); // Documents api.loaders.documents.register( new CodeFileLoader({ pluckConfig: { skipIndent: true, }, }) ); api.loaders.documents.register(new GitLoader()); api.loaders.documents.register(new GithubLoader()); return { name: 'codegen', }; }; export async function findAndLoadGraphQLConfig(filepath?: string): Promise { const config = await loadConfig({ filepath, rootDir: process.cwd(), extensions: [CodegenExtension], throwOnEmpty: false, throwOnMissing: false, }); if (isGraphQLConfig(config)) { return config; } } // Kamil: user might load a config that is not GraphQL Config // so we need to check if it's a regular config or not function isGraphQLConfig(config: GraphQLConfig): config is GraphQLConfig { if (!config) { return false; } try { return config.getDefault().hasExtension('codegen'); } catch {} try { for (const projectName in config.projects) { if (Object.prototype.hasOwnProperty.call(config.projects, projectName)) { const project = config.projects[projectName]; if (project.hasExtension('codegen')) { return true; } } } } catch {} return false; } ================================================ FILE: packages/graphql-codegen-cli/src/hooks.ts ================================================ import { exec } from 'child_process'; import { delimiter, sep } from 'path'; import { Types } from '@graphql-codegen/plugin-helpers'; import { quote } from 'shell-quote'; import { debugLog } from './utils/debugging.js'; const DEFAULT_HOOKS: Types.LifecycleHooksDefinition = { afterStart: [], beforeDone: [], onWatchTriggered: [], onError: [], afterOneFileWrite: [], afterAllFileWrite: [], beforeOneFileWrite: [], beforeAllFileWrite: [], }; function execShellCommand(cmd: string): Promise { return new Promise((resolve, reject) => { exec( cmd, { env: { ...process.env, PATH: `${process.env.PATH}${delimiter}${process.cwd()}${sep}node_modules${sep}.bin`, }, }, (error, stdout, stderr) => { if (error) { reject(error); // eslint-disable-next-line no-console console.error(error); } else { debugLog(stdout || stderr); resolve(stdout || stderr); } } ); }); } async function executeHooks( hookName: string, _scripts: Types.LifeCycleHookValue | Types.LifeCycleAlterHookValue = [], args: string[] = [], initialState?: string ): Promise { debugLog(`Running lifecycle hook "${hookName}" scripts...`); let state = initialState; const scripts = Array.isArray(_scripts) ? _scripts : [_scripts]; const quotedArgs = quote(args); for (const script of scripts) { if (typeof script === 'string') { debugLog(`Running lifecycle hook "${hookName}" script: ${script} with args: ${quotedArgs}...`); await execShellCommand(`${script} ${quotedArgs}`); } else { debugLog(`Running lifecycle hook "${hookName}" script: ${script.name} with args: ${args.join(' ')}...`); const hookArgs = state === undefined ? args : [...args, state]; const hookResult = await script(...hookArgs); if (typeof hookResult === 'string' && typeof state === 'string') { debugLog(`Received new content from lifecycle hook "${hookName}" script: ${script.name}`); state = hookResult; } } } return state; } export const lifecycleHooks = (_hooks: Partial = {}) => { const hooks = { ...DEFAULT_HOOKS, ..._hooks, }; return { afterStart: async (): Promise => { await executeHooks('afterStart', hooks.afterStart); }, onWatchTriggered: async (event: string, path: string): Promise => { await executeHooks('onWatchTriggered', hooks.onWatchTriggered, [event, path]); }, onError: async (error: string): Promise => { await executeHooks('onError', hooks.onError, [error]); }, afterOneFileWrite: async (path: string): Promise => { await executeHooks('afterOneFileWrite', hooks.afterOneFileWrite, [path]); }, afterAllFileWrite: async (paths: string[]): Promise => { await executeHooks('afterAllFileWrite', hooks.afterAllFileWrite, paths); }, beforeOneFileWrite: async (path: string, content: string): Promise => { const result = await executeHooks('beforeOneFileWrite', hooks.beforeOneFileWrite, [path], content); return typeof result === 'string' ? result : content; }, beforeAllFileWrite: async (paths: string[]): Promise => { await executeHooks('beforeAllFileWrite', hooks.beforeAllFileWrite, paths); }, beforeDone: async (): Promise => { await executeHooks('beforeDone', hooks.beforeDone); }, }; }; ================================================ FILE: packages/graphql-codegen-cli/src/index.ts ================================================ export * from './cli.js'; export { executeCodegen } from './codegen.js'; export * from './config.js'; export { CodegenConfig } from './config.js'; export { generate } from './generate-and-save.js'; export * from './graphql-config.js'; export * from './init/index.js'; export * from './utils/cli-error.js'; ================================================ FILE: packages/graphql-codegen-cli/src/init/helpers.ts ================================================ import { readFileSync, writeFileSync } from 'fs'; import { relative, resolve } from 'path'; import generate from '@babel/generator'; import template from '@babel/template'; import * as t from '@babel/types'; import { Types } from '@graphql-codegen/plugin-helpers'; import chalk from 'chalk'; import detectIndent from 'detect-indent'; import { getLatestVersion } from '../utils/get-latest-version.js'; import { Answers, Tags } from './types.js'; function jsObjectToBabelObjectExpression(obj: T): ReturnType { const objExp = t.objectExpression([]); for (const [key, val] of Object.entries(obj)) { if (Array.isArray(val)) { objExp.properties.push( t.objectProperty( /^[a-zA-Z0-9]+$/.test(key) ? t.identifier(key) : t.stringLiteral(key), t.arrayExpression( val.map(v => (typeof v === 'object' ? jsObjectToBabelObjectExpression(v as object) : t.valueToNode(v))) ) ) ); } else { objExp.properties.push( t.objectProperty( /^[a-zA-Z0-9]+$/.test(key) ? t.identifier(key) : t.stringLiteral(key), typeof val === 'object' ? jsObjectToBabelObjectExpression(val as unknown as object) : t.valueToNode(val) ) ); } } return objExp; } // Parses config and writes it to a file export async function writeConfig(answers: Answers, config: Types.Config) { const YAML = await import('json-to-pretty-yaml').then(m => ('default' in m ? m.default : m)); const ext = answers.config.toLocaleLowerCase().split('.')[1]; const fullPath = resolve(process.cwd(), answers.config); const relativePath = relative(process.cwd(), answers.config); let content: string; if (ext === 'ts') { const buildRequire = template.statement(`%%config%%`); const ast = buildRequire({ config: jsObjectToBabelObjectExpression(config), }); content = ` import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = ${generate(ast).code.replace(/\(|\)/g, '')} export default config; `; } else { content = ext === 'json' ? JSON.stringify(config) : YAML.stringify(config); } writeFileSync(fullPath, content, 'utf8'); return { relativePath, fullPath, }; } // Updates package.json (script and plugins as dependencies) export async function writePackage(answers: Answers, configLocation: string) { // script const pkgPath = resolve(process.cwd(), 'package.json'); const pkgContent = readFileSync(pkgPath, 'utf8'); const pkg = JSON.parse(pkgContent); const { indent } = detectIndent(pkgContent); pkg.scripts ||= {}; pkg.scripts[answers.script] = `graphql-codegen --config ${configLocation}`; // plugin pkg.devDependencies ||= {}; await Promise.all( (answers.plugins || []).map(async plugin => { pkg.devDependencies[plugin.package] = await getLatestVersion(plugin.package); }) ); if (answers.introspection) { pkg.devDependencies['@graphql-codegen/introspection'] = await getLatestVersion('@graphql-codegen/introspection'); } pkg.devDependencies['@graphql-codegen/cli'] = await getLatestVersion('@graphql-codegen/cli'); if (answers.targets.includes(Tags.client)) { pkg.devDependencies['@graphql-codegen/client-preset'] = await getLatestVersion('@graphql-codegen/client-preset'); } writeFileSync(pkgPath, JSON.stringify(pkg, null, indent)); } export function bold(str: string) { return chalk.bold(str); } export function grey(str: string) { return chalk.grey(str); } export function italic(str: string) { return chalk.italic(str); } ================================================ FILE: packages/graphql-codegen-cli/src/init/index.ts ================================================ import type { Types } from '@graphql-codegen/plugin-helpers'; import { bold, writeConfig, writePackage } from './helpers.js'; import { getAnswers } from './questions.js'; import { guessTargets } from './targets.js'; import { Tags } from './types.js'; function log(...msgs: string[]) { // eslint-disable-next-line no-console console.log(...msgs); } export async function init() { log(` Welcome to ${bold('GraphQL Code Generator')}! Answer few questions and we will setup everything for you. `); const possibleTargets = await guessTargets(); const answers = await getAnswers(possibleTargets); // define config const config: Types.Config = { overwrite: true, schema: answers.schema, ...(answers.targets.includes(Tags.client) || answers.targets.includes(Tags.angular) || answers.targets.includes(Tags.stencil) ? { documents: answers.documents } : {}), generates: { [answers.output]: { ...(answers.targets.includes(Tags.client) ? { preset: 'client' } : {}), plugins: answers.plugins ? answers.plugins.map(p => p.value) : [], }, }, }; // introspection if (answers.introspection) { addIntrospection(config); } // config file const { relativePath } = await writeConfig(answers, config); log(`Fetching latest versions of selected plugins...`); // write package.json await writePackage(answers, relativePath); // Emit status to the terminal log(` Config file generated at ${bold(relativePath)} ${bold('$ npm install')} To install the plugins. ${bold(`$ npm run ${answers.script}`)} To run GraphQL Code Generator. `); } // adds an introspection to `generates` function addIntrospection(config: Types.Config) { config.generates['./graphql.schema.json'] = { plugins: ['introspection'], }; } ================================================ FILE: packages/graphql-codegen-cli/src/init/plugins.ts ================================================ import { italic } from './helpers.js'; import { PluginOption, Tags } from './types.js'; export const plugins: Array = [ { name: `TypeScript ${italic('(required by other typescript plugins)')}`, package: '@graphql-codegen/typescript', value: 'typescript', pathInRepo: 'typescript/typescript', available: hasTag(Tags.typescript), shouldBeSelected: tags => oneOf(tags, Tags.angular, Tags.stencil) || allOf(tags, Tags.typescript, Tags.react) || noneOf(tags, Tags.flow), defaultExtension: '.ts', }, { name: `TypeScript Operations ${italic('(operations and fragments)')}`, package: '@graphql-codegen/typescript-operations', value: 'typescript-operations', pathInRepo: 'typescript/operations', available: tags => allOf(tags, Tags.client, Tags.typescript) || hasTag(Tags.stencil)(tags), shouldBeSelected: tags => oneOf(tags, Tags.angular, Tags.stencil) || allOf(tags, Tags.typescript, Tags.react), defaultExtension: '.ts', }, { name: `TypeScript Resolvers ${italic('(strongly typed resolve functions)')}`, package: '@graphql-codegen/typescript-resolvers', value: 'typescript-resolvers', pathInRepo: 'typescript/resolvers', available: tags => allOf(tags, Tags.node, Tags.typescript), shouldBeSelected: tags => noneOf(tags, Tags.flow), defaultExtension: '.ts', }, { name: `Flow ${italic('(required by other flow plugins)')}`, package: '@graphql-codegen/flow', value: 'flow', pathInRepo: 'flow/flow', available: hasTag(Tags.flow), shouldBeSelected: tags => noneOf(tags, Tags.typescript), defaultExtension: '.js', }, { name: `Flow Operations ${italic('(operations and fragments)')}`, package: '@graphql-codegen/flow-operations', value: 'flow-operations', pathInRepo: 'flow/operations', available: tags => allOf(tags, Tags.client, Tags.flow), shouldBeSelected: tags => noneOf(tags, Tags.typescript), defaultExtension: '.js', }, { name: `Flow Resolvers ${italic('(strongly typed resolve functions)')}`, package: '@graphql-codegen/flow-resolvers', value: 'flow-resolvers', pathInRepo: 'flow/resolvers', available: tags => allOf(tags, Tags.node, Tags.flow), shouldBeSelected: tags => noneOf(tags, Tags.typescript), defaultExtension: '.js', }, { name: `TypeScript Stencil Apollo ${italic('(typed components)')}`, package: '@graphql-codegen/typescript-stencil-apollo', value: 'typescript-stencil-apollo', pathInRepo: 'typescript/stencil-apollo', available: hasTag(Tags.stencil), shouldBeSelected: () => true, defaultExtension: '.tsx', }, { name: `TypeScript MongoDB ${italic('(typed MongoDB objects)')}`, package: '@graphql-codegen/typescript-mongodb', value: 'typescript-mongodb', pathInRepo: 'typescript/mongodb', available: tags => allOf(tags, Tags.node, Tags.typescript), shouldBeSelected: () => false, defaultExtension: '.ts', }, { name: `TypeScript GraphQL files modules ${italic('(declarations for .graphql files)')}`, package: '@graphql-codegen/typescript-graphql-files-modules', value: 'typescript-graphql-files-modules', pathInRepo: 'typescript/graphql-files-modules', available: tags => allOf(tags, Tags.client, Tags.typescript) || hasTag(Tags.stencil)(tags), shouldBeSelected: () => false, defaultExtension: '.ts', }, { name: `TypeScript GraphQL document nodes ${italic('(embedded GraphQL document)')}`, package: '@graphql-codegen/typescript-document-nodes', value: 'typescript-document-nodes', pathInRepo: 'typescript/document-nodes', available: tags => allOf(tags, Tags.typescript) || hasTag(Tags.stencil)(tags), shouldBeSelected: () => false, defaultExtension: '.ts', }, { name: `Introspection Fragment Matcher ${italic('(for Apollo Client)')}`, package: '@graphql-codegen/fragment-matcher', value: 'fragment-matcher', pathInRepo: 'other/fragment-matcher', available: tags => hasTag(Tags.client)(tags) || hasTag(Tags.angular)(tags) || hasTag(Tags.stencil)(tags), shouldBeSelected: () => false, defaultExtension: '.ts', }, { name: `Urql Introspection ${italic('(for Urql Client)')}`, package: '@graphql-codegen/urql-introspection', value: 'urql-introspection', pathInRepo: 'other/urql-introspection', available: tags => hasTag(Tags.client)(tags) || hasTag(Tags.stencil)(tags), shouldBeSelected: () => false, defaultExtension: '.ts', }, { name: `TypeScript Apollo Angular ${italic('(typed GQL services)')}`, package: '@graphql-codegen/typescript-apollo-angular', value: 'typescript-apollo-angular', pathInRepo: 'typescript/apollo-angular', available: hasTag(Tags.angular), shouldBeSelected: () => true, defaultExtension: '.ts', }, ]; function hasTag(tag: Tags) { return (tags: Tags[]) => tags.includes(tag); } function oneOf(list: T[], ...items: T[]): boolean { return list.some(i => items.includes(i)); } function noneOf(list: T[], ...items: T[]): boolean { return !list.some(i => items.includes(i)); } function allOf(list: T[], ...items: T[]): boolean { return items.every(i => list.includes(i)); } ================================================ FILE: packages/graphql-codegen-cli/src/init/questions.ts ================================================ import { checkbox, input, select, confirm } from '@inquirer/prompts'; import { grey } from './helpers.js'; import { plugins } from './plugins.js'; import { type Answers, type PluginOption, Tags } from './types.js'; export async function getAnswers(possibleTargets: Record): Promise { try { const targetChoices = getApplicationTypeChoices(possibleTargets); const targets = await select({ message: `What type of application are you building?`, choices: targetChoices, default: targetChoices.find(c => c.checked)?.value, }); const schema = await input({ message: `Where is your schema?: ${grey('(path or url)')}`, default: 'http://localhost:4000', // matches Apollo Server's default validate: str => str.length > 0, }); let documents: string | undefined; if (targets.includes(Tags.client) || targets.includes(Tags.angular) || targets.includes(Tags.stencil)) documents = await input({ message: 'Where are your operations and fragments?:', default: getDocumentsDefaultValue(targets), validate: str => str.length > 0, }); let plugins: PluginOption[]; if (!targets.includes(Tags.client)) { plugins = await checkbox({ message: 'Pick plugins:', choices: getPluginChoices(targets), validate: plugins => plugins.length > 0, }); } const output = await input({ message: 'Where to write the output:', default: getOutputDefaultValue({ targets, plugins }), validate: str => str.length > 0, }); const introspection = await confirm({ message: 'Do you want to generate an introspection file?', default: false, }); const config = await input({ message: 'How to name the config file?', default: (() => targets.includes(Tags.client) || targets.includes(Tags.typescript) || targets.includes(Tags.angular) ? 'codegen.ts' : 'codegen.yml')(), validate: str => { const isNotEmpty = str.length > 0; const hasCorrectExtension = ['json', 'yml', 'yaml', 'js', 'ts'].some(ext => str.toLocaleLowerCase().endsWith(`.${ext}`) ); return isNotEmpty && hasCorrectExtension; }, }); const script = await input({ default: 'codegen', message: 'What script in package.json should run the codegen?', validate: (str: string) => str.length > 0, }); return { targets, schema, documents, plugins, output, introspection, config, script, }; } catch (error) { if (error instanceof Error && error.name === 'ExitPromptError') { // This error because user exited using CMD+C, just exit gracefully or else user would see an ugly error message // https://github.com/SBoudrias/Inquirer.js/blob/ee16061a1e3f99a6cc714a3d473f7cd12b06a3f1/packages/prompts/README.md#handling-ctrlc-gracefully process.exit(); } else { throw error; } } } export function getApplicationTypeChoices(possibleTargets: Record) { function withFlowOrTypescript(tags: Tags[]) { if (possibleTargets.TypeScript) { tags.push(Tags.typescript); } else if (possibleTargets.Flow) { tags.push(Tags.flow); } else if (possibleTargets.Node) { tags.push(Tags.typescript, Tags.flow); } return tags; } return [ { name: 'Backend - API or server', key: 'backend', value: withFlowOrTypescript([Tags.node]), checked: possibleTargets.Node, }, { name: 'Application built with Angular', key: 'angular', value: [Tags.angular], checked: possibleTargets.Angular, }, { name: 'Application built with React', key: 'react', value: withFlowOrTypescript([Tags.react, Tags.client]), checked: possibleTargets.React, }, { name: 'Application built with Stencil', key: 'stencil', value: [Tags.stencil, Tags.typescript], checked: possibleTargets.Stencil, }, { name: 'Application built with Vue', key: 'vue', value: [Tags.vue, Tags.client], checked: possibleTargets.Vue, }, { name: 'Application using graphql-request', key: 'graphqlRequest', value: [Tags.graphqlRequest, Tags.client], checked: possibleTargets.graphqlRequest, }, { name: 'Application built with other framework or vanilla JS', key: 'client', value: [Tags.typescript, Tags.flow], checked: possibleTargets.Browser && !possibleTargets.Angular && !possibleTargets.React && !possibleTargets.Stencil, }, ]; } export function getPluginChoices(targets: Tags[]) { return plugins .filter(p => p.available(targets)) .map(p => { return { name: p.name, value: p, checked: p.shouldBeSelected(targets), }; }); } function getOutputDefaultValue({ targets, plugins }: { targets: Tags[]; plugins: PluginOption[] }) { if (targets.includes(Tags.client)) { return 'src/gql/'; } if (plugins.some(plugin => plugin.defaultExtension === '.tsx')) { return 'src/generated/graphql.tsx'; } if (plugins.some(plugin => plugin.defaultExtension === '.ts')) { return 'src/generated/graphql.ts'; } return 'src/generated/graphql.js'; } function getDocumentsDefaultValue(targets: Tags[]): string { if (targets.includes(Tags.vue)) { return 'src/**/*.vue'; } if (targets.includes(Tags.angular)) { return 'src/**/*.ts'; } if (targets.includes(Tags.client)) { return 'src/**/*.tsx'; } return 'src/**/*.graphql'; } ================================================ FILE: packages/graphql-codegen-cli/src/init/targets.ts ================================================ import { readFileSync } from 'fs'; import { resolve } from 'path'; import { Tags } from './types.js'; export async function guessTargets(): Promise> { const pkg = JSON.parse(readFileSync(resolve(process.cwd(), 'package.json'), 'utf8')); const dependencies = Object.keys({ ...pkg.dependencies, ...pkg.devDependencies, }); return { [Tags.angular]: isAngular(dependencies), [Tags.react]: isReact(dependencies), [Tags.stencil]: isStencil(dependencies), [Tags.vue]: isVue(dependencies), [Tags.client]: false, [Tags.node]: false, [Tags.typescript]: isTypescript(dependencies), [Tags.flow]: isFlow(dependencies), [Tags.graphqlRequest]: isGraphqlRequest(dependencies), }; } function isAngular(dependencies: string[]): boolean { return dependencies.includes('@angular/core'); } function isReact(dependencies: string[]): boolean { return dependencies.includes('react'); } function isStencil(dependencies: string[]): boolean { return dependencies.includes('@stencil/core'); } function isVue(dependencies: string[]): boolean { return dependencies.includes('vue') || dependencies.includes('nuxt'); } function isTypescript(dependencies: string[]): boolean { return dependencies.includes('typescript'); } function isFlow(dependencies: string[]): boolean { return dependencies.includes('flow'); } function isGraphqlRequest(dependencies: string[]): boolean { return dependencies.includes('graphql-request'); } ================================================ FILE: packages/graphql-codegen-cli/src/init/types.ts ================================================ export interface PluginOption { name: string; package: string; value: string; pathInRepo: string; available(tags: Tags[]): boolean; shouldBeSelected(tags: Tags[]): boolean; defaultExtension: string; } export interface Answers { targets: Tags[]; config: string; plugins?: PluginOption[]; schema: string; documents?: string; output: string; script: string; introspection: boolean; } export enum Tags { client = 'Browser', node = 'Node', typescript = 'TypeScript', flow = 'Flow', angular = 'Angular', stencil = 'Stencil', react = 'React', vue = 'Vue', graphqlRequest = 'graphqlRequest', } ================================================ FILE: packages/graphql-codegen-cli/src/load.ts ================================================ import { extname, join } from 'path'; import { Types } from '@graphql-codegen/plugin-helpers'; import { ApolloEngineLoader } from '@graphql-tools/apollo-engine-loader'; import { CodeFileLoader } from '@graphql-tools/code-file-loader'; import { GitLoader } from '@graphql-tools/git-loader'; import { GithubLoader } from '@graphql-tools/github-loader'; import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'; import { JsonFileLoader } from '@graphql-tools/json-file-loader'; import { loadDocuments as loadDocumentsToolkit, loadSchema as loadSchemaToolkit, NoTypeDefinitionsFound, UnnormalizedTypeDefPointer, } from '@graphql-tools/load'; import { UrlLoader } from '@graphql-tools/url-loader'; import { GraphQLError, GraphQLSchema } from 'graphql'; export const defaultSchemaLoadOptions = { assumeValidSDL: true, sort: true, convertExtensions: true, includeSources: true, }; export const defaultDocumentsLoadOptions = { sort: true, skipGraphQLImport: true, }; export async function loadSchema( schemaPointers: UnnormalizedTypeDefPointer | UnnormalizedTypeDefPointer[], config: Types.Config ): Promise { try { const loaders = [ new CodeFileLoader(), new GitLoader(), new GithubLoader(), new GraphQLFileLoader(), new JsonFileLoader(), new UrlLoader(), new ApolloEngineLoader(), ]; const schema = await loadSchemaToolkit(schemaPointers, { ...defaultSchemaLoadOptions, loaders, ...config, ...config.config, }); return schema; } catch (e) { throw new Error( [ `Failed to load schema from ${Object.keys(schemaPointers).join(',')}:`, printError(e), '\nGraphQL Code Generator supports:', '\n- ES Modules and CommonJS exports (export as default or named export "schema")', '- Introspection JSON File', '- URL of GraphQL endpoint', '- Multiple files with type definitions (glob expression)', '- String in config file', '\nTry to use one of above options and run codegen again.\n', ].join('\n') ); } } export async function loadDocuments( documentPointers: UnnormalizedTypeDefPointer | UnnormalizedTypeDefPointer[], config: Types.Config ): Promise { const loaders = [ new CodeFileLoader({ pluckConfig: { skipIndent: true, }, }), new GitLoader(), new GithubLoader(), new GraphQLFileLoader(), ]; const ignore: Array = []; for (const generatePath of Object.keys(config.generates)) { if (extname(generatePath) === '') { // we omit paths that don't resolve to a specific file continue; } ignore.push(join(process.cwd(), generatePath)); } try { const loadedFromToolkit = await loadDocumentsToolkit(documentPointers, { ...defaultDocumentsLoadOptions, ignore, loaders, ...config, ...config.config, }); return loadedFromToolkit; } catch (error) { // NoTypeDefinitionsFound from `@graphql-tools/load` already has a message with pointer, so we can just rethrow the error if (error instanceof NoTypeDefinitionsFound) { throw error; } // For other errors, we need to add an error message with documentPointers, so it's better for DevX throw new Error( [`Failed to load documents from ${Object.keys(documentPointers).join(',')}:`, printError(error)].join('\n') ); } } const printError = (error: any) => { if (error instanceof GraphQLError) { return String(error); } return [String(error.message || error), String(error.stack)].join('\n'); }; ================================================ FILE: packages/graphql-codegen-cli/src/plugins.ts ================================================ import { resolve } from 'path'; import { CodegenPlugin, Types } from '@graphql-codegen/plugin-helpers'; export async function getPluginByName( name: string, pluginLoader: Types.PackageLoaderFn ): Promise { const possibleNames = [ `@graphql-codegen/${name}`, `@graphql-codegen/${name}-template`, `@graphql-codegen/${name}-plugin`, `graphql-codegen-${name}`, `graphql-codegen-${name}-template`, `graphql-codegen-${name}-plugin`, `codegen-${name}`, `codegen-${name}-template`, name, ]; const possibleModules = possibleNames.concat(resolve(process.cwd(), name)); for (const moduleName of possibleModules) { try { return await pluginLoader(moduleName); } catch (err) { if (err.code !== 'MODULE_NOT_FOUND' && err.code !== 'ERR_MODULE_NOT_FOUND') { throw new Error( ` Unable to load template plugin matching '${name}'. Reason: ${err.message} ` ); } } } const possibleNamesMsg = possibleNames .map(name => ` - ${name} `.trimEnd() ) .join(''); throw new Error( ` Unable to find template plugin matching '${name}' Install one of the following packages: ${possibleNamesMsg} ` ); } ================================================ FILE: packages/graphql-codegen-cli/src/presets.ts ================================================ import { resolve } from 'path'; import { Types } from '@graphql-codegen/plugin-helpers'; export async function getPresetByName( name: string, loader: Types.PackageLoaderFn<{ preset?: Types.OutputPreset; default?: Types.OutputPreset }> ): Promise { const possibleNames = [ `@graphql-codegen/${name}`, `@graphql-codegen/${name}-preset`, name, resolve(process.cwd(), name), ]; for (const moduleName of possibleNames) { try { const loaded = await loader(moduleName); if (loaded?.preset) { return loaded.preset; } if (loaded?.default) { return loaded.default; } return loaded as Types.OutputPreset; } catch (err) { if ( /** CJS Error code */ err.code !== 'MODULE_NOT_FOUND' && /** ESM Error code */ err.code !== 'ERR_MODULE_NOT_FOUND' ) { throw new Error( `Unable to load preset matching ${name} Unable to load preset matching '${name}'. Reason: ${err.message} ` ); } } } const possibleNamesMsg = possibleNames .map(name => ` - ${name} `.trimEnd() ) .join(''); throw new Error( `Unable to find preset matching ${name} Unable to find preset matching '${name}' Install one of the following packages: ${possibleNamesMsg} ` ); } ================================================ FILE: packages/graphql-codegen-cli/src/utils/abort-controller-polyfill.ts ================================================ import { EventEmitter } from 'events'; import { debugLog } from './debugging.js'; /** * Node v14 does not have AbortSignal or AbortController, so to safely use it in * another module, you can import it from here. * * Node v14.7+ does have it, but only with flag --experimental-abortcontroller * * We don't actually use AbortController anywhere except in tests, but it * still gets called in watcher.ts, so by polyfilling it we can avoid breaking * existing installations using Node v14 without flag --experimental-abortcontroller, * and we also ensure that tests continue to pass under Node v14 without any new flags. * * This polyfill was adapted (TypeScript-ified) from here: * https://github.com/southpolesteve/node-abort-controller/blob/master/index.js */ class AbortSignalPolyfill implements AbortSignal { eventEmitter: EventEmitter; onabort: EventListener; aborted: boolean; reason: any | undefined; constructor() { this.eventEmitter = new EventEmitter(); this.onabort = null; this.aborted = false; this.reason = undefined; } toString() { return '[object AbortSignal]'; } get [Symbol.toStringTag]() { return 'AbortSignal'; } removeEventListener(name, handler) { this.eventEmitter.removeListener(name, handler); } addEventListener(name, handler) { this.eventEmitter.on(name, handler); } // @ts-expect-error No Event type in Node 14 dispatchEvent(type: string) { const event = { type, target: this }; const handlerName = `on${event.type}`; if (typeof this[handlerName] === 'function') this[handlerName](event); return this.eventEmitter.emit(event.type, event); } throwIfAborted() { if (this.aborted) { throw this.reason; } } static abort(reason: any) { const controller = new AbortController(); controller.abort(reason); return controller.signal; } static timeout(time) { const controller = new AbortController(); setTimeout(() => controller.abort(new Error('TimeoutError')), time); return controller.signal; } } const AbortSignal = global.AbortSignal ?? AbortSignalPolyfill; class AbortControllerPolyfill implements AbortController { signal: AbortSignal; constructor() { debugLog('Using polyfilled AbortController'); // @ts-expect-error No Event type in Node 14 this.signal = new AbortSignal(); } abort(reason?: any) { if (this.signal.aborted) return; // @ts-expect-error Not a read only property when polyfilling this.signal.aborted = true; if (reason) { // @ts-expect-error Not a read only property when polyfilling this.signal.reason = reason; } else { // @ts-expect-error Not a read only property when polyfilling this.signal.reason = new Error('AbortError'); } // @ts-expect-error No Event type in Node 14 this.signal.dispatchEvent('abort'); } toString() { return '[object AbortController]'; } get [Symbol.toStringTag]() { return 'AbortController'; } } const AbortController = global.AbortController ?? AbortControllerPolyfill; export { AbortController }; ================================================ FILE: packages/graphql-codegen-cli/src/utils/cli-error.ts ================================================ type CompositeError = Error; type ListrError = Error & { errors: CompositeError[] }; export function isListrError(err: Error & { name?: unknown; errors?: unknown }): err is ListrError { return err.name === 'ListrError' && Array.isArray(err.errors) && err.errors.length > 0; } export function cliError(err: any, exitOnError = true) { let msg: string | Error; if (err instanceof Error) { msg = err; } else if (typeof err === 'string') { msg = err; } else { msg = JSON.stringify(err); } // eslint-disable-next-line no-console console.error(msg); if (exitOnError) { process.exit(1); } } ================================================ FILE: packages/graphql-codegen-cli/src/utils/debugging.ts ================================================ import { getLogger } from './logger.js'; let queue: Array<{ message: string; meta?: any[]; }> = []; export function debugLog(message: string, ...meta: any[]) { queue.push({ message, meta, }); } export function printLogs() { for (const log of queue) { getLogger().info(log.message, ...log.meta); } resetLogs(); } export function resetLogs() { queue = []; } ================================================ FILE: packages/graphql-codegen-cli/src/utils/file-system.ts ================================================ import { promises, unlink as fsUnlink } from 'fs'; const { access: fsAccess, writeFile: fsWriteFile, readFile: fsReadFile, mkdir } = promises; export function access(...args: Parameters) { return fsAccess(...args); } export function writeFile(filepath: string, content: string) { return fsWriteFile(filepath, content); } export function readFile(filepath: string) { return fsReadFile(filepath, 'utf-8'); } export function unlinkFile(filePath: string, cb?: (err?: Error) => any): void { fsUnlink(filePath, cb); } export function mkdirp(filePath: string) { return mkdir(filePath, { recursive: true }); } ================================================ FILE: packages/graphql-codegen-cli/src/utils/get-latest-version.ts ================================================ import { fetch } from '@whatwg-node/fetch'; /** * Fetches the version directly from the registry instead of depending on * an ESM only module as latest-version does. * @param packageName */ export async function getLatestVersion(packageName: string): Promise { return fetch(`https://unpkg.com/${packageName}/package.json`) .then(res => res.json()) .then(pkg => pkg.version); } ================================================ FILE: packages/graphql-codegen-cli/src/utils/helpers.ts ================================================ export function isURL(str: string): boolean { try { const url = new URL(str); return !!url; } catch { return false; } } ================================================ FILE: packages/graphql-codegen-cli/src/utils/logger.ts ================================================ import { dummyLogger, Logger } from 'ts-log'; let logger: Logger; export function getLogger(): Logger { return logger || dummyLogger; } useWinstonLogger(); export function setLogger(newLogger: Logger) { logger = newLogger; } export function setSilentLogger() { logger = dummyLogger; } export function useWinstonLogger() { if (logger?.levels) { return; } logger = console; } ================================================ FILE: packages/graphql-codegen-cli/src/utils/patterns.ts ================================================ import { isAbsolute, relative } from 'path'; import { isValidPath } from '@graphql-tools/utils'; import { normalizeInstanceOrArray, Types } from '@graphql-codegen/plugin-helpers'; import isGlob from 'is-glob'; import mm from 'micromatch'; import { CodegenContext } from '../config.js'; import { isURL } from './helpers.js'; type NegatedPattern = `!${string}`; /** * Flatten a list of pattern sets to be a list of only the affirmative patterns * are contained in all of them. * * This can be used, for example, to find the "longest common prefix directory" * by examining `mm.scan(pattern).base` for each `pattern`. */ export const allAffirmativePatternsFromPatternSets = (patternSets: PatternSet[]) => { return patternSets.flatMap(patternSet => [ ...patternSet.watch.affirmative, ...patternSet.documents.affirmative, ...patternSet.schemas.affirmative, ]); }; /** * Create a rebuild trigger that follows the algorithm described here: * https://github.com/dotansimha/graphql-code-generator/issues/9270#issuecomment-1496765045 * * There is a flow chart diagram in that comment. * * Basically: * * * "Global" patterns are defined at top level of config file, and "local" * patterns are defined for each output target * * Each pattern can have "watch", "documents", and "schemas" * * Watch patterns (global and local) always take precedence over documents and * schemas patterns, i.e. a watch negation always negates, and a watch match is * a match even if it would be negated by some pattern in documents or schemas * * The trigger returns true if any output target's local patterns result in * a match, after considering the precedence of any global and local negations */ export const makeShouldRebuild = ({ globalPatternSet, localPatternSets, }: { globalPatternSet: PatternSet; localPatternSets: PatternSet[]; }) => { const localMatchers = localPatternSets.map(localPatternSet => { return (path: string) => { // Is path negated by any negating watch pattern? if (matchesAnyNegatedPattern(path, [...globalPatternSet.watch.negated, ...localPatternSet.watch.negated])) { // Short circut: negations in watch patterns take priority return false; } // Does path match any affirmative watch pattern? if ( matchesAnyAffirmativePattern(path, [ ...globalPatternSet.watch.affirmative, ...localPatternSet.watch.affirmative, ]) ) { // Immediately return true: Watch pattern takes priority, even if documents or schema would negate it return true; } // Does path match documents patterns (without being negated)? if ( matchesAnyAffirmativePattern(path, [ ...globalPatternSet.documents.affirmative, ...localPatternSet.documents.affirmative, ]) && !matchesAnyNegatedPattern(path, [...globalPatternSet.documents.negated, ...localPatternSet.documents.negated]) ) { return true; } // Does path match schemas patterns (without being negated)? if ( matchesAnyAffirmativePattern(path, [ ...globalPatternSet.schemas.affirmative, ...localPatternSet.schemas.affirmative, ]) && !matchesAnyNegatedPattern(path, [...globalPatternSet.schemas.negated, ...localPatternSet.schemas.negated]) ) { return true; } // Otherwise, there is no match return false; }; }); /** * Return `true` if `path` should trigger a rebuild */ return ({ path: absolutePath }: { path: string }) => { if (!isAbsolute(absolutePath)) { throw new Error('shouldRebuild trigger should be called with absolute path'); } const path = relative(process.cwd(), absolutePath); const shouldRebuild = localMatchers.some(matcher => matcher(path)); return shouldRebuild; }; }; /** * Create the pattern set for the "global" (top level) config. * * In the `shouldRebuild` algorithm, any of these watch patterns will take * precedence over local configs, and any schemas and documents patterns will be * mixed into the pattern set of each local config. */ export const makeGlobalPatternSet = (initialContext: CodegenContext) => { const config: Types.Config & { configFilePath?: string } = initialContext.getConfig(); return { watch: sortPatterns([ ...(typeof config.watch === 'boolean' ? [] : normalizeInstanceOrArray(config.watch ?? [])), relative(process.cwd(), initialContext.filepath), ]), schemas: sortPatterns(makePatternsFromSchemas(normalizeInstanceOrArray(config.schema))), documents: sortPatterns( makePatternsFromDocuments(normalizeInstanceOrArray(config.documents)) ), }; }; /** * Create the pattern set for a "local" (output target) config * * In the `shouldRebuild` algorithm, any of these watch patterns will take * precedence over documents or schemas patterns, and the documents and schemas * patterns will be mixed into the pattern set of their respective gobal pattern * set equivalents. */ export const makeLocalPatternSet = (conf: Types.ConfiguredOutput) => { return { watch: sortPatterns(normalizeInstanceOrArray(conf.watchPattern)), documents: sortPatterns( makePatternsFromDocuments(normalizeInstanceOrArray(conf.documents)) ), schemas: sortPatterns(makePatternsFromSchemas(normalizeInstanceOrArray(conf.schema))), }; }; /** * Parse a list of micromatch patterns from a list of documents, which should * already have been normalized from their raw config values. */ const makePatternsFromDocuments = (documents: Types.OperationDocument[]): string[] => { const patterns: string[] = []; if (documents) { for (const doc of documents) { if (typeof doc === 'string') { patterns.push(doc); } else { patterns.push(...Object.keys(doc)); } } } return patterns; }; /** * Parse a list of micromatch patterns from a list of schemas, which should * already have been normalized from their raw config values. */ const makePatternsFromSchemas = (schemas: Types.Schema[]): string[] => { const patterns: string[] = []; for (const s of schemas) { const schema = s as string; if (!isURL(schema) && (isGlob(schema) || isValidPath(schema))) { patterns.push(schema); } } return patterns; }; /** * Given a list of micromatch patterns, sort them into `patterns` (all of them), * `affirmative` (only the affirmative patterns), and `negated` (only the negated patterns) * * @param patterns List of micromatch patterns */ export const sortPatterns =

    (patterns: P[]): SortedPatterns

    => ({ patterns, affirmative: onlyAffirmativePatterns(patterns) as P[], negated: onlyNegatedPatterns(patterns) as Extract[], }); /** * A type that "sorts" (or "groups") patterns. For a given list of `patterns`, * this type will include the original list in `patterns`, all of its * "affirmative" (non-negated) patterns in `affirmative`, and all of its * "negated" patterns in `negated` */ type SortedPatterns = { /** List of patterns, which could include both negated and affirmative patterns */ patterns: PP[]; /** List of only the affirmative (non-negated) patterns in `patterns` */ affirmative: PP[]; /** List of only the negated patterns in `patterns` */ negated: Extract[]; }; /** * The global (top-level) config and each local (output target) config can have * patterns which are separable into "watch" (always takes precedence), "documents", * and "schemas". This type can hold sorted versions of these patterns. */ type PatternSet = { watch: SortedPatterns; documents: SortedPatterns; schemas: SortedPatterns; }; /** * Filter the provided list of patterns to include only "affirmative" (non-negated) patterns. * * @param patterns List of micromatch patterns (or paths) to filter */ const onlyAffirmativePatterns = (patterns: string[]) => { return patterns.filter(pattern => !mm.scan(pattern).negated); }; /** * Filter the provided list of patterns to include only negated patterns. * * @param patterns List of micromatch patterns (or paths) to filter */ const onlyNegatedPatterns = (patterns: string[]) => { return patterns.filter(pattern => mm.scan(pattern).negated); }; /** * Given a list of negated patterns, invert them by removing their negation prefix * * If there is a non-negated pattern in the list, throw an error, because this * function should only be called after filtering the list to be only negated patterns * * @param patterns List of negated micromatch patterns */ const invertNegatedPatterns = (patterns: string[]) => { return patterns.map(pattern => { const scanned = mm.scan(pattern); if (!scanned.negated) { throw new Error(`onlyNegatedPatterns got a non-negated pattern: ${pattern}`); } // Remove the leading prefix (NOTE: this is not always "!") // e.g. mm.scan("!./foo/bar/never-watch.graphql").prefix === '!./' return pattern.slice(scanned.prefix.length); }); }; /** * Return true if relativeCandidatePath matches any of the affirmativePatterns * * @param relativeCandidatePath A relative path to evaluate against the supplied affirmativePatterns * @param affirmativePatterns A list of patterns, containing no negated patterns, to evaluate */ const matchesAnyAffirmativePattern = (relativeCandidatePath: string, affirmativePatterns: string[]) => { if (isAbsolute(relativeCandidatePath)) { throw new Error('matchesAny should only be called with relative candidate path'); } // Developer error: This function is not intended to work with pattern sets including negations if (affirmativePatterns.some(pattern => mm.scan(pattern).negated)) { throw new Error('matchesAnyAffirmativePattern should only include affirmative patterns'); } // micromatch.isMatch does not omit matches that are negated by negation patterns, // which is why we require this function only examine affirmative patterns return mm.isMatch(relativeCandidatePath, affirmativePatterns); }; /** * Return true if relativeCandidatePath matches any of the negatedPatterns * * This function will invert the negated patterns and then call matchesAnyAffirmativePattern * * @param relativeCandidatePath A relative path to evaluate against the suppliednegatedPatterns * @param negatedPatterns A list of patterns, containing no negated patterns, to evaluate */ const matchesAnyNegatedPattern = (relativeCandidatePath: string, negatedPatterns: string[]) => { // NOTE: No safety check that negatedPatterns contains only negated, because that will happen in invertedNegatedPatterns return matchesAnyAffirmativePattern(relativeCandidatePath, invertNegatedPatterns(negatedPatterns)); }; ================================================ FILE: packages/graphql-codegen-cli/src/utils/watcher.ts ================================================ import { join, isAbsolute, relative, resolve, sep } from 'path'; import { normalizeOutputParam, Types } from '@graphql-codegen/plugin-helpers'; import type { subscribe } from '@parcel/watcher'; import debounce from 'debounce'; import mm from 'micromatch'; import logSymbols from 'log-symbols'; import { executeCodegen } from '../codegen.js'; import { CodegenContext, loadContext } from '../config.js'; import { lifecycleHooks } from '../hooks.js'; import { access } from './file-system.js'; import { debugLog } from './debugging.js'; import { getLogger } from './logger.js'; import { allAffirmativePatternsFromPatternSets, makeGlobalPatternSet, makeLocalPatternSet, makeShouldRebuild, } from './patterns.js'; import { AbortController } from './abort-controller-polyfill.js'; function log(msg: string) { // double spaces to inline the message with Listr getLogger().info(` ${msg}`); } function emitWatching(watchDir: string) { log(`${logSymbols.info} Watching for changes in ${watchDir}...`); } export const createWatcher = ( initialContext: CodegenContext, onNext: (result: Types.FileOutput[]) => Promise ): { /** * Call this function to stop the running watch server * * @returns Promise that resolves when watcher has terminated ({@link runningWatcher} promise settled) * */ stopWatching: () => Promise; /** * Promise that will never resolve as long as the watcher is running. To stop * the watcher, call {@link stopWatching}, which will send a stop signal and * then return a promise that doesn't resolve until `runningWatcher` has resolved. * */ runningWatcher: Promise; } => { debugLog(`[Watcher] Starting watcher...`); let config: Types.Config & { configFilePath?: string } = initialContext.getConfig(); const globalPatternSet = makeGlobalPatternSet(initialContext); const localPatternSets = Object.keys(config.generates) .map(filename => normalizeOutputParam(config.generates[filename])) .map(conf => makeLocalPatternSet(conf)); const allAffirmativePatterns = allAffirmativePatternsFromPatternSets([globalPatternSet, ...localPatternSets]); const shouldRebuild = makeShouldRebuild({ globalPatternSet, localPatternSets }); let watcherSubscription: Awaited>; const runWatcher = async (abortSignal: AbortSignal) => { const watchDirectory = await findHighestCommonDirectory(allAffirmativePatterns); // Try to load the parcel watcher, but don't fail if it's not available. let parcelWatcher: typeof import('@parcel/watcher'); try { parcelWatcher = await import('@parcel/watcher'); } catch { log( 'Failed to import @parcel/watcher.\n To use watch mode, install https://www.npmjs.com/package/@parcel/watcher.' ); return; } debugLog(`[Watcher] Parcel watcher loaded...`); let isShutdown = false; const debouncedExec = debounce(() => { if (!isShutdown) { executeCodegen(initialContext) .then( ({ result, error }) => { // FIXME: this is a quick fix to stop `onNext` (writeOutput) from // removing all files when there is an error. // // This is because `removeStaleFiles()` will remove files if the // generated files are different between runs. And on error, it // returns an empty array i.e. will remove all generated files from // the previous run // // This also means we don't have config.allowPartialOutputs in watch mode if (error) { return; } onNext(result); }, () => Promise.resolve() ) .then(() => emitWatching(watchDirectory)); } }, 100); emitWatching(watchDirectory); const ignored: string[] = ['**/.git/**']; for (const entry of Object.keys(config.generates).map(filename => ({ filename, config: normalizeOutputParam(config.generates[filename]), }))) { // ParcelWatcher expects relative ignore patterns to be relative from watchDirectory, // but we expect filename from config to be relative from cwd, so we need to convert const filenameRelativeFromWatchDirectory = relative(watchDirectory, resolve(process.cwd(), entry.filename)); if (entry.config.preset) { const extension = entry.config.presetConfig?.extension; if (extension) { ignored.push(join(filenameRelativeFromWatchDirectory, '**', '*' + extension)); } } else { ignored.push(filenameRelativeFromWatchDirectory); } } watcherSubscription = await parcelWatcher.subscribe( watchDirectory, async (_, events) => { // it doesn't matter what has changed, need to run whole process anyway await Promise.all( // NOTE: @parcel/watcher always provides path as an absolute path events.map(async ({ type: eventName, path }) => { if (!shouldRebuild({ path })) { return; } lifecycleHooks(config.hooks).onWatchTriggered(eventName, path); debugLog(`[Watcher] triggered due to a file ${eventName} event: ${path}`); // In ESM require is not defined try { delete require.cache[path]; } catch {} if (eventName === 'update' && config.configFilePath && path === config.configFilePath) { log(`${logSymbols.info} Config file has changed, reloading...`); const context = await loadContext(config.configFilePath); const newParsedConfig: Types.Config & { configFilePath?: string } = context.getConfig(); newParsedConfig.watch = config.watch; newParsedConfig.silent = config.silent; newParsedConfig.overwrite = config.overwrite; newParsedConfig.configFilePath = config.configFilePath; config = newParsedConfig; initialContext.updateConfig(config); } debouncedExec(); }) ); }, { ignore: ignored } ); debugLog(`[Watcher] Started`); const shutdown = ( /** Optional callback to execute after shutdown has completed its async tasks */ afterShutdown?: () => void ) => { isShutdown = true; debugLog(`[Watcher] Shutting down`); log(`Shutting down watch...`); const pendingUnsubscribe = watcherSubscription.unsubscribe(); const pendingBeforeDoneHook = lifecycleHooks(config.hooks).beforeDone(); if (afterShutdown && typeof afterShutdown === 'function') { Promise.allSettled([pendingUnsubscribe, pendingBeforeDoneHook]).then(afterShutdown); } }; abortSignal.addEventListener('abort', () => shutdown(abortSignal.reason)); process.once('SIGINT', () => shutdown()); process.once('SIGTERM', () => shutdown()); }; // Use an AbortController for shutdown signals // NOTE: This will be polyfilled on Node 14 (or any environment without it defined) const abortController = new AbortController(); /** * Send shutdown signal and return a promise that only resolves after the * runningWatcher has resolved, which only resolved after the shutdown signal has been handled */ const stopWatching = async function () { // stopWatching.afterShutdown is lazily set to resolve pendingShutdown promise abortController.abort(stopWatching.afterShutdown); // SUBTLE: runningWatcher waits for pendingShutdown before it resolves itself, so // by awaiting it here, we are awaiting both the shutdown handler, and runningWatcher itself await stopWatching.runningWatcher; }; stopWatching.afterShutdown = () => { debugLog('Shutdown watcher before it started'); }; stopWatching.runningWatcher = Promise.resolve(); /** Promise will resolve after the shutdown() handler completes */ const pendingShutdown = new Promise(afterShutdown => { // afterShutdown will be passed to shutdown() handler via abortSignal.reason stopWatching.afterShutdown = afterShutdown; }); /** * Promise that resolves after the watch server has shutdown, either because * stopWatching() was called or there was an error inside it */ stopWatching.runningWatcher = new Promise((resolve, reject) => { executeCodegen(initialContext) .then( ({ result, error }) => { // TODO: this is the initial run, the logic here mimics the above watcher logic. // We need to check whether it's ok to deviate between these two. if (error) { return; } onNext(result); }, () => Promise.resolve() ) .then(() => runWatcher(abortController.signal)) .catch(err => { watcherSubscription.unsubscribe(); reject(err); }) .then(() => pendingShutdown) .finally(() => { debugLog('Done watching.'); resolve(); }); }); return { stopWatching, runningWatcher: stopWatching.runningWatcher, }; }; /** * Given a list of file paths (each of which may be absolute, or relative from * `process.cwd()`), find absolute path of the "highest" common directory, * i.e. the directory that contains all the files in the list. * * @param files List of relative and/or absolute file paths (or micromatch patterns) */ const findHighestCommonDirectory = async (files: string[]): Promise => { // Map files to a list of basePaths, where "base" is the result of mm.scan(pathOrPattern) // e.g. mm.scan("/**/foo/bar").base -> "/" ; mm.scan("/foo/bar/**/fizz/*.graphql") -> /foo/bar const dirPaths = files .map(filePath => (isAbsolute(filePath) ? filePath : resolve(filePath))) // mm.scan doesn't know how to handle Windows \ path separator .map(patterned => patterned.replace(/\\/g, '/')) .map(patterned => mm.scan(patterned).base) // revert the separators to the platform-supported ones .map(base => base.replace(/\//g, sep)); // Return longest common prefix if it's accessible, otherwise process.cwd() return (async (maybeValidPath: string) => { debugLog(`[Watcher] Longest common prefix of all files: ${maybeValidPath}...`); try { await access(maybeValidPath); return maybeValidPath; } catch { log(`[Watcher] Longest common prefix (${maybeValidPath}) is not accessible`); log(`[Watcher] Watching current working directory (${process.cwd()}) instead`); return process.cwd(); } })(longestCommonPrefix(dirPaths.map(path => path.split(sep))).join(sep)); }; /** * Find the longest common prefix of an array of paths, where each item in * the array an array of path segments which comprise an absolute path when * joined together by a path separator * * Adapted from: * https://duncan-mcardle.medium.com/leetcode-problem-14-longest-common-prefix-javascript-3bc6a2f777c4 * * @param splitPaths An array of arrays, where each item is a path split by its separator * @returns An array of path segments representing the longest common prefix of splitPaths */ const longestCommonPrefix = (splitPaths: string[][]): string[] => { // Return early on empty input if (!splitPaths.length) { return []; } // Loop through the segments of the first path for (let i = 0; i <= splitPaths[0].length; i++) { // Check if this path segment is present in the same position of every path if (!splitPaths.every(string => string[i] === splitPaths[0][i])) { // If not, return the path segments up to and including the previous segment return splitPaths[0].slice(0, i); } } return splitPaths[0]; }; ================================================ FILE: packages/graphql-codegen-cli/tests/__mocks__/fs.cjs ================================================ const { fs } = require('memfs'); module.exports = fs; ================================================ FILE: packages/graphql-codegen-cli/tests/__mocks__/some-fetch.cjs ================================================ const { promises: { readFile }, } = require('fs'); const { join } = require('path'); const { buildSchema, graphql, introspectionQuery } = require('graphql'); module.exports = { someFetchFn: async () => { const schemaFile = await readFile(join(__dirname, '../test-documents/schema.graphql'), 'utf8'); const schema = buildSchema(schemaFile); global.CUSTOM_FETCH_FN_CALLED = true; return { headers: { 'content-type': 'application/json', }, async text() { return JSON.stringify(await graphql(schema, introspectionQuery)); }, async json() { return JSON.parse(await this.text()); }, }; }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/__snapshots__/init.spec.ts.snap ================================================ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`init > custom setup 1`] = ` " import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { overwrite: true, schema: "http://localhost:4000", documents: "graphql/*.ts", generates: { "src/gql/": { preset: "client", plugins: [] }, "./graphql.schema.json": { plugins: ["introspection"] } } }; export default config; " `; exports[`init > plugins suggestions for client-side setup > should use angular related plugins when @angular/core is found 1`] = ` " import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { overwrite: true, schema: "http://localhost:4000", documents: "src/**/*.ts", generates: { "src/generated/graphql.ts": { plugins: ["typescript-apollo-angular"] } } }; export default config; " `; exports[`init > plugins suggestions for client-side setup > should use react related plugins when react is found 1`] = ` " import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { overwrite: true, schema: "http://localhost:4000", documents: "src/**/*.tsx", generates: { "src/gql/": { preset: "client", plugins: [] } } }; export default config; " `; exports[`init > plugins suggestions for client-side setup > should use stencil related plugins when @stencil/core is found 1`] = ` " import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { overwrite: true, schema: "http://localhost:4000", documents: "src/**/*.graphql", generates: { "src/generated/graphql.tsx": { plugins: ["typescript", "typescript-operations", "typescript-stencil-apollo"] } } }; export default config; " `; exports[`init > plugins suggestions non client-side setup > should use typescript related plugins when typescript is found (node) 1`] = ` " import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { overwrite: true, schema: "http://localhost:4000", generates: { "src/generated/graphql.ts": { plugins: ["typescript", "typescript-resolvers"] } } }; export default config; " `; exports[`init > should have few default values for Angular 1`] = ` " import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { overwrite: true, schema: "http://localhost:4000", documents: "src/**/*.tsx", generates: { "src/gql/": { preset: "client", plugins: [] } } }; export default config; " `; exports[`init > should have few default values for React 1`] = ` "overwrite: true schema: "./schema.ts" documents: "graphql/**/*.graphql" generates: graphql/index.ts: preset: "client" plugins: [] ./graphql.schema.json: plugins: - "introspection" " `; ================================================ FILE: packages/graphql-codegen-cli/tests/cli-error.spec.ts ================================================ import { cliError } from '../src/utils/cli-error.js'; describe('cliError', () => { let spyProcessExit: ReturnType; let spyConsoleError: ReturnType; beforeEach(() => { spyProcessExit = vi.spyOn(process, 'exit'); spyProcessExit.mockImplementation(() => {}); spyConsoleError = vi.spyOn(console, 'error'); spyConsoleError.mockImplementation(() => {}); }); afterEach(() => { spyProcessExit.mockRestore(); spyConsoleError.mockRestore(); }); it('should handle an Error', () => { const msg = 'used as error'; cliError(new Error(msg)); expect(spyProcessExit).toBeCalledWith(1); }); it('should handle string', () => { const msg = 'used as string'; cliError(msg); expect(spyProcessExit).toBeCalledWith(1); }); it('should handle an object', () => { const obj = { foo: 1, }; cliError(obj); expect(spyProcessExit).toBeCalledWith(1); }); }); ================================================ FILE: packages/graphql-codegen-cli/tests/cli-flags.spec.ts ================================================ import { createContext, parseArgv } from '../src/config.js'; import { TempDir } from './utils.js'; const mockConfig = (str: string, file = './codegen.yml') => temp.createFile(file, str); const createArgv = (str = ''): string[] => { const result = ['node', 'fake.js']; // eslint-disable-next-line no-control-regex const regexp = /([^\s'"]+(['"])([^\x02]*?)\x02)|[^\s'"]+|(['"])([^\x04]*?)\x04/gi; let match; do { match = regexp.exec(str); if (match !== null) { result.push(match[1] || match[5] || match[0]); } } while (match !== null); return result; }; const temp = new TempDir(); describe('CLI Flags', () => { beforeEach(() => { temp.clean(); vi.spyOn(process, 'cwd').mockImplementation(() => temp.dir); }); afterEach(() => { vi.clearAllMocks(); vi.restoreAllMocks(); }); afterAll(() => { temp.deleteTempDir(); }); it('Should create basic config using new yml API', async () => { mockConfig(` schema: schema.graphql generates: file.ts: - plugin `); const args = createArgv(); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.schema).toEqual('schema.graphql'); expect(config.generates).toEqual({ 'file.ts': ['plugin'] }); }); it('Should use different config file correctly with --config', async () => { mockConfig( ` schema: schema.graphql generates: file.ts: - plugin `, 'other.yml' ); const args = createArgv('--config other.yml'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.schema).toEqual('schema.graphql'); expect(config.generates).toEqual({ 'file.ts': ['plugin'] }); }); it('Should set --watch with new YML api', async () => { mockConfig(` schema: schema.graphql generates: file.ts: - plugin `); const args = createArgv('--watch'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.watch).toBeTruthy(); }); it('Should set watch and overwrite to default (false) with new YML api', async () => { mockConfig(` schema: schema.graphql generates: file.ts: - plugin `); const args = createArgv(); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.watch).not.toBeTruthy(); expect(config.overwrite).not.toBeTruthy(); }); it('Should overwrite watch config using cli flag to true', async () => { mockConfig(` schema: schema.graphql watch: false generates: file.ts: - plugin `); const args = createArgv('--watch'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.watch).toBeTruthy(); }); it('Should overwrite watch config using cli flags to false', async () => { mockConfig(` schema: schema.graphql watch: true generates: file.ts: - plugin `); const args = createArgv('--watch=false'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.watch).toBeFalsy(); }); it('Should overwrite ignoreNoDocuments config using cli flags to false', async () => { mockConfig(` schema: schema.graphql ignoreNoDocuments: true generates: file.ts: - plugin `); const args = createArgv('--ignore-no-documents=false'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.ignoreNoDocuments).toBeFalsy(); }); it('Should overwrite emitLegacyCommonJSImports config using cli flags to true', async () => { mockConfig(` schema: schema.graphql emitLegacyCommonJSImports: false generates: file.ts: - plugin `); const args = createArgv('--emit-legacy-common-js-imports'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.emitLegacyCommonJSImports).toBeTruthy(); }); it('Should overwrite emitLegacyCommonJSImports config using cli flags to false', async () => { mockConfig(` schema: schema.graphql emitLegacyCommonJSImports: true generates: file.ts: - plugin `); const args = createArgv('--emit-legacy-common-js-imports=false'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.emitLegacyCommonJSImports).toBeFalsy(); }); it('Should set importExtension config using cli flags to .js', async () => { mockConfig(` schema: schema.graphql generates: file.ts: - plugin `); const args = createArgv('--import-extension .js'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.importExtension).toBe('.js'); }); it('Should set importExtension config using cli flags to .mjs', async () => { mockConfig(` schema: schema.graphql generates: file.ts: - plugin `); const args = createArgv('--import-extension .mjs'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.importExtension).toBe('.mjs'); }); it('Should set importExtension config using cli flags to empty string', async () => { mockConfig(` schema: schema.graphql generates: file.ts: - plugin `); const args = createArgv('--import-extension ""'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.importExtension).toBe(''); }); it('Should overwrite importExtension from config using cli flags', async () => { mockConfig(` schema: schema.graphql importExtension: .js generates: file.ts: - plugin `); const args = createArgv('--import-extension .mjs'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.importExtension).toBe('.mjs'); }); it('Should overwrite importExtension config using cli flags to empty string', async () => { mockConfig(` schema: schema.graphql importExtension: .js generates: file.ts: - plugin `); const args = createArgv('--import-extension ""'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.importExtension).toBe(''); }); it('Should overwrite ignoreNoDocuments config using cli flags to true', async () => { mockConfig(` schema: schema.graphql ignoreNoDocuments: false generates: file.ts: - plugin `); const args = createArgv('--ignore-no-documents'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.ignoreNoDocuments).toBeTruthy(); }); it('Should set --overwrite with new YML api', async () => { mockConfig(` schema: schema.graphql generates: file.ts: - plugin `); const args = createArgv('--overwrite'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.overwrite).toBeTruthy(); }); it('Should interpolate environmental variables in YML', async () => { process.env.SCHEMA_PATH = 'schema-env.graphql'; mockConfig(` schema: \${SCHEMA_PATH} generates: file.ts: - plugin `); const args = createArgv('--overwrite'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.schema).toBe('schema-env.graphql'); }); it('Should interpolate multiple environmental variables in YML', async () => { process.env.SCHEMA_SCHEME = 'https'; process.env.SCHEMA_HOST = 'localhost'; mockConfig(` schema: \${SCHEMA_SCHEME}://\${SCHEMA_HOST}/graphql generates: file.ts: - plugin `); const args = createArgv('--overwrite'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.schema).toBe('https://localhost/graphql'); }); it('Should interpolate environmental variables in YML and support default value', async () => { process.env.SCHEMA_PATH = ''; mockConfig(` schema: \${SCHEMA_PATH:schema.graphql} generates: file.ts: - plugin `); const args = createArgv('--overwrite'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.schema).toBe('schema.graphql'); }); it('Should interpolate environmental variables in YML and support default value containing ":"', async () => { process.env.SCHEMA_PATH = ''; mockConfig(` schema: \${SCHEMA_PATH:http://url-to-graphql-api} generates: file.ts: - plugin `); const args = createArgv('--overwrite'); const context = await createContext(parseArgv(args)); const config = context.getConfig(); expect(config.schema).toBe('http://url-to-graphql-api'); }); it('Should load require extensions provided by cli flags', async () => { process.env.SCHEMA_PATH = 'schema-env.graphql'; mockConfig(` schema: \${SCHEMA_PATH} generates: file.ts: - plugin `); const args = createArgv('--require my-extension'); try { await createContext(parseArgv(args)); expect(true).toBeFalsy(); } catch (e) { expect(e.code).toEqual('MODULE_NOT_FOUND'); } }); }); ================================================ FILE: packages/graphql-codegen-cli/tests/codegen.spec.ts ================================================ import { join } from 'path'; import '@graphql-codegen/testing'; import { mergeTypeDefs } from '@graphql-tools/merge'; import { buildASTSchema, buildSchema, GraphQLObjectType, parse, print, OperationDefinitionNode, Kind } from 'graphql'; import { createContext, executeCodegen } from '../src/index.js'; import type { Types } from '@graphql-codegen/plugin-helpers'; const SHOULD_NOT_THROW_STRING = 'SHOULD_NOT_THROW'; const SIMPLE_TEST_SCHEMA = `type MyType { f: String } type Query { f: String }`; describe('Codegen Executor', () => { describe('Generator General Options', () => { it('Should output the correct filenames', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out1.ts': { plugins: ['typescript'] }, 'out2.ts': { plugins: ['typescript'] }, }, }); expect(result.length).toBe(2); expect(result.map(f => f.filename)).toEqual(expect.arrayContaining(['out1.ts', 'out2.ts'])); }); it('Should load require extensions', async () => { expect((global as any).dummyWasLoaded).toBeFalsy(); const { result } = await executeCodegen({ schema: join(__dirname, './test-files/schema-dir/schema-object.cjs'), require: join(__dirname, './dummy-require.js'), generates: { 'out1.ts': { plugins: ['typescript'] }, }, cwd: __dirname, }); expect(result.length).toBe(1); expect((global as any).dummyWasLoaded).toBeTruthy(); }); it('Should throw when require extension is invalid', async () => { try { await executeCodegen({ schema: join(__dirname, './test-files/schema-dir/schema-object.js'), require: join(__dirname, './missing.js'), generates: { 'out1.ts': { plugins: ['typescript'] }, }, cwd: __dirname, }); throw new Error(SHOULD_NOT_THROW_STRING); } catch (e) { expect(e.message).not.toBe(SHOULD_NOT_THROW_STRING); } }); it('Should accept plugins as object', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, generates: { 'out1.ts': { plugins: [ { 'typescript-operations': {}, }, ], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type RootQuery'); }); it('Should accept plugins as array of objects', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, generates: { 'out1.ts': { plugins: [{ 'typescript-operations': {} }], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type RootQuery'); }); it('Should throw when no output files has been specified', async () => { try { await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: {}, }); throw new Error(SHOULD_NOT_THROW_STRING); } catch (e) { expect(e.message).not.toBe(SHOULD_NOT_THROW_STRING); expect(e.message).toMatch('Invalid Codegen Configuration!'); } }); it('Should work with just schema', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out.ts': { plugins: ['typescript'], }, }, }); expect(result.length).toBe(1); }); it('Should not throw when every output has a schema and there is no root schema', async () => { try { const { result } = await executeCodegen({ generates: { 'out.ts': { schema: SIMPLE_TEST_SCHEMA, plugins: ['typescript'], }, }, }); expect(result.length).toBe(1); } catch (e) { expect(e.message).not.toBe(SHOULD_NOT_THROW_STRING); expect(e.message).not.toMatch('Invalid Codegen Configuration!'); } }); it('Should throw when there is no root schema and some outputs have not defined its own schema', async () => { try { await executeCodegen({ generates: { 'out.ts': { plugins: ['typescript'], }, }, }); throw new Error(SHOULD_NOT_THROW_STRING); } catch (e) { expect(e.message).toMatch('Invalid Codegen Configuration!'); expect(e.message).not.toBe(SHOULD_NOT_THROW_STRING); } }); it('Should throw when one output has no plugins or preset defined', async () => { expect.assertions(1); try { await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out.ts': {}, }, }); } catch (e) { expect(e.message).toMatch('Invalid Codegen Configuration!'); } }); it('Should throw when one output has no plugins defined', async () => { expect.assertions(1); try { await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out.ts': { plugins: [], }, }, }); } catch (e) { expect(e.message).toMatch('Invalid Codegen Configuration!'); } }); it('Should succeed when one output has no plugins but preset defined', async () => { await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { './src/gql/': { preset: 'client-preset', }, }, }); }); it('should handle extend keyword when GraphQLSchema is used', async () => { const { result } = await executeCodegen({ schema: './tests/test-files/schema-dir/with-extend.js', generates: { 'out.ts': { plugins: ['typescript'], }, }, }); expect(result.length).toBe(1); expect(result[0].filename).toBe('out.ts'); expect(result[0].content).toContain(`hello?: Maybe`); }); }); describe('Per-output options', () => { it('Should allow to specify schema extension for specific output', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out1.ts': { schema: ` type OtherType { a: String } `, plugins: ['typescript'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type Query'); expect(result[0].content).toContain('export type MyType'); expect(result[0].content).toContain('export type OtherType'); }); it('Should allow to specify documents extension for specific output', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out1.ts': { documents: `query q { f }`, plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type QQuery'); }); it('Should extend existing documents', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, generates: { 'out1.ts': { documents: `query q { f }`, plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type QQuery'); }); it('Should inherit root importExtension and emitLegacyCommonJSImports for preset outputs and allow per-output overrides', async () => { const recordingPreset = { buildGeneratesSection: ({ baseOutputDir, config }) => [ { filename: `${baseOutputDir}recorded-config.ts`, pluginMap: { recorder: { plugin: (_schema, _documents, pluginConfig) => JSON.stringify({ importExtension: pluginConfig.importExtension, emitLegacyCommonJSImports: pluginConfig.emitLegacyCommonJSImports, }), }, }, plugins: [{ recorder: {} }], schema: parse(SIMPLE_TEST_SCHEMA), documents: [], config, }, ], }; const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, emitLegacyCommonJSImports: false, importExtension: '.mjs', generates: { './src/gql/': { preset: recordingPreset, }, './src/gql-with-override/': { preset: recordingPreset, config: { importExtension: '.js', }, }, }, }); expect(result).toHaveLength(2); const inheritedOutput = result.find(file => file.filename === './src/gql/recorded-config.ts'); expect(inheritedOutput?.content).toBe(`{"importExtension":".mjs","emitLegacyCommonJSImports":false}`); const overriddenOutput = result.find(file => file.filename === './src/gql-with-override/recorded-config.ts'); expect(overriddenOutput?.content).toBe(`{"importExtension":".js","emitLegacyCommonJSImports":false}`); }); it('Should return error on duplicated names', async () => { const { error } = await executeCodegen({ schema: ` type RootQuery { f: String } schema { query: RootQuery } `, documents: [`query q { e }`, `query q { f }`], generates: { 'out1.ts': { plugins: ['typescript'] }, }, }); expect(error.message).toContain('Not all operations have an unique name: q'); }); it('should handle gql tag in ts with with nested fragment', async () => { const { result } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: ['./tests/test-documents/my-fragment.ts', './tests/test-documents/query-with-my-fragment.ts'], generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result[0].content).toContain('MyQuery'); expect(result[0].filename).toEqual('out1.ts'); }); it('should handle gql tag in ts with with multiple nested fragment', async () => { const { result } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: ['./tests/test-documents/my-fragment.ts', './tests/test-documents/query-with-my-fragment.ts'], generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result[0].content).toContain('MyQuery'); expect(result[0].filename).toEqual('out1.ts'); }); it('should handle gql tag in js with with nested fragment', async () => { const { result } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: ['./tests/test-documents/js-query-with-my-fragment.js', './tests/test-documents/js-my-fragment.js'], generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result[0].content).toContain('MyQuery'); expect(result[0].filename).toEqual('out1.ts'); }); it('should handle TypeScript features', async () => { const { result } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: ['./tests/test-documents/ts-features-with-query.ts'], generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result[0].content).toContain('MyQuery'); expect(result[0].content).toContain('MyQueryInNamespace'); expect(result[0].filename).toEqual('out1.ts'); }); it('should handle multiple fragments with the same name, but one is commented out', async () => { const { result } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: ['./tests/test-documents/query-with-commented-fragment.ts'], generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result[0].content).toContain('MyQuery'); expect(result[0].filename).toEqual('out1.ts'); }); it('should handle graphql-tag and gatsby by default (documents)', async () => { const { result } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: ['./tests/test-documents/gatsby-and-custom-parsers.ts'], generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result[0].content).toContain('FragmentA'); // import gql from 'graphql-tag' expect(result[0].content).toContain('FragmentB'); // import { graphql } from 'gatsby' }); it('should handle custom graphql string parsers (documents)', async () => { const { result } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: ['./tests/test-documents/gatsby-and-custom-parsers.ts'], generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], }, }, pluckConfig: { modules: [ { name: 'custom-graphql-parser', identifier: 'parser', }, ], }, }); expect(result[0].content).toContain('FragmentC'); // import { parser } from 'custom-graphql-parser'; }); // Dotan: @kamil please check it.skip('should handle graphql-tag and gatsby by default (schema)', async () => { const result = await executeCodegen({ schema: './tests/test-files/schema-dir/gatsby-and-custom-parsers/*.ts', generates: { 'out1.ts': { plugins: ['typescript'] }, }, }); const { content } = result[0]; expect(content).toContain('Used graphql-tag'); // import gql from 'graphql-tag' expect(content).toContain('Used gatsby'); // import { graphql } from 'gatsby' expect(content).not.toContain('Used custom parser'); }); // Dotan: @kamil please check it.skip('should handle custom graphql string parsers (schema)', async () => { const result = await executeCodegen({ schema: './tests/test-files/schema-dir/gatsby-and-custom-parsers/*.ts', generates: { 'out1.ts': { plugins: ['typescript'] }, }, pluckConfig: { modules: [ { name: 'custom-graphql-parser', identifier: 'parser', }, ], }, }); const { content } = result[0]; expect(content).toContain('Used custom parser'); // import { parser } from 'custom-graphql-parser'; expect(content).not.toContain('Used graphql-tag'); expect(content).not.toContain('Used gatsby'); }); }); describe('Plugin Configuration', () => { it('Should inherit root config', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, config: { namingConvention: 'change-case-all#lowerCase', }, generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type rootquery'); expect(result[0].content).toContain('export type root'); }); it('Should accept config in per-output (override)', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, generates: { 'out1.ts': { config: { namingConvention: 'change-case-all#lowerCase', }, plugins: ['typescript', 'typescript-operations'], }, 'out2.ts': { config: { namingConvention: 'change-case-all#upperCase', }, plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result.length).toBe(2); expect(result[0].content).toContain('export type rootquery'); expect(result[1].content).toContain('export type ROOTQUERY'); }); it('Should accept config in per-plugin', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, generates: { 'out1.ts': { plugins: [ { 'typescript-operations': { namingConvention: 'change-case-all#lowerCase', }, }, ], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type root'); expect(result[0].content).toContain('export type rootquery'); }); it('Should allow override of config in', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, config: { namingConvention: 'change-case-all#lowerCase', }, generates: { 'out1.ts': { plugins: [ { 'typescript-operations': { namingConvention: 'change-case-all#upperCase', }, }, ], }, 'out2.ts': { plugins: [ { 'typescript-operations': { namingConvention: 'change-case-all#pascalCase', }, }, ], }, }, }); expect(result.length).toBe(2); expect(result[0].content).toContain('export type ROOTQUERY'); expect(result[1].content).toContain('export type RootQuery'); }); }); describe('Plugin loading', () => { it('Should load custom plugin from local file', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out1.ts': { plugins: ['./tests/custom-plugins/basic.js'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('plugin'); }); it('Should return error when custom plugin is not valid', async () => { const { error } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out1.ts': { plugins: ['./tests/custom-plugins/invalid.js'], }, }, }); expect(error.message).toContain('Invalid Custom Plugin'); }); it('Should execute custom plugin validation and return error when it fails', async () => { const { error } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out1.ts': { plugins: ['./tests/custom-plugins/validation.js'], }, }, }); expect(error.message).toContain('validation failed'); }); it('Should allow plugins to extend schema', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out1.ts': { plugins: ['./tests/custom-plugins/extends-schema.js', './tests/custom-plugins/checks-extended-schema.js'], }, }, }); expect(result[0].content).toContain('MyType,'); expect(result[0].content).toContain('Extension'); expect(result[0].content).toContain(`Should have the Extension type: 'Extension'`); }); it('Should allow plugins to extend schema (using a function)', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, config: { test: 'MyType', }, generates: { 'out1.ts': { plugins: ['./tests/custom-plugins/extends-schema-fn.js'], }, }, }); expect(result[0].content).toContain('MyType'); }); }); describe('Schema Merging', () => { it('should keep definitions of all directives', async () => { const merged = buildASTSchema( mergeTypeDefs([ buildSchema(SIMPLE_TEST_SCHEMA), buildSchema(/* GraphQL */ ` directive @id on FIELD_DEFINITION type Post { id: String @id } `), ]) ); expect(merged.getDirectives().map(({ name }) => name)).toContainEqual('id'); }); it('should keep directives in types', async () => { const merged = buildASTSchema( mergeTypeDefs([ buildSchema(SIMPLE_TEST_SCHEMA), buildSchema(/* GraphQL */ ` directive @id on FIELD_DEFINITION directive @test on OBJECT type Post @test { id: String @id } type Query { posts: [Post] } schema { query: Query } `), ]) ); expect(merged.getType('Post').astNode.directives.map(({ name }) => name.value)).toContainEqual('test'); expect( (merged.getType('Post') as GraphQLObjectType).getFields().id.astNode.directives.map(({ name }) => name.value) ).toContainEqual('id'); }); it('should keep scalars', async () => { const schemaA = SIMPLE_TEST_SCHEMA; const schemaB = ` scalar UniqueID type Post { id: UniqueID } `; const schemaC = parse(` scalar NotUniqueID `); const merged = mergeTypeDefs([schemaA, schemaB, schemaC]); expect(print(merged)).toContain('scalar UniqueID'); expect(print(merged)).toContain('scalar NotUniqueID'); const schema = buildASTSchema(merged); expect(schema.getType('UniqueID')).toBeDefined(); expect(schema.getType('NotUniqueID')).toBeDefined(); }); it('should keep scalars when executing codegen', async () => { const schemaA = SIMPLE_TEST_SCHEMA; const schemaB = ` scalar UniqueID type Post { id: UniqueID } `; const { result } = await executeCodegen({ schema: [schemaA, schemaB], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toBeSimilarStringTo(`export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } UniqueID: { input: any; output: any; } };`); }); }); describe('Parsed GraphQLSchema input', () => { it('should accept a GraphQLSchema instance as root schema', async () => { const schema = buildSchema(SIMPLE_TEST_SCHEMA); const { result } = await executeCodegen({ schema, generates: { 'out1.ts': { plugins: ['typescript'] }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('MyType'); }); it('should accept a GraphQLSchema instance in an array', async () => { const schema = buildSchema(SIMPLE_TEST_SCHEMA); const { result } = await executeCodegen({ schema: [schema], generates: { 'out1.ts': { plugins: ['typescript'] }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('MyType'); }); it('should merge a GraphQLSchema instance with an SDL string', async () => { const schema = buildSchema(SIMPLE_TEST_SCHEMA); const { result } = await executeCodegen({ schema: [schema, `type Post { id: ID! }`], generates: { 'out1.ts': { plugins: ['typescript'] }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('MyType'); expect(result[0].content).toContain('Post'); }); it('should merge two GraphQLSchema instances', async () => { const schemaA = buildSchema(SIMPLE_TEST_SCHEMA); const schemaB = buildSchema(`type Post { id: ID! } type Query { posts: [Post] }`); const { result } = await executeCodegen({ schema: [schemaA, schemaB], generates: { 'out1.ts': { plugins: ['typescript'] }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('MyType'); expect(result[0].content).toContain('Post'); }); it('should accept a GraphQLSchema instance as output-level schema', async () => { const schema = buildSchema(SIMPLE_TEST_SCHEMA); const { result } = await executeCodegen({ generates: { 'out1.ts': { schema, plugins: ['typescript'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('MyType'); }); it('should merge root SDL string with output-level GraphQLSchema instance', async () => { const outputSchema = buildSchema(`type Post { id: ID! } type Query { posts: [Post] }`); const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, generates: { 'out1.ts': { schema: outputSchema, plugins: ['typescript'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('MyType'); expect(result[0].content).toContain('Post'); }); it('should work with documents when schema is a GraphQLSchema instance', async () => { const schema = buildSchema(SIMPLE_TEST_SCHEMA); const { result } = await executeCodegen({ schema, documents: `query root { f }`, generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'] }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('RootQuery'); }); it('should preserve custom scalars from a GraphQLSchema instance', async () => { const schema = buildSchema(` scalar DateTime type Query { now: DateTime } `); const { result } = await executeCodegen({ schema, generates: { 'out1.ts': { plugins: ['typescript'] }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('DateTime'); }); }); describe('Custom schema loader', () => { it('Should allow custom loaders to load schema on root level', async () => { await executeCodegen({ schema: [ { './tests/test-documents/schema.graphql': { loader: './tests/custom-loaders/custom-schema-loader.cjs', }, }, ], generates: { 'out1.ts': { plugins: ['typescript'] }, }, }); expect((global as any).CUSTOM_SCHEMA_LOADER_CALLED).toBeTruthy(); }); it('Should allow custom loaders to load schema on output level', async () => { await executeCodegen({ generates: { 'out1.ts': { schema: [ { './tests/test-documents/schema.graphql': { loader: './tests/custom-loaders/custom-schema-loader.cjs', }, }, ], plugins: ['typescript'], }, }, }); expect((global as any).CUSTOM_SCHEMA_LOADER_CALLED).toBeTruthy(); }); it('Should return error when invalid return value from loader', async () => { const { error } = await executeCodegen({ schema: [ { './tests/test-documents/schema.graphql': { loader: './tests/custom-loaders/invalid-return-value-schema-loader.cjs', }, }, ], generates: { 'out1.ts': { plugins: ['typescript'] }, }, }); expect(error.message).toContain('Failed to load schema'); }); it('Should return error when invalid module specified as loader', async () => { const { error } = await executeCodegen({ schema: [ { './tests/test-documents/schema.graphql': { loader: './tests/custom-loaders/non-existing.js', }, }, ], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); expect(error.message).toContain('Failed to load custom loader'); }); it('Should return error when invalid file declaration', async () => { const { error } = await executeCodegen({ schema: [ { './tests/test-documents/schema.graphql': { loader: './tests/custom-loaders/invalid-export.cjs', }, }, ], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); expect(error.message).toContain('Failed to load schema'); expect(error.message).toContain('Failed to load custom loader'); }); }); describe('Custom documents loader', () => { it('Should allow to use custom documents loader on root level', async () => { await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: [ { './tests/test-documents/valid.graphql': { loader: './tests/custom-loaders/custom-documents-loader.cjs', }, }, ], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); expect((global as any).CUSTOM_DOCUMENT_LOADER_CALLED).toBeTruthy(); }); it('Should allow custom loaders to load documents on output level', async () => { await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], generates: { 'out1.ts': { documents: [ { './tests/test-documents/valid.graphql': { loader: join(__dirname, './custom-loaders/custom-documents-loader.js'), }, }, ], plugins: ['typescript'], }, }, }); expect((global as any).CUSTOM_DOCUMENT_LOADER_CALLED).toBeTruthy(); }); it('Should return error when invalid return value from custom documents loader', async () => { const { error } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: [ { './tests/test-documents/valid.graphql': { loader: './tests/custom-loaders/invalid-return-value-documents-loader.cjs', }, }, ], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); expect(error.message).toContain('Unable to find any GraphQL type definitions for the following pointers'); }); it('Should return error when invalid module specified as loader', async () => { const { error } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: [ { './tests/test-documents/valid.graphql': { loader: './tests/custom-loaders/non-existing.js', }, }, ], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); expect(error.message).toContain('Failed to load custom loader'); }); it('Should return error when invalid file declaration', async () => { const { error } = await executeCodegen({ schema: ['./tests/test-documents/schema.graphql'], documents: [ { './tests/test-documents/valid.graphql': { loader: './tests/custom-loaders/invalid-export.cjs', }, }, ], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); expect(error.message).toContain('Failed to load custom loader'); }); }); it('should load schema with custom fetch', async () => { try { await executeCodegen({ schema: ['http://www.dummyschema.com/graphql'], customFetch: 'some-fetch#someFetchFn', documents: ['./tests/test-documents/valid.graphql'], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); } catch (error) { expect(error.message).toContain('Failed to load schema from http://www.dummyschema.com/graphql'); } expect((global as any).CUSTOM_FETCH_FN_CALLED).toBeTruthy(); }); it('should load schema with custom fetch function', async () => { let fetchCalledFor = null; async function myCustomFetch(url: string, _options?: RequestInit): Promise { fetchCalledFor = url; return Promise.resolve(new Response()); } try { await executeCodegen({ schema: ['http://www.dummyschema.com/graphql'], customFetch: myCustomFetch, documents: ['./tests/test-documents/valid.graphql'], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); } catch (error) { expect(error.message).toContain('Failed to load schema from http://www.dummyschema.com/graphql'); } expect(fetchCalledFor).toBe('http://www.dummyschema.com/graphql'); }); it('should evaluate glob expressions correctly', async () => { try { await executeCodegen({ schema: ['./tests/test-documents/*schema.graphql', '!./tests/test-documents/invalid-schema.graphql'], documents: [ './tests/test-documents/*.graphql', '!./tests/test-documents/invalid-*.graphql', '!./tests/test-documents/unused-*.graphql', ], generates: { 'out1.ts': { plugins: ['typescript'], }, }, }); } catch (e) { // eslint-disable-next-line no-console console.error(e); throw new Error('This should not throw as the invalid file is excluded via glob.'); } }); it('Should allow plugins to extend schema with custom root', async () => { try { const { result } = await executeCodegen({ schema: `schema { query: RootQuery } type MyType { f: String } type RootQuery { f: String }`, documents: `query root { f }`, generates: { 'out1.ts': { plugins: ['./tests/custom-plugins/extends-schema.js', './tests/custom-plugins/checks-extended-schema.js'], }, }, }); expect(result.length).toBe(1); } catch (e) { expect(e.message).not.toBe('Query root type must be provided.'); } }); it('Should allow plugin context to be accessed and modified', async () => { const { result } = await executeCodegen({ schema: [ { './tests/test-documents/schema.graphql': { loader: './tests/custom-loaders/custom-schema-loader-with-context.cjs', }, }, ], generates: { 'out1.ts': { plugins: ['./tests/custom-plugins/context.js'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('Hello world!'); }); it('Should sort the input schema', async () => { const nonSortedSchema = /* GraphQL */ ` type Query { d: String z: String a: String } type User { aa: String a: String } type A { s: String b: String } `; const { result } = await executeCodegen({ schema: [nonSortedSchema], generates: { 'out1.graphql': { plugins: ['schema-ast'], }, }, config: { sort: true, }, }); expect(result.length).toBe(1); expect(result[0].content).toBeSimilarStringTo(/* GraphQL */ ` type A { b: String s: String } type Query { a: String d: String z: String } type User { a: String aa: String } `); }); it('Handles weird errors due to invalid schema', async () => { const schema = /* GraphQL */ ` type Query { brrrt:1 } `; try { await executeCodegen({ schema: [schema], generates: { 'out1.graphql': { plugins: ['schema-ast'], }, }, }); } catch (error) { expect(error.message).toContain('Failed to load schema from'); } }); it('Should generate documents output even if prj1/documents and prj1/extensions/codegen/generate/xxx/documents are both definded with the same glob files', async () => { const prj1 = await createContext({ config: './tests/test-files/graphql.config.js', project: 'prj1', errorsOnly: true, overwrite: true, profile: true, require: [], silent: false, watch: false, }); const config = prj1.getConfig(); const { result } = await executeCodegen(config); expect(result[0].content).toContain('DocumentNode'); }); describe('Document Transform', () => { it('Should transform documents', async () => { const transform: Types.DocumentTransformFunction = ({ documents }) => { const newDocuments = [ { document: { ...documents[0].document, definitions: [ { ...documents[0].document.definitions[0], name: { kind: Kind.NAME, value: 'bar' }, } as OperationDefinitionNode, ], }, }, ]; return newDocuments; }; const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query foo { f }`, generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], documentTransforms: [{ transform }], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type BarQuery'); }); it('Should allow users to set config', async () => { const generateDocumentTransform: (config: { queryName: string }) => Types.DocumentTransformObject = ({ queryName, }) => { return { transform: ({ documents }) => { const newDocuments = [ { document: { ...documents[0].document, definitions: [ { ...documents[0].document.definitions[0], name: { kind: Kind.NAME, value: queryName }, } as OperationDefinitionNode, ], }, }, ]; return newDocuments; }, }; }; const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query foo { f }`, generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], documentTransforms: [generateDocumentTransform({ queryName: 'test' })], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type TestQuery'); }); it('Should transform documents when specifying files', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], documentTransforms: ['./tests/custom-document-transforms/document-transform.js'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type BarQuery'); }); it('Should allow users to set config when specifying files', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], documentTransforms: [ { './tests/custom-document-transforms/test-config.js': { queryName: 'test', }, }, ], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type TestQuery'); }); it('Should allow plugin context to be accessed and modified', async () => { const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query root { f }`, generates: { 'out1.ts': { documentTransforms: [ { transform: ({ pluginContext, documents }) => { pluginContext.myPluginInfo = 'world'; return documents; }, }, ], plugins: ['./tests/custom-plugins/document-transform-context.js'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('Hello world!'); }); it('should return error an understandable error if it fails.', async () => { const { error } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query foo { f }`, generates: { 'out1.ts': { plugins: ['typescript'], documentTransforms: [ { transform: () => { throw new Error('Something Wrong!'); }, }, ], }, }, }); expect(error.message).toContain('DocumentTransform "the element at index 0 of the documentTransforms" failed'); expect(error.message).toContain('Something Wrong!'); }); it('Should transform documents with client-preset', async () => { const transform: Types.DocumentTransformFunction = ({ documents }) => { const newDocuments = [ { document: { ...documents[0].document, definitions: [ { ...documents[0].document.definitions[0], name: { kind: Kind.NAME, value: 'bar' }, } as OperationDefinitionNode, ], }, }, ]; return newDocuments; }; const { result } = await executeCodegen({ schema: SIMPLE_TEST_SCHEMA, documents: `query foo { f }`, generates: { './src/gql/': { preset: 'client', documentTransforms: [{ transform }], }, }, }); const fileOutput = result.find(file => file.filename === './src/gql/graphql.ts'); expect(fileOutput.content).toContain('export type BarQuery'); }); }); it('should not run out of memory when generating very complex types (issue #7720)', async () => { const { result } = await executeCodegen({ schema: ['../../dev-test/gatsby/schema.graphql'], documents: ['../../dev-test/gatsby/fragments.ts'], config: { extractAllFieldsToTypes: true, dedupeOperationSuffix: true, }, generates: { 'out1.ts': { plugins: ['typescript', 'typescript-operations'], }, }, }); expect(result.length).toBe(1); expect(result[0].content).toContain('export type WpCoreImageBlockForGalleryFragment = '); }); }); ================================================ FILE: packages/graphql-codegen-cli/tests/config.spec.ts ================================================ import { buildSchema } from 'graphql'; import { createContext, ensureContext, CodegenContext } from '../src/index.js'; describe('Codegen config - Context', () => { it('loads and merge multiple schemas when using GraphQL config', async () => { const context = await createContext({ config: './tests/test-files/graphql.config.js', project: 'prj1', errorsOnly: true, overwrite: true, profile: true, require: [], silent: false, watch: false, }); const schema1 = /* GraphQL */ ` type Query scalar Date `; const schema2 = /* GraphQL */ ` extend type Query { me: User } type User { id: ID! name: String! createdAt: Date! } `; const schema3 = /* GraphQL */ ` extend type Query { media: Media } interface Media { id: ID! } type Image implements Media { id: ID! url: String! } type Book implements Media { id: ID! title: String! } `; const mergedSchema = await context.loadSchema([schema1, schema2, schema3]); const typeMap = mergedSchema.getTypeMap(); expect(typeMap['Query']).toBeDefined(); expect(typeMap['Date']).toBeDefined(); expect(typeMap['User']).toBeDefined(); expect(typeMap['Media']).toBeDefined(); expect(typeMap['Image']).toBeDefined(); expect(typeMap['Book']).toBeDefined(); }); it('loads and merge multiple schemas when using input config', async () => { const context = ensureContext({ generates: {}, }); const schema1 = /* GraphQL */ ` type Mutation scalar DateTime `; const schema2 = /* GraphQL */ ` extend type Mutation { createUser: User } type User { id: ID! createdAt: DateTime! } `; const mergedSchema = await context.loadSchema([schema1, schema2]); const typeMap = mergedSchema.getTypeMap(); expect(typeMap['Mutation']).toBeDefined(); expect(typeMap['DateTime']).toBeDefined(); expect(typeMap['User']).toBeDefined(); }); it('passes nested config values to graphql-config schema loader', async () => { const loadSchemaSpy = vi.fn().mockResolvedValue(buildSchema('type Query { _: Boolean }')); const project = { extension: vi.fn().mockReturnValue({ generates: {}, config: { inputValueDeprecation: true, }, }), schema: ['http://example.com/graphql'], documents: [], loadSchema: loadSchemaSpy, loadDocuments: vi.fn(), }; const graphqlConfig = { filepath: '/tmp/graphql.config.ts', dirpath: '/tmp', getProject: vi.fn().mockReturnValue(project), } as any; const context = new CodegenContext({ graphqlConfig }); await context.loadSchema(['http://example.com/graphql']); expect(loadSchemaSpy).toHaveBeenCalledWith( ['http://example.com/graphql'], 'GraphQLSchema', expect.objectContaining({ inputValueDeprecation: true, }) ); }); }); ================================================ FILE: packages/graphql-codegen-cli/tests/custom-document-transforms/document-transform.js ================================================ module.exports = { transform: ({ documents }) => { const newDocuments = [ { document: { ...documents[0].document, definitions: [ { ...documents[0].document.definitions[0], name: { kind: 'Name', value: 'bar' }, }, ], }, }, ]; return newDocuments; }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-document-transforms/test-config.js ================================================ module.exports = { transform: ({ documents, config }) => { const newDocuments = [ { document: { ...documents[0].document, definitions: [ { ...documents[0].document.definitions[0], name: { kind: 'Name', value: config.queryName }, }, ], }, }, ]; return newDocuments; }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-loaders/custom-documents-loader.cjs ================================================ const { parse } = require('graphql'); const { readFileSync } = require('fs'); const { join } = require('path'); module.exports = function (docString, _config) { global.CUSTOM_DOCUMENT_LOADER_CALLED = true; return parse(readFileSync(join(process.cwd(), docString), 'utf8')); }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-loaders/custom-schema-loader-with-context.cjs ================================================ const { buildSchema } = require('graphql'); const { readFileSync } = require('fs'); const { join } = require('path'); module.exports = function (schemaString, config) { config.pluginContext.hello = 'world'; return buildSchema(readFileSync(join(process.cwd(), schemaString), 'utf8')); }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-loaders/custom-schema-loader.cjs ================================================ const { buildSchema } = require('graphql'); const { readFileSync } = require('fs'); const { join } = require('path'); module.exports = function (schemaString, _config) { global.CUSTOM_SCHEMA_LOADER_CALLED = true; return buildSchema(readFileSync(join(process.cwd(), schemaString), 'utf8')); }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-loaders/invalid-export.cjs ================================================ module.exports = 'oops'; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-loaders/invalid-return-value-documents-loader.cjs ================================================ module.exports = function (schemaString, _config) { return schemaString; }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-loaders/invalid-return-value-schema-loader.cjs ================================================ module.exports = function (schemaString, _config) { return schemaString; }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-plugins/basic.js ================================================ module.exports = { plugin(_schema, _documents, _config) { return 'plugin'; }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-plugins/checks-extended-schema.js ================================================ module.exports = { plugin(schema, _documents, _config) { return ` Should have the Extension type: '${schema.getType('Extension')}' `; }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-plugins/context.js ================================================ module.exports = { plugin: (_schema, _documents, _config, { pluginContext }) => { return `Hello ${pluginContext.hello}!`; }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-plugins/document-transform-context.js ================================================ module.exports = { plugin: (_schema, _documents, _config, { pluginContext }) => { return `Hello ${pluginContext.myPluginInfo}!`; }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-plugins/extends-schema-fn.js ================================================ module.exports = { plugin(schema, _documents, _config) { return Object.keys(schema.getTypeMap()).join(', '); }, addToSchema: c => `type ${c.test} { f: String }`, }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-plugins/extends-schema.js ================================================ module.exports = { plugin(schema, _documents, _config) { return Object.keys(schema.getTypeMap()).join(','); }, addToSchema: `type Extension { f: String }`, }; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-plugins/invalid.js ================================================ module.exports = {}; ================================================ FILE: packages/graphql-codegen-cli/tests/custom-plugins/validation.js ================================================ module.exports = { plugin(_schema, _documents, _config) { return 'plugin'; }, validate() { throw new Error('Invalid!'); }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/dummy-require.js ================================================ // Just set something in global so the test can verify that it got set and thereby know that this module was loaded global.dummyWasLoaded = true; ================================================ FILE: packages/graphql-codegen-cli/tests/generate-and-save.spec.ts ================================================ import { dirname, join } from 'path'; import logSymbols from 'log-symbols'; import { Types } from '@graphql-codegen/plugin-helpers'; import '@graphql-codegen/testing'; import makeDir from 'make-dir'; import { createContext } from '../src/config.js'; import { generate } from '../src/generate-and-save.js'; import * as fs from '../src/utils/file-system.js'; import { setLogger } from '../src/utils/logger.js'; const SIMPLE_TEST_SCHEMA = `type MyType { f: String } type Query { f: String }`; const inputFile = join(__dirname, '../temp/input-graphql.tsx'); const outputFile = join(__dirname, '../temp/output-graphql.tsx'); const writeSpy = vi.spyOn(fs, 'writeFile'); const readSpy = vi.spyOn(fs, 'readFile'); const outputErrorSpy = vi.spyOn(process.stderr, 'write'); describe('generate-and-save', () => { beforeEach(() => { // We must call .spyOn and .mockReset these individually instead of vi.resetAllMocks // because there's a `vi.spyOn(process, 'cwd').mockImplementation(() => __dirname);` in vitest.setup.ts // // If we called vi.resetAllMocks, the cwd spy is reset too! // That would cause all `schema` and `documents`paths to be from the root of the workspace writeSpy.mockReset(); readSpy.mockReset(); outputErrorSpy.mockReset(); }); test('allow to specify overwrite for specific output (should write file)', async () => { const filename = 'overwrite.ts'; writeSpy.mockImplementation(() => Promise.resolve()); const output = await generate( { schema: SIMPLE_TEST_SCHEMA, overwrite: false, generates: { [filename]: { overwrite: true, schema: ` type OtherType { a: String } `, plugins: ['typescript'], }, }, }, true ); expect(output.length).toBe(1); // makes sure it writes a new file expect(writeSpy).toHaveBeenCalled(); }); test('allow to specify overwrite for specific output (should not write file)', async () => { const filename = 'overwrite.ts'; writeSpy.mockImplementation(() => Promise.resolve()); readSpy.mockImplementation(async () => ''); // forces file to exist const output = await generate( { schema: SIMPLE_TEST_SCHEMA, overwrite: true, generates: { [filename]: { overwrite: false, schema: ` type OtherType { a: String } `, plugins: ['typescript'], }, }, }, true ); expect(output.length).toBe(1); // makes sure it checks if file is there expect(readSpy).toHaveBeenCalledWith(filename); // makes sure it doesn't write a new file expect(writeSpy).not.toHaveBeenCalled(); }); test('should use global overwrite option and write a file', async () => { const filename = 'overwrite.ts'; writeSpy.mockImplementation(() => Promise.resolve()); const output = await generate( { schema: SIMPLE_TEST_SCHEMA, overwrite: true, generates: { [filename]: { schema: ` type OtherType { a: String } `, plugins: ['typescript'], }, }, }, true ); expect(output.length).toBe(1); // makes sure it writes a new file expect(writeSpy).toHaveBeenCalled(); }); test('should use global overwrite option and not write a file', async () => { const filename = 'overwrite.ts'; writeSpy.mockImplementation(() => Promise.resolve()); readSpy.mockImplementation(async () => ''); // forces file to exist const output = await generate( { schema: SIMPLE_TEST_SCHEMA, overwrite: false, generates: { [filename]: { schema: ` type OtherType { a: String } `, plugins: ['typescript'], }, }, }, true ); expect(output.length).toBe(1); // makes sure it checks if file is there expect(readSpy).toHaveBeenCalledWith(filename); // makes sure it doesn't write a new file expect(writeSpy).not.toHaveBeenCalled(); }); test('should overwrite a file by default', async () => { const filename = 'overwrite.ts'; writeSpy.mockImplementation(() => Promise.resolve()); readSpy.mockImplementation(() => Promise.resolve('')); readSpy.mockImplementation(async _f => ''); const output = await generate( { schema: SIMPLE_TEST_SCHEMA, generates: { [filename]: { schema: /* GraphQL */ ` type OtherType { a: String } `, plugins: ['typescript'], }, }, }, true ); expect(output.length).toBe(1); // makes sure it doesn't write a new file expect(writeSpy).toHaveBeenCalled(); }); test('should override generated files', async () => { vi.unmock('fs'); const fs = await import('fs'); makeDir.sync(dirname(outputFile)); if (fs.existsSync(outputFile)) { fs.unlinkSync(outputFile); } fs.writeFileSync( inputFile, ` import gql from 'graphql-tag'; const MyQuery = gql\`query MyQuery { f }\`; `, 'utf8' ); const generateOnce: () => Promise = () => generate( { schema: SIMPLE_TEST_SCHEMA, documents: inputFile, generates: { [outputFile]: { plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo'], }, }, }, true ); const [firstOutput] = await generateOnce(); fs.writeFileSync(firstOutput.filename, firstOutput.content); await generateOnce(); }); test('should extract a document from the gql tag (imported from apollo-server)', async () => { const filename = 'overwrite.ts'; writeSpy.mockImplementation(() => Promise.resolve()); const output = await generate( { schema: './tests/test-files/schema-dir/gatsby-and-custom-parsers/apollo-server.ts', generates: { [filename]: { plugins: ['typescript'], }, }, }, true ); expect(output.length).toBe(1); expect(output[0].content).toMatch('Used apollo-server'); // makes sure it doesn't write a new file expect(writeSpy).toHaveBeenCalled(); }); test('should allow to alter the content with the beforeOneFileWrite hook', async () => { const filename = 'modify.ts'; writeSpy.mockImplementation(() => Promise.resolve()); const output = await generate( { schema: SIMPLE_TEST_SCHEMA, generates: { [filename]: { plugins: ['typescript'], hooks: { beforeOneFileWrite: [() => 'new content'], }, }, }, }, true ); expect(output.length).toBe(1); expect(output[0].content).toMatch('new content'); // makes sure it doesn't write a new file expect(writeSpy).toHaveBeenCalled(); }); describe('Errors when loading pointers', () => { const originalNodeEnv = process.env.NODE_ENV; beforeEach(() => { // By default, the NODE_ENV is set to 'test', and this is used to silent console errors. // For these tests below, we want to see what's being logged out to console errors. process.env.NODE_ENV = 'not_test_so_error'; vi.spyOn(process.stdout, 'write').mockImplementation(() => true); }); afterEach(() => { process.env.NODE_ENV = originalNodeEnv; }); test('Schema syntax error - should print native GraphQLError', async () => { expect.assertions(1); outputErrorSpy.mockImplementation(() => true); try { await generate( { verbose: true, schema: './tests/test-files/schema-dir/error-schema.graphql', generates: { 'src/test.ts': { plugins: ['typescript'], }, }, }, false ); } catch { const cwd = process.cwd(); // cwd is different for every machine, remember to replace local path with this after updating snapshot expect(outputErrorSpy.mock.calls[0][0]).toMatchInlineSnapshot(` "[FAILED] Failed to load schema from ./tests/test-files/schema-dir/error-schema.graphql: [FAILED] Syntax Error: Expected Name, found "!". [FAILED] ${cwd}/tests/test-files/schema-dir/error-schema.graphql:2:15 [FAILED] 1 | type Query { [FAILED] 2 | foo: String!! [FAILED] | ^ [FAILED] 3 | } [FAILED] GraphQL Code Generator supports: [FAILED] - ES Modules and CommonJS exports (export as default or named export "schema") [FAILED] - Introspection JSON File [FAILED] - URL of GraphQL endpoint [FAILED] - Multiple files with type definitions (glob expression) [FAILED] - String in config file [FAILED] Try to use one of above options and run codegen again. " `); } }); test('Document syntax error - should print native GraphQLError', async () => { expect.assertions(1); outputErrorSpy.mockImplementation(() => true); try { await generate( { verbose: true, schema: './tests/test-files/schema-dir/schema.ts', documents: './tests/test-files/error-document.graphql', generates: { 'src/test.ts': { plugins: ['typescript'], }, }, }, false ); } catch { const cwd = process.cwd(); // cwd is different for every machine, remember to replace local path with this after updating snapshot expect(outputErrorSpy.mock.calls[0][0]).toMatchInlineSnapshot(` "[FAILED] Failed to load documents from ./tests/test-files/error-document.graphql: [FAILED] Syntax Error: Expected "{", found . [FAILED] ${cwd}/tests/test-files/error-document.graphql:2:1 [FAILED] 1 | query [FAILED] 2 | [FAILED] | ^ " `); } }); test('No documents found - should throw error by default', async () => { expect.assertions(1); outputErrorSpy.mockImplementation(() => true); try { await generate( { verbose: true, schema: './tests/test-files/schema-dir/schema.ts', documents: './tests/test-files/document-file-does-not-exist.graphql', generates: { 'src/test.ts': { plugins: ['typescript'], }, }, }, false ); } catch { expect(outputErrorSpy.mock.calls[0][0]).toMatchInlineSnapshot(` " [FAILED] Unable to find any GraphQL type definitions for the following pointers: [FAILED] - ./tests/test-files/document-file-does-not-exist.graphql " `); } }); test('No documents found - should not fail if ignoreNoDocuments=true', async () => { outputErrorSpy.mockImplementation(() => true); await generate( { verbose: true, ignoreNoDocuments: true, schema: './tests/test-files/schema-dir/schema.ts', documents: './tests/test-files/document-file-does-not-exist.graphql', generates: { 'src/test.ts': { plugins: ['typescript'], }, }, }, false ); expect(outputErrorSpy).not.toHaveBeenCalled(); }); test('No documents found - GraphQL Config - should throw error by default', async () => { outputErrorSpy.mockImplementation(() => true); expect.assertions(1); try { const config = await createContext({ config: './tests/test-files/graphql.config.no-doc.js', project: undefined, errorsOnly: true, overwrite: true, profile: true, require: [], silent: false, watch: false, }); await generate(config, false); } catch { expect(outputErrorSpy.mock.calls[0][0]).toMatchInlineSnapshot(` " [FAILED] Unable to find any GraphQL type definitions for the following pointers: [FAILED] - ../test-documents/empty.graphql " `); } }); test('No documents found - GraphQL Config - should not fail if ignoreNoDocuments=true', async () => { outputErrorSpy.mockImplementation(() => true); vi.spyOn(fs, 'writeFile').mockImplementation(() => Promise.resolve()); const config = await createContext({ config: './tests/test-files/graphql.config.no-doc-ignored.js', project: undefined, errorsOnly: true, overwrite: true, profile: true, require: [], silent: false, watch: false, }); await generate(config, false); expect(outputErrorSpy).not.toHaveBeenCalled(); }); }); describe('config.allowPartialOutputs', () => { const mockLogger: any = { warn: vi.fn(), error: vi.fn(), }; beforeEach(() => { setLogger(mockLogger); vi.resetAllMocks(); }); test('when allowPartialOutputs=true - writes partial success and does not throw', async () => { const invalidSchema = /* GraphQL */ ` type A { id: WRONG_TYPE! } `; const validSchema = /* GraphQL */ ` type B { id: ID! } `; const output = await generate( { allowPartialOutputs: true, generates: { 'src/a.ts': { schema: invalidSchema, plugins: ['typescript'], }, 'src/b.ts': { schema: validSchema, plugins: ['typescript'], }, }, }, false ); expect(output.length).toBe(1); expect(output[0].filename).toBe('src/b.ts'); expect(mockLogger.warn.mock.calls[0][0]).toBeSimilarStringTo( `${logSymbols.warning} One or more errors occurred, some files were generated. To prevent any output on errors, set config.allowPartialOutputs=false` ); }); test('when allowPartialOutputs=true - complete failure throws', async () => { expect.assertions(2); try { const invalidSchema = /* GraphQL */ ` type A { id: WRONG_TYPE! } `; await generate( { allowPartialOutputs: true, generates: { 'src/a.ts': { schema: invalidSchema, plugins: ['typescript'], }, 'src/b.ts': { schema: invalidSchema, plugins: ['typescript'], }, }, }, false ); } catch { expect(mockLogger.warn).not.toHaveBeenCalled(); expect(mockLogger.error).not.toHaveBeenCalled(); } }); test('when allowPartialOutputs=false - does not write partial success and throws', async () => { expect.assertions(1); const invalidSchema = /* GraphQL */ ` type A { id: WRONG_TYPE! } `; const validSchema = /* GraphQL */ ` type B { id: ID! } `; try { await generate( { allowPartialOutputs: false, generates: { 'src/a.ts': { schema: invalidSchema, plugins: ['typescript'], }, 'src/b.ts': { schema: validSchema, plugins: ['typescript'], }, }, }, false ); } catch { expect(mockLogger.error.mock.calls[0][0]).toBeSimilarStringTo( `${logSymbols.error} One or more errors occurred, no files were generated. To allow output on errors, set config.allowPartialOutputs=true` ); } }); test('when allowPartialOutputs=false - complete failure throws', async () => { expect.assertions(2); try { const invalidSchema = /* GraphQL */ ` type A { id: WRONG_TYPE! } `; await generate( { allowPartialOutputs: false, generates: { 'src/a.ts': { schema: invalidSchema, plugins: ['typescript'], }, 'src/b.ts': { schema: invalidSchema, plugins: ['typescript'], }, }, }, false ); } catch { expect(mockLogger.warn).not.toHaveBeenCalled(); expect(mockLogger.error).not.toHaveBeenCalled(); } }); }); }); ================================================ FILE: packages/graphql-codegen-cli/tests/init.spec.ts ================================================ import { resolve } from 'path'; import bddStdin from 'bdd-stdin'; import { fs, vol } from 'memfs'; import { bold } from '../src/init/helpers.js'; import { init } from '../src/init/index.js'; import { getApplicationTypeChoices, getPluginChoices } from '../src/init/questions.js'; import { guessTargets } from '../src/init/targets.js'; import { Tags } from '../src/init/types.js'; vi.mock('../src/utils/get-latest-version.ts', () => { return { getLatestVersion: () => Promise.resolve('1.0.0') }; }); vi.mock('fs', () => require('./__mocks__/fs.cjs')); const { version } = require('../package.json'); const SELECT = ' '; // checkbox const ENTER = '\n'; // const DOWN = bddStdin.keys.down; const packageJson = { withAngular: JSON.stringify({ version, dependencies: { '@angular/core': 'x.x.x', }, }), withTypescript: JSON.stringify({ version, devDependencies: { typescript: 'x.x.x', }, }), withReact: JSON.stringify({ version, dependencies: { react: 'x.x.x', }, }), withFlow: JSON.stringify({ version, devDependencies: { flow: 'x.x.x', }, }), withStencil: JSON.stringify({ version, dependencies: { '@stencil/core': 'x.x.x', }, }), withVue: JSON.stringify({ version, dependencies: { vue: 'x.x.x', }, }), withReactQuery: JSON.stringify({ version, dependencies: { '@tanstack/react-query': 'x.x.x', }, }), withSWR: JSON.stringify({ version, dependencies: { swr: 'x.x.x', }, }), withGraphqlRequest: JSON.stringify({ version, dependencies: { 'graphql-request': 'x.x.x', }, }), }; describe('init', () => { beforeEach(() => { // make sure terminal don't get noisy vi.spyOn(process.stdout, 'write').mockImplementation(() => true); vol.reset(); }); afterEach(() => { vi.clearAllMocks(); }); describe('guessTargets()', () => { it('should guess angular projects', async () => { vol.fromJSON({ ['package.json']: packageJson.withAngular }, process.cwd()); const targets = await guessTargets(); expect(targets.Angular).toEqual(true); }); it('should guess typescript projects', async () => { vol.fromJSON({ ['package.json']: packageJson.withTypescript }, process.cwd()); const targets = await guessTargets(); expect(targets.TypeScript).toEqual(true); }); it('should guess react projects', async () => { vol.fromJSON({ ['package.json']: packageJson.withReact }, process.cwd()); const targets = await guessTargets(); expect(targets.React).toEqual(true); }); it('should guess stencil projects', async () => { vol.fromJSON({ ['package.json']: packageJson.withStencil }, process.cwd()); const targets = await guessTargets(); expect(targets.Stencil).toEqual(true); }); it('should guess flow projects', async () => { vol.fromJSON({ ['package.json']: packageJson.withFlow }, process.cwd()); const targets = await guessTargets(); expect(targets.Flow).toEqual(true); }); it('should guess vue projects', async () => { vol.fromJSON({ ['package.json']: packageJson.withVue }, process.cwd()); const targets = await guessTargets(); expect(targets.Vue).toEqual(true); }); it('should guess graphql-request projects', async () => { vol.fromJSON({ ['package.json']: packageJson.withGraphqlRequest }, process.cwd()); const targets = await guessTargets(); expect(targets.graphqlRequest).toEqual(true); }); }); describe('plugins suggestions for client-side setup', () => { it('should use angular related plugins when @angular/core is found', async () => { vol.fromJSON({ ['package.json']: packageJson.withAngular }, process.cwd()); const writeFileSpy = vi.spyOn(fs, 'writeFileSync'); // silent vi.spyOn(console, 'log').mockImplementation(() => {}); useInputs({ onTarget: [ENTER], // confirm target onSchema: [ENTER], // use default onDocuments: [ENTER], onPlugins: [ENTER], // use selected packages onOutput: [ENTER], // use default output path onIntrospection: ['n', ENTER], // no introspection, onConfig: [ENTER], // use default config path onScript: ['graphql', ENTER], // use custom npm script }); await init(); expect(writeFileSpy).toHaveBeenCalledTimes(2); const pkg = JSON.parse(writeFileSpy.mock.calls[1][1] as string); const config = writeFileSpy.mock.calls[0][1] as string; expect(config).toMatchSnapshot(); // expected plugins expect(pkg.devDependencies).toEqual({ '@graphql-codegen/cli': '1.0.0', '@graphql-codegen/typescript-apollo-angular': '1.0.0', }); }); it('should use react related plugins when react is found', async () => { vol.fromJSON({ ['package.json']: packageJson.withReact }, process.cwd()); const writeFileSpy = vi.spyOn(fs, 'writeFileSync'); // silent vi.spyOn(console, 'log').mockImplementation(() => {}); useInputs({ onTarget: [ENTER], // confirm react target onSchema: [ENTER], // use default onDocuments: [ENTER], onOutput: [ENTER], // use default output path onIntrospection: ['n', ENTER], // no introspection, onConfig: [ENTER], // use default config path onScript: ['graphql', ENTER], // use custom npm script }); await init(); expect(writeFileSpy).toHaveBeenCalledTimes(2); const pkg = JSON.parse(writeFileSpy.mock.calls[1][1] as string); const config = writeFileSpy.mock.calls[0][1] as string; expect(config).toMatchSnapshot(); // expected plugins expect(pkg.devDependencies).toHaveProperty('@graphql-codegen/cli'); expect(pkg.devDependencies).toHaveProperty('@graphql-codegen/client-preset'); // should not have other plugins expect(Object.keys(pkg.devDependencies)).toHaveLength(2); }); it('should use stencil related plugins when @stencil/core is found', async () => { vol.fromJSON({ ['package.json']: packageJson.withStencil }, process.cwd()); const writeFileSpy = vi.spyOn(fs, 'writeFileSync'); // silent vi.spyOn(console, 'log').mockImplementation(() => {}); useInputs({ onTarget: [ENTER], // confirm stencil target onSchema: [ENTER], // use default onDocuments: [ENTER], onPlugins: [ENTER], // use selected packages onOutput: [ENTER], // use default output path onIntrospection: ['n', ENTER], // no introspection, onConfig: [ENTER], // use default config path onScript: ['graphql', ENTER], // use custom npm script }); await init(); expect(writeFileSpy).toHaveBeenCalledTimes(2); const pkg = JSON.parse(writeFileSpy.mock.calls[1][1] as string); const config = writeFileSpy.mock.calls[0][1] as string; expect(config).toMatchSnapshot(); // expected plugins expect(pkg.devDependencies).toHaveProperty('@graphql-codegen/typescript'); expect(pkg.devDependencies).toHaveProperty('@graphql-codegen/typescript-operations'); expect(pkg.devDependencies).toHaveProperty('@graphql-codegen/typescript-stencil-apollo'); // should not have other plugins expect(Object.keys(pkg.devDependencies)).toHaveLength(4); }); }); describe('plugins suggestions non client-side setup', () => { it('should use typescript related plugins when typescript is found (node)', async () => { vol.fromJSON({ ['package.json']: packageJson.withTypescript }, process.cwd()); const writeFileSpy = vi.spyOn(fs, 'writeFileSync'); // silent vi.spyOn(console, 'log').mockImplementation(() => {}); useInputs({ onTarget: [SELECT, ENTER], // confirm api target onSchema: [ENTER], // use default onPlugins: [ENTER], // use selected packages onOutput: [ENTER], // use default output path onIntrospection: ['n', ENTER], // no introspection, onConfig: [ENTER], // use default config path onScript: ['graphql', ENTER], // use custom npm script }); await init(); expect(writeFileSpy).toHaveBeenCalledTimes(2); const pkg = JSON.parse(writeFileSpy.mock.calls[1][1] as string); const config = writeFileSpy.mock.calls[0][1] as string; expect(config).toMatchSnapshot(); // expected plugins expect(pkg.devDependencies).toHaveProperty('@graphql-codegen/typescript'); expect(pkg.devDependencies).toHaveProperty('@graphql-codegen/typescript-resolvers'); // should not have other plugins expect(Object.keys(pkg.devDependencies)).toHaveLength(4); // 3 - because we have typescript package in devDeps }); }); it('should have few default values for Angular', async () => { vol.fromJSON({ ['package.json']: packageJson.withReact }, process.cwd()); const writeFileSpy = vi.spyOn(fs, 'writeFileSync'); const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); const defaults = { config: 'codegen.ts', }; useInputs({ onTarget: [ENTER], // confirm angular target onSchema: [ENTER], // use default onDocuments: [ENTER], onOutput: [ENTER], // use default output path onIntrospection: [ENTER], // no introspection, onConfig: [ENTER], // use default config path onScript: ['graphql', ENTER], // use custom npm script }); await init(); const configFile = writeFileSpy.mock.calls[0][0] as string; const config = writeFileSpy.mock.calls[0][1] as string; const pkg = JSON.parse(writeFileSpy.mock.calls[1][1] as string); expect(pkg.scripts.graphql).toEqual(`graphql-codegen --config codegen.ts`); expect(configFile).toEqual(resolve(process.cwd(), defaults.config)); expect(config).toMatchSnapshot(); expect(logSpy.mock.calls[2][0]).toContain(`Config file generated at ${bold(defaults.config)}`); }); it('should have few default values for React', async () => { vol.fromJSON({ ['package.json']: packageJson.withReact }, process.cwd()); const writeFileSpy = vi.spyOn(fs, 'writeFileSync'); const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); const options = { script: 'graphql', schema: './schema.ts', documents: 'graphql/**/*.graphql', output: 'graphql/index.ts', config: 'app-codegen.yml', }; useInputs({ onTarget: [ENTER], // confirm target onSchema: [options.schema, ENTER], // use default onDocuments: [options.documents, ENTER], onOutput: [options.output, ENTER], // use default output path onIntrospection: ['y', ENTER], // with introspection, onConfig: [options.config, ENTER], // use default config path onScript: [options.script, ENTER], // use custom npm script }); await init(); const configFile = writeFileSpy.mock.calls[0][0] as string; const config = writeFileSpy.mock.calls[0][1] as string; const pkg = JSON.parse(writeFileSpy.mock.calls[1][1] as string); expect(pkg.scripts[options.script]).toEqual(`graphql-codegen --config ${options.config}`); expect(configFile).toEqual(resolve(process.cwd(), options.config)); expect(config).toMatchSnapshot(); expect(logSpy.mock.calls[2][0]).toContain(`Config file generated at ${bold(options.config)}`); }); it('custom setup', async () => { vol.fromJSON({ ['package.json']: packageJson.withReact }, process.cwd()); const { init } = await import('../src/init/index.js'); const writeFileSpy = vi.spyOn(fs, 'writeFileSync'); const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); const documents = 'graphql/*.ts'; const script = 'generate:types'; useInputs({ onTarget: [ENTER], // confirm target onSchema: [ENTER], // use default onDocuments: [documents, ENTER], onOutput: [ENTER], // use default output path onIntrospection: ['y', ENTER], // no introspection, onConfig: [ENTER], // use default config path onScript: [script, ENTER], // use custom npm script }); await init(); expect(writeFileSpy).toHaveBeenCalledTimes(2); const pkg = JSON.parse(writeFileSpy.mock.calls[1][1] as string); const config = writeFileSpy.mock.calls[0][1] as string; // config expect(config).toMatchSnapshot(); // script name should match what we provided expect(pkg.scripts[script]).toEqual('graphql-codegen --config codegen.ts'); // expected plugins expect(pkg.devDependencies).toHaveProperty('@graphql-codegen/introspection'); // should not have these plugins expect(pkg.devDependencies).not.toHaveProperty('@graphql-codegen/typescript-resolvers'); // logs const welcomeMsg = logSpy.mock.calls[0][0]; const doneMsg = logSpy.mock.calls[2][0]; expect(welcomeMsg).toContain(`Welcome to ${bold('GraphQL Code Generator')}`); expect(doneMsg).toContain(`Config file generated at ${bold('codegen.ts')}`); expect(doneMsg).toContain(bold('$ npm install')); expect(doneMsg).toContain(bold(`$ npm run ${script}`)); }); describe('plugin choices', () => { function getAvailable(tags: Tags[]): string[] { return getPluginChoices(tags).map((c: any) => c.value.value); } function getSelected(tags: Tags[]): string[] { return getPluginChoices(tags) .filter((c: any) => c.checked) .map((c: any) => c.value.value); } function getPlugins(targets: Tags[]) { const tags: Tags[] = getApplicationTypeChoices({ [Tags.angular]: targets.includes(Tags.angular), [Tags.react]: targets.includes(Tags.react), [Tags.stencil]: targets.includes(Tags.stencil), [Tags.client]: targets.includes(Tags.client), [Tags.node]: targets.includes(Tags.node), [Tags.typescript]: targets.includes(Tags.typescript), [Tags.flow]: targets.includes(Tags.flow), [Tags.vue]: targets.includes(Tags.vue), [Tags.graphqlRequest]: targets.includes(Tags.graphqlRequest), }) .filter(c => c.checked) .reduce((all, choice) => all.concat(choice.value), []); return { available: getAvailable(tags), selected: getSelected(tags), }; } it('node', () => { const { available, selected } = getPlugins([Tags.node]); // available expect(available).toHaveLength(6); expect(available).toContainEqual('typescript'); expect(available).toContainEqual('typescript-resolvers'); expect(available).toContainEqual('typescript-mongodb'); expect(available).toContainEqual('typescript-document-nodes'); expect(available).toContainEqual('flow'); expect(available).toContainEqual('flow-resolvers'); // selected expect(selected).toHaveLength(0); }); it('node + typescript', () => { const { selected, available } = getPlugins([Tags.node, Tags.typescript]); // available expect(available).toHaveLength(4); expect(available).toContainEqual('typescript'); expect(available).toContainEqual('typescript-resolvers'); expect(available).toContainEqual('typescript-mongodb'); expect(available).toContainEqual('typescript-document-nodes'); // selected expect(selected).toHaveLength(2); expect(selected).toContainEqual('typescript'); expect(selected).toContainEqual('typescript-resolvers'); }); it('node + flow', () => { const { selected, available } = getPlugins([Tags.node, Tags.flow]); // available expect(available).toHaveLength(2); expect(available).toContainEqual('flow'); expect(available).toContainEqual('flow-resolvers'); // selected expect(selected).toHaveLength(2); expect(selected).toContainEqual('flow'); expect(selected).toContainEqual('flow-resolvers'); }); it('angular', () => { const { selected, available } = getPlugins([Tags.angular]); // available expect(available).toHaveLength(2); expect(available).toEqual(['fragment-matcher', 'typescript-apollo-angular']); // selected expect(selected).toHaveLength(1); expect(selected).toEqual(['typescript-apollo-angular']); }); it('react', () => { const { selected, available } = getPlugins([Tags.react]); // available expect(available).toHaveLength(2); expect(available).toContainEqual('fragment-matcher'); expect(available).toContainEqual('urql-introspection'); // selected expect(selected).toHaveLength(0); }); it('react + flow', () => { const { selected, available } = getPlugins([Tags.react, Tags.flow]); // available expect(available).toHaveLength(4); expect(available).toContainEqual('flow'); expect(available).toContainEqual('flow-operations'); expect(available).toContainEqual('fragment-matcher'); // selected expect(selected).toHaveLength(2); expect(selected).toContainEqual('flow'); expect(selected).toContainEqual('flow-operations'); }); it('stencil', () => { const { selected, available } = getPlugins([Tags.stencil]); // available expect(available).toHaveLength(7); expect(available).toContainEqual('typescript'); expect(available).toContainEqual('typescript-operations'); expect(available).toContainEqual('typescript-stencil-apollo'); expect(available).toContainEqual('typescript-graphql-files-modules'); expect(available).toContainEqual('typescript-document-nodes'); expect(available).toContainEqual('fragment-matcher'); // selected expect(selected).toHaveLength(3); expect(selected).toContainEqual('typescript'); expect(selected).toContainEqual('typescript-operations'); expect(selected).toContainEqual('typescript-stencil-apollo'); }); }); }); function useInputs(inputs: { onTarget: string[]; onSchema: string[]; onDocuments?: string[]; onPlugins?: string[]; onOutput: string[]; onIntrospection: string[]; onConfig: string[]; onScript: string[]; }) { bddStdin( [].concat( inputs.onTarget, inputs.onSchema, inputs.onDocuments || [], inputs.onPlugins || [], inputs.onOutput, inputs.onIntrospection, inputs.onConfig, inputs.onScript ) ); } ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/additional-schema.graphql ================================================ type AdditionalType { f: Int! } ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/gatsby-and-custom-parsers.ts ================================================ import { parser } from 'custom-graphql-parser'; import { graphql } from 'gatsby'; import gql from 'graphql-tag'; export const fragmentA = gql` fragment FragmentA on MyType { fieldC } `; export const fragmentB = graphql` fragment FragmentB on MyType { fieldC } `; export const fragmentC = parser` fragment FragmentC on MyType { fieldC } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/invalid-directive.graphql ================================================ query myQuery { fieldA fieldB @client { fieldC } } ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/invalid-fields.graphql ================================================ query myQuery { fieldD } ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/invalid-schema.graphql ================================================ INVALID_SCHEMA ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/js-my-fragment.js ================================================ import gql from 'graphql-tag'; export const myFragment = gql` fragment MyFragment on MyType { fieldC } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/js-query-with-my-fragment.js ================================================ import gql from 'graphql-tag'; import { myFragment } from './js-my-fragment'; export const query = gql` query myQuery($a: String) { fieldA(a: $a) fieldB { ...MyFragment } } ${myFragment} `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/my-fragment.ts ================================================ import gql from 'graphql-tag'; export const myFragment = gql` fragment MyFragment on MyType { fieldC } `; export const myFragment2 = gql` fragment MyFragment2 on DType { field1 } `; export const myFragment3 = gql` fragment MyFragment3 on DType { field2 } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/query-with-commented-fragment.ts ================================================ import gql from 'graphql-tag'; export const myFragment = gql` fragment MyFragment on MyType { fieldC } `; // export const myFragment = gql` // fragment MyFragment on MyType { // fieldC // } // `; export const query = gql` query myQuery { fieldB { ...MyFragment } } ${myFragment} `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/query-with-my-fragment.ts ================================================ import gql from 'graphql-tag'; import { myFragment, myFragment2, myFragment3 } from './my-fragment.js'; export const query = gql` query myQuery($a: String) { fieldA(a: $a) fieldB { ...MyFragment } } ${myFragment} `; export const query2 = gql` query myQuery2 { fieldC { item { ...MyFragment2 ...MyFragment3 } } } ${myFragment2} ${myFragment3} `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/schema.graphql ================================================ type Query { fieldA(a: String): String fieldB: MyType fieldC: CType } type MyType { fieldC: Int } type CType { item: DType } type DType { field1: String field2: Int } ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/test-schema.graphql ================================================ type Query { f(a: Filter): String b: MyType } input Filter { id: String! } type MyType { t: MyEnum! } enum MyEnum { A B C } ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/ts-features-with-query.ts ================================================ import gql from 'graphql-tag'; namespace Foo { export const foo = 12; export const query = gql` query myQueryInNamespace { fieldA } `; } interface ModuleWithProviders { ngModule: string; } export class FooModule { static forRoot() { return { ngModule: 'foo', value: Foo.foo, } as ModuleWithProviders; } } export const query = gql` query myQuery { fieldA } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/unused-variable.graphql ================================================ query myQuery($v: String!) { fieldA fieldB { fieldC } } ================================================ FILE: packages/graphql-codegen-cli/tests/test-documents/valid.graphql ================================================ query myQuery { fieldA fieldB { fieldC } } ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/1.ts ================================================ import gql from 'graphql-tag'; export const myQuery = gql` query myQuery { data { field1 field2 } } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/10.tsx ================================================ import { buildQuery } from 'graph/buildQuery'; import { GPlayerList } from 'graph/types'; import graphql from 'graphql-tag'; export const playerListQuery = buildQuery(graphql` query GPlayerList { allPlayers { id tier name } } `); ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/11.ts ================================================ import graphql from 'graphql-tag'; export const articleDetailQuery = graphql` query ArticleDetail { Article(id: "thisisnotarealID") { title } } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/12.tsx ================================================ import * as React from 'react'; import gql from 'graphql-tag'; export default class extends React.Component<{}, {}> { public render() { return

    ; } } export const pageQuery = gql` query IndexQuery { site { siteMetadata { title } } } `; // export const pageQuery = gql` // query IndexQuery { // site { // siteMetadata { // title // } // } // } // `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/13.tsx ================================================ import * as React from 'react'; import graphql from 'graphql-tag'; export default class extends React.Component<{}, {}> { public render() { return
    ; } } export const pageQuery = graphql` query IndexQuery { site { siteMetadata { title } } } `; // export const pageQuery = graphql` // query IndexQuery { // site { // siteMetadata { // title // } // } // } // `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/14.js ================================================ import gql from 'graphql-tag'; export const booksQuery = gql` { books { isbn title description rating thumbnails { url } } } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/15.js ================================================ import graphql from 'graphql-tag'; export const booksQuery = graphql` { books { isbn title description rating thumbnails { url } } } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/16.ts ================================================ const other = 'asd'; export const endpoint = `${other}/graphql`; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/2.ts ================================================ import gql from 'graphql-tag'; export const myQuery = gql(` query myQuery { data { field1 field2 } } `); ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/3.graphql ================================================ query myQuery { data { field1 field2 } } ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/4.ts ================================================ import gql from 'graphql-tag'; // export const myQuery = gql(` // query myQuery1 { // data { // field1 // field2 // } // } // `); export const myQuery = gql(` query myQuery2 { data { field1 field2 } } `); /* export const myQuery = gql(` query myQuery3 { data { field1 field2 } } `); */ ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/5.tsx ================================================ import { buildQuery } from 'graph/buildQuery'; import { GPlayerList } from 'graph/types'; import gql from 'graphql-tag'; export const playerListQuery = buildQuery(gql` query GPlayerList { allPlayers { id tier name } } `); ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/6.ts ================================================ import gql from 'graphql-tag'; export const articleDetailQuery = gql` query ArticleDetail { Article(id: "thisisnotarealID") { title } } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/7.ts ================================================ import graphql from 'graphql-tag'; export const myQuery = graphql` query myQuery { data { field1 field2 } } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/8.ts ================================================ import graphql from 'graphql-tag'; export const myQuery = graphql(` query myQuery { data { field1 field2 } } `); ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/9.ts ================================================ import graphql from 'graphql-tag'; // export const myQuery = graphql(` // query myQuery1 { // data { // field1 // field2 // } // } // `); export const myQuery = graphql(` query myQuery2 { data { field1 field2 } } `); /* export const myQuery = graphql(` query myQuery3 { data { field1 field2 } } `); */ ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/ByteOrderMask.json ================================================ { "data": { "__schema": { "queryType": { "name": "Query" }, "mutationType": { "name": "Mutation" }, "subscriptionType": { "name": "Subscription" }, "types": [ { "kind": "OBJECT", "name": "Query", "description": null, "fields": [ { "name": "getUser", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastUser", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "listUsers", "description": null, "args": [ { "name": "first", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "after", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UserConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "getProduct", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Product", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "listProducts", "description": null, "args": [ { "name": "first", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "after", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ProductConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "getRecycleEvent", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RecycleEvent", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "listRecycleEvents", "description": null, "args": [ { "name": "first", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "after", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RecycleEventConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "User", "description": null, "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "ID", "description": "Built-in ID", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "String", "description": "Built-in String", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UserConnection", "description": null, "fields": [ { "name": "items", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nextToken", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "Int", "description": "Built-in Int", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Product", "description": null, "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "title", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "image", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ProductConnection", "description": null, "fields": [ { "name": "items", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Product", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nextToken", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RecycleEvent", "description": null, "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userid", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "product", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Product", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RecycleEventConnection", "description": null, "fields": [ { "name": "items", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "RecycleEvent", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nextToken", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Mutation", "description": null, "fields": [ { "name": "createUser", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CreateUserInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateUser", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateUserInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteUser", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteUserInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createProduct", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CreateProductInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Product", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateProduct", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateProductInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Product", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteProduct", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteProductInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Product", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createRecycleEvent", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CreateRecycleEventInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RecycleEvent", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateRecycleEvent", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateRecycleEventInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RecycleEvent", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteRecycleEvent", "description": null, "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteRecycleEventInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RecycleEvent", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CreateUserInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateUserInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteUserInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CreateProductInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "title", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "image", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateProductInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "title", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "image", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteProductInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CreateRecycleEventInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateRecycleEventInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteRecycleEventInput", "description": null, "fields": null, "inputFields": [ { "name": "id", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Subscription", "description": null, "fields": [ { "name": "onCreateUser", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "name", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onUpdateUser", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "name", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onDeleteUser", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "name", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onCreateProduct", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "title", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "image", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Product", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onUpdateProduct", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "title", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "image", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Product", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onDeleteProduct", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "title", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "image", "description": null, "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Product", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onCreateRecycleEvent", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RecycleEvent", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onUpdateRecycleEvent", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RecycleEvent", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onDeleteRecycleEvent", "description": null, "args": [ { "name": "id", "description": null, "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RecycleEvent", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Schema", "description": "A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.", "fields": [ { "name": "types", "description": "A list of all types supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type" } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "queryType", "description": "The type that query operations will be rooted at.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mutationType", "description": "If this server supports mutation, the type that mutation operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "directives", "description": "'A list of all directives supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Directive" } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subscriptionType", "description": "'If this server support subscription, the type that subscription operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Type", "description": null, "fields": [ { "name": "kind", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "fields", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "interfaces", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "possibleTypes", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "enumValues", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "inputFields", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ofType", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__TypeKind", "description": "An enum describing what kind of type a given __Type is", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "SCALAR", "description": "Indicates this type is a scalar.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Indicates this type is a union. `possibleTypes` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Indicates this type is an enum. `enumValues` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Indicates this type is an input object. `inputFields` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "LIST", "description": "Indicates this type is a list. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "NON_NULL", "description": "Indicates this type is a non-null. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "__Field", "description": null, "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue" } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__InputValue", "description": null, "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "defaultValue", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "Boolean", "description": "Built-in Boolean", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__EnumValue", "description": null, "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Directive", "description": null, "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "locations", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue" } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "onOperation", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onFragment", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onField", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "isDeprecated": true, "deprecationReason": "Use `locations`." } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__DirectiveLocation", "description": "An enum describing valid locations where a directive can be placed", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "QUERY", "description": "Indicates the directive is valid on queries.", "isDeprecated": false, "deprecationReason": null }, { "name": "MUTATION", "description": "Indicates the directive is valid on mutations.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD", "description": "Indicates the directive is valid on fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_DEFINITION", "description": "Indicates the directive is valid on fragment definitions.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_SPREAD", "description": "Indicates the directive is valid on fragment spreads.", "isDeprecated": false, "deprecationReason": null }, { "name": "INLINE_FRAGMENT", "description": "Indicates the directive is valid on inline fragments.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCHEMA", "description": "Indicates the directive is valid on a schema IDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCALAR", "description": "Indicates the directive is valid on a scalar IDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Indicates the directive is valid on an object IDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD_DEFINITION", "description": "Indicates the directive is valid on a field IDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ARGUMENT_DEFINITION", "description": "Indicates the directive is valid on a field argument IDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Indicates the directive is valid on an interface IDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Indicates the directive is valid on an union IDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Indicates the directive is valid on an enum IDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Indicates the directive is valid on an input object IDL definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_FIELD_DEFINITION", "description": "Indicates the directive is valid on an input object field IDL definition.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null } ], "directives": [ { "name": "include", "description": "Directs the executor to include this field or fragment only when the `if` argument is true", "args": [ { "name": "if", "description": "Included when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": true, "onField": true }, { "name": "skip", "description": "Directs the executor to skip this field or fragment when the `if`'argument is true.", "args": [ { "name": "if", "description": "Skipped when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": true, "onField": true }, { "name": "aws_auth", "description": "Directs the schema to enforce authorization on a field", "args": [ { "name": "cognito_groups", "description": "List of cognito user pool groups which have access on this field", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": false, "onField": false }, { "name": "aws_publish", "description": "Tells the service which subscriptions will be published to when this mutation is called.", "args": [ { "name": "subscriptions", "description": "List of subscriptions which will be published to when this mutation is called.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": false, "onField": false }, { "name": "aws_subscribe", "description": "Tells the service which mutation triggers this subscription.", "args": [ { "name": "mutations", "description": "List of mutations which will trigger this subscription when they are called.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "onOperation": false, "onFragment": false, "onField": false } ] } } } ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/error-document.graphql ================================================ query ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/graphql.config.js ================================================ /** @type {import('graphql-config').IGraphQLConfig } */ module.exports = { generates: {}, projects: { prj1: { schema: ['**/test-documents/schema.graphql'], documents: ['**/test-documents/valid.graphql'], extensions: { codegen: { generates: { 'graphqlTypes.ts': { schema: ['**/test-documents/schema.graphql'], documents: ['**/test-documents/valid.graphql'], plugins: ['typed-document-node'], }, }, }, }, }, }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/graphql.config.no-doc-ignored.js ================================================ /** @type {import('graphql-config').IGraphQLConfig } */ module.exports = { schema: ['../test-documents/schema.graphql'], documents: ['../test-documents/empty.graphql'], extensions: { codegen: { verbose: true, ignoreNoDocuments: true, generates: { './gql/': { preset: 'client', }, }, }, }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/graphql.config.no-doc.js ================================================ /** @type {import('graphql-config').IGraphQLConfig } */ module.exports = { schema: ['../test-documents/schema.graphql'], documents: ['../test-documents/empty.graphql'], extensions: { codegen: { verbose: true, generates: { './gql/': { preset: 'client', }, }, }, }, }; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/error-schema.graphql ================================================ type Query { foo: String!! } ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/gatsby-and-custom-parsers/apollo-server.ts ================================================ import { gql } from 'apollo-server'; export const typeDefs = gql` type Query { user: User } type User { """ Used apollo-server """ a: String } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/gatsby-and-custom-parsers/custom.ts ================================================ import { parser } from 'custom-graphql-parser'; export const typeDefs = parser` type Query { book: Book } type Book { """ Used custom parser """ a: String } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/gatsby-and-custom-parsers/gatsby.ts ================================================ import { graphql } from 'gatsby'; export const typeDefs = graphql` extend type User { """ Used gatsby """ b: String } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/gatsby-and-custom-parsers/graphql-tag.ts ================================================ import gql from 'graphql-tag'; export const typeDefs = gql` type Query { user: User } type User { """ Used graphql-tag """ a: String } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/query.graphql ================================================ # import User from './user.graphql' type Query { user: User } ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/schema-object.cjs ================================================ const { GraphQLSchema, GraphQLObjectType, GraphQLString } = require('graphql'); module.exports = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { foo: { type: GraphQLString, resolve: () => `FOO`, }, }, }), }); ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/schema.ts ================================================ import gql from 'graphql-tag'; export const typeDefs = gql` type Query { user: User } type User { a: String } `; ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/user.graphql ================================================ type User { a: String } ================================================ FILE: packages/graphql-codegen-cli/tests/test-files/schema-dir/with-extend.js ================================================ const { buildSchema } = require('graphql'); const schema = buildSchema(/* GraphQL */ ` type User { a: String } type Query { user: User } extend type Query { hello: String } `); module.exports = schema; ================================================ FILE: packages/graphql-codegen-cli/tests/utils.ts ================================================ import os from 'os'; import { join, parse, relative, resolve } from 'path'; import makeDir from 'make-dir'; import * as rimraf from 'rimraf'; const fs = await vi.importActual('fs'); export class TempDir { dir: string; constructor() { const tempDir = fs.realpathSync(os.tmpdir()); const relativeParent = relative(process.cwd(), 'codegen'); // Each temp directory will be unique to the test file. // This ensures that temp files/dirs won't cause side effects for other tests. this.dir = resolve(tempDir, 'codegen', `${relativeParent}-dir`); makeDir.sync(this.dir); } createFile(file: string, contents: string): void { const filePath = join(this.dir, file); const fileDir = parse(filePath).dir; makeDir.sync(fileDir); fs.writeFileSync(filePath, `${contents}\n`); } clean() { const cleanPattern = join(this.dir, '**/*'); rimraf.sync(cleanPattern); } deleteTempDir() { rimraf.sync(this.dir); } } ================================================ FILE: packages/graphql-codegen-cli/tests/watcher-test-helpers/assert-watcher-build-triggers.ts ================================================ import { join, isAbsolute, relative, resolve, sep } from 'path'; import type { Options } from '@parcel/watcher'; import isGlob from 'is-glob'; import type { Mock } from 'vitest'; import { formatBuildTriggerErrorPrelude, formatErrorGlobNotIgnoredByParcelWatcher, formatErrorPathNotIgnoredByParcelWatcher, } from './format-watcher-assertion-errors'; interface MockWatcher { watchDirectory: string; subscribeOpts?: Options; dispatchChange: (path: string) => Promise; stopWatching: () => Promise; subscribeCallbackMock: Mock; subscribeMock: Mock; onWatchTriggeredMock: Mock; unsubscribeMock: Mock; } /** * Helper function for asserting that multiple paths did or did not trigger a build, * and for asserting the values of paths and globs passed to {@link Options}`["ignore"]` */ export const assertBuildTriggers = async ( mockWatcher: MockWatcher, { shouldTriggerBuild, shouldNotTriggerBuild, globsWouldBeIgnoredByParcelWatcher, pathsWouldBeIgnoredByParcelWatcher, keepWatching, }: { /** * Optional array of relative (from CWD) paths that SHOULD trigger build during watch mode * * Each path will be converted to an absolute path before dispatching it as * a change event, which is consistent with how ParcelWatcher dispatches * events (always containing an absolute path). */ shouldTriggerBuild?: string[]; /** * Optional array of relative (from CWD) paths that SHOULD NOT trigger build during watch mode * * Each path will be converted to an absolute path before dispatching it as * a change event, which is consistent with how ParcelWatcher dispatches * events (always containing an absolute path). * * NOTE: If a path would match one of the ignore patterns passed to Parcel, * because we do not implement the C++ code that evaluates those paths, it * will still be evaluated by the subscribe trigger. That's probably fine, * if you expect that our JS level matchers should also ignore the path, * but keep in mind that in production, the real Parcel watcher would (hopefully) * never dispatch an event with an ignored path to the subscribe callback. */ shouldNotTriggerBuild?: string[]; /** * Optional array specifying paths (_not_ globs) that should be included * in the `options.ignore` value passed to {@link ParcelWatcher.subscribe}. * * Any paths expected to be ignored should be specified _relative from cwd_, * as they would be in the config file. Note that ParcelWatcher expects * these paths to be relative from the `watchDirectory`, and the assertion * helper will do the conversion, by converting each item in the `options.ignore` * array to be relative from the cwd, and _then_ searching for a match to the * specified path. * * This is different from {@link globsWouldBeIgnoredByParcelWatcher} which * does no conversion and only looks for exact matches. * * For each path in this array: * * * It will be checked for equality with an item in `options.ignore`, but * only after all paths in options.ignore have been converted to also be relative from cwd * * See: {@link https://github.com/parcel-bundler/watcher#options} * * NOTE: Because our mock does not implement Parcel Watcher's C++ code that * checks whether a path should be ignored, that means that every dispatched * event, regardless of path, will always call the subscribe callback on our mock, * even if Parcel would have otherwise ignored it. */ pathsWouldBeIgnoredByParcelWatcher?: string[]; /** * Optional array specifying glob patterns (_not_ paths) that should be included * in the `options.ignore` value passed to {@link ParcelWatcher.subscribe}. * * This assertion helper will look for an **exact match** of each string * in this array. Any relative globs should be specified relative from the * `watchDirectory`, because this asertion helper will not attempt to convert * them (unlike with {@link pathsWouldBeIgnoredByParcelWatcher}). * * For each string in this array: * * * It will be checked for exact equality with an item in options.ignore * * See: {@link https://github.com/parcel-bundler/watcher#options} * * NOTE: Because our mock does not implement Parcel Watcher's C++ code that * checks whether a path should be ignored, that means that every dispatched * event, regardless of path, will always call the subscribe callback on our mock, * even if Parcel would have otherwise ignored it. */ globsWouldBeIgnoredByParcelWatcher?: string[]; /** * Set this to `true` if the helper function should not call `stopWatching()` * (for example, if you want to continue making assertions within the test). * * By default, the helper will stop the watcher when it's done, even if it * encounters an error. */ keepWatching?: true; } ) => { const { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory, subscribeOpts, } = mockWatcher; // These are optional, but to avoid if/else nesting, set them to empty list if not specified shouldTriggerBuild ??= []; shouldNotTriggerBuild ??= []; // Wrap in a try/finally block so even if there's an error, we can stop the watcher // This way, we avoid misleading "cannot log after tests are done" error try { expect(subscribeMock).toHaveBeenCalledTimes(1); expect(subscribeMock.mock.calls[0][0]).toBe(watchDirectory); expect(subscribeMock.mock.calls[0][2]).toStrictEqual(subscribeOpts); for (const relPath of shouldTriggerBuild) { const path = join(process.cwd(), relPath); await assertTriggeredBuild(path, { dispatchChange, subscribeCallbackMock, onWatchTriggeredMock }); } expect(subscribeCallbackMock).toHaveBeenCalledTimes(shouldTriggerBuild.length); expect(onWatchTriggeredMock).toHaveBeenCalledTimes(shouldTriggerBuild.length); for (const relPath of shouldNotTriggerBuild) { const path = join(process.cwd(), relPath); await assertDidNotTriggerBuild(path, { dispatchChange, subscribeCallbackMock, onWatchTriggeredMock }); } expect(subscribeCallbackMock).toHaveBeenCalledTimes(shouldTriggerBuild.length + shouldNotTriggerBuild.length); expect(onWatchTriggeredMock).toHaveBeenCalledTimes(shouldTriggerBuild.length); const ignore = subscribeOpts.ignore ?? []; if (pathsWouldBeIgnoredByParcelWatcher) { for (const relPathFromCwd of pathsWouldBeIgnoredByParcelWatcher) { if (isGlob(relPathFromCwd)) { throw new Error( [ `expected path, got glob: ${relPathFromCwd}`, 'pass globs to globsWouldBeIgnoredByParcelWatcher, not pathsWouldBeIgnoredByParcelWatcher', ].join('\n') ); } if (isAbsolute(relPathFromCwd)) { throw new Error('pathsWouldBeIgnoredByParcelWatcher should only include relative paths from cwd'); } assertParcelWouldIgnorePath(relPathFromCwd, { watchDirectory, ignore }); } } if (globsWouldBeIgnoredByParcelWatcher) { for (const expectedIgnoredGlob of globsWouldBeIgnoredByParcelWatcher) { if (!isGlob(expectedIgnoredGlob)) { throw new Error( [ `expected glob, got path (or something that is not a glob): ${expectedIgnoredGlob}`, 'pass paths to pathsWouldBeIgnoredByParcelWatcher, not globsWouldBeIgnoredByParcelWatcher', ].join('\n') ); } assertParcelWouldIgnoreGlob(expectedIgnoredGlob, { watchDirectory, ignore }); } } } finally { if (keepWatching !== true) { await stopWatching(); expect(unsubscribeMock).toHaveBeenCalledTimes(1); } } }; /** * Given a glob pattern, assert that {@link Options}`["ignore"]` * contains that glob pattern (exact match). * * We don't implement actual globbing logic, because Parcel Watcher does that * from C++ and it would be a leaky mock. */ const assertParcelWouldIgnoreGlob = ( /** Glob pattern expected to exist in {@link Options}`["ignore"]` */ expectToIgnoreGlob: string, { ignore, watchDirectory }: { watchDirectory: string; ignore: Required['ignore'] } ) => { const parcelIgnoredGlobs = ignore.filter(pathOrGlob => isGlob(pathOrGlob)); const hasMatch = parcelIgnoredGlobs.includes(expectToIgnoreGlob); try { expect(hasMatch).toBe(true); } catch (error) { error.message = formatErrorGlobNotIgnoredByParcelWatcher({ expectedGlob: expectToIgnoreGlob, parcelIgnoredGlobs, jestErrorMessage: error.message, watchDirectory, }); Error.captureStackTrace(error, assertParcelWouldIgnoreGlob); throw error; } }; /** * Given a path, and the `ignore` option passed to the mocked {@link Options}, * assert that ParcelWatcher "would" ignore the path if given it as part of the ignore option. * * Note that ParcelWatcher expects paths relative from the watchDirectory, but * our assertion helper expects paths relative from cwd. */ const assertParcelWouldIgnorePath = ( /** * Relative path from cwd, as given to {@link assertBuildTriggers} * `pathsWouldBeIgnoredByParcelWatcher` option */ expectToIgnoreRelPathFromCwd: string, { watchDirectory, ignore, }: { watchDirectory: string; ignore: Required['ignore']; } ) => { const parcelIgnoredPaths = ignore.filter(pathOrGlob => !isGlob(pathOrGlob)); const parcelIgnoredPathsRelativeFromCwd = parcelIgnoredPaths.map(relOrAbsolutePath => { // NOTE: ParcelWatcher considers relative ignore paths relative from the given watchDirectory const relPathFromWatchDir = isAbsolute(relOrAbsolutePath) ? relative(watchDirectory, relOrAbsolutePath) : relOrAbsolutePath; // ...but we want to assert relative from cwd const absPath = resolve(process.cwd(), relative(process.cwd(), watchDirectory), relPathFromWatchDir); const relPathFromCwd = relative(process.cwd(), absPath); // NOTE: This will not include "./" return relPathFromCwd; }); // Match on exact match, or exact match with ./ prefix (or .\ on windows) const hasMatch = parcelIgnoredPathsRelativeFromCwd.some( ignorePathRelFromCwd => expectToIgnoreRelPathFromCwd === ignorePathRelFromCwd || expectToIgnoreRelPathFromCwd === `.${sep}${ignorePathRelFromCwd}` ); try { expect(hasMatch).toBe(true); } catch (error) { error.message = formatErrorPathNotIgnoredByParcelWatcher({ expectedPath: expectToIgnoreRelPathFromCwd, parcelIgnoredPaths, parcelIgnoredPathsRelativeFromCwd, jestErrorMessage: error.message, watchDirectory, }); Error.captureStackTrace(error, assertParcelWouldIgnorePath); throw error; } }; type MockWatcherAssertionHelpers = Pick< MockWatcher, 'dispatchChange' | 'subscribeCallbackMock' | 'onWatchTriggeredMock' >; /** * Assertion helper to assert that the given (absolute) path triggered a build */ const assertTriggeredBuild = async ( /** Absolute path */ path: string, { dispatchChange, subscribeCallbackMock, onWatchTriggeredMock }: MockWatcherAssertionHelpers ) => { try { await dispatchChange(path); expect(subscribeCallbackMock).toHaveBeenLastCalledWith(undefined, [{ path, type: 'update' }]); expect(onWatchTriggeredMock).toHaveBeenLastCalledWith('update', path); } catch (error) { error.message = formatBuildTriggerErrorPrelude(path, true, error.message); Error.captureStackTrace(error, assertTriggeredBuild); throw error; } }; /** * Assertion helper to assert that the given (absolute) path did NOT trigger a build */ const assertDidNotTriggerBuild = async ( /** Absolute path */ path: string, { dispatchChange, subscribeCallbackMock, onWatchTriggeredMock }: MockWatcherAssertionHelpers ) => { try { await dispatchChange(path); expect(subscribeCallbackMock).toHaveBeenLastCalledWith(undefined, [{ path, type: 'update' }]); expect(onWatchTriggeredMock).not.toHaveBeenLastCalledWith('update', path); } catch (error) { error.message = formatBuildTriggerErrorPrelude(path, false, error.message); Error.captureStackTrace(error, assertDidNotTriggerBuild); throw error; } }; ================================================ FILE: packages/graphql-codegen-cli/tests/watcher-test-helpers/format-watcher-assertion-errors.ts ================================================ import { relative } from 'path'; import chalk from 'chalk'; /** * Format an error message when a glob is not ignored by Parcel Watcher */ export const formatErrorGlobNotIgnoredByParcelWatcher = ({ expectedGlob, parcelIgnoredGlobs, jestErrorMessage, watchDirectory, }: { expectedGlob: string; parcelIgnoredGlobs: string[]; jestErrorMessage: string; watchDirectory: string; }) => { const rawGlobTableLines = [ 'Expected glob not found:', expectedGlob, 'globs received by ParcelWatcher.Options.ignore', '----------------------------------------------------', ...parcelIgnoredGlobs, ]; const maxGlobLength = Math.max(...rawGlobTableLines.map(s => s.length)); const globTableLineFormatters: ((s: string) => string)[] = [s => s, s => chalk.red(s), s => chalk.bold(s)]; const tableLines = rawGlobTableLines.map((line, rowNum) => { const formatLine = globTableLineFormatters[rowNum] ?? (s => s); return `| ${chalk.reset(formatLine(line.padStart(maxGlobLength)))} |`; }); return `${[ chalk.gray( '-----------------------------------------', 'Watch Mode Parcel Ignore Assertion Failure:', '-----------------------------------------' ), '', chalk.gray( chalk.bold('Note:'), 'Assertion should specify relative glob paths relative from watchDirectory (_not_ cwd),' ), chalk.gray( ' i.e. exactly as given to ParcelWatcher (unlike path assertions which should be relative from cwd),' ), chalk.gray(' because glob assertion looks for an exact match and does not try to convert them.'), '', chalk.gray(chalk.bold('watchDirectory:'), watchDirectory), ' ', ' ', ...tableLines, ' ', chalk.gray( '----------------------------------------------------', 'Raw Error (from Jest):', '---------------------------------------------------' ), ].join('\n')}\n${jestErrorMessage}`; }; /** * Format an error message when a path is not ignored by Parcel Watcher */ export const formatErrorPathNotIgnoredByParcelWatcher = ({ expectedPath, parcelIgnoredPaths, parcelIgnoredPathsRelativeFromCwd, jestErrorMessage, watchDirectory, }: { expectedPath: string; watchDirectory: string; parcelIgnoredPaths: string[]; parcelIgnoredPathsRelativeFromCwd: string[]; jestErrorMessage: string; }) => { const leftCol = [ '', '', 'ParcelWatcher.Options[ignore]', 'These raw values were received in the options.ignore argument', 'of ParcelWatcher.subscribe, which ParcelWatcher expects to be', 'either an absolute path, or relative from watchDirectory', '--------------------------------------------------------------+', ...parcelIgnoredPaths, ]; const rightCol = [ 'Match not found:', expectedPath, 'Converted to be relative from CWD', 'Each value was converted to be relative from CWD, (assuming', 'that the inputs were correctly relative from watchDirectory),', 'and then we scanned this column looking for a match.', '+--------------------------------------------------------------', ...parcelIgnoredPathsRelativeFromCwd, ]; const headerFormatters: [(s: string) => string, (s: string) => string][] = [ [s => chalk.gray(s), s => chalk.gray(s)], [s => s, s => chalk.red(s)], [s => chalk.bold(s), s => chalk.bold(s)], [s => chalk.gray(s), s => chalk.gray(s)], [s => chalk.gray(s), s => chalk.gray(s)], [s => chalk.gray(s), s => chalk.gray(s)], ]; const maxLeftCol = Math.max(...leftCol.map(c => c.length)); const maxRightCol = Math.max(...rightCol.map(c => c.length)); if (leftCol.length !== rightCol.length) { throw new Error('Formatting error: columns different height'); } const tableLines = leftCol.map((leftCell, rowNum) => { const [formatLeft, formatRight] = headerFormatters[rowNum] ?? [(s: string) => s, (s: string) => s]; return `${formatLeft(leftCell.padStart(maxLeftCol))} | ${formatRight(rightCol[rowNum].padEnd(maxRightCol))}`; }); return `${[ chalk.gray( '-----------------------------------------', 'Watch Mode Parcel Ignore Assertion Failure:', '-----------------------------------------' ), chalk.red(`<${expectedPath}> ` + chalk.bold('would not have been ignored by Parcel Watcher')), chalk.gray(chalk.bold('Note:'), 'Assertion should specify path relative from current working directory,'), chalk.gray(' but code should give path to ParcelWatcher relative from', chalk.bold('watchDirectory')), '', chalk.gray(chalk.bold('watchDirectory:'), watchDirectory), '', '', ...tableLines, '', chalk.gray( '----------------------------------------------------', 'Raw Error (from Jest):', '---------------------------------------------------' ), ].join('\n')}\n${jestErrorMessage}`; }; /** * Format a readable error message to print when the assertion fails, so that * the developer can immediately see which path was expected to trigger (or not trigger) * the rebuild. * * Since we're using auto-assertions, this makes for much more readable errors * than the raw Jest message (which can be misleading because, e.g. if the assertion * is that `onWatchTriggered` was last called with the right path, but it wasn't, * then the Jest error message will misleadingly print the previous path). */ export const formatBuildTriggerErrorPrelude = ( /** Absolute path */ path: string, expectedToBuild: boolean, jestErrorMessage: string ) => { const relPath = relative(process.cwd(), path); const should = `${expectedToBuild ? 'have' : 'not have'} triggered build`; const but = expectedToBuild ? 'it did not' : 'it did'; return `${[ chalk.gray('---------------------- Watch Mode Build Trigger Assertion Failure: ----------------------'), chalk.red(`<${relPath}>` + chalk.bold(` should ${should}, but ${but}.`)), ` Expected: ${chalk.green(expectedToBuild ? 'to trigger build' : 'not to trigger build')}`, ` Received: ${chalk.red(expectedToBuild ? 'did not trigger build' : 'triggered build')}`, chalk.gray(`Absolute Path: ${path}`), '', chalk.gray('-------------------------------- Raw Error (from Jest): --------------------------------'), ].join('\n')}\n${jestErrorMessage}`; }; ================================================ FILE: packages/graphql-codegen-cli/tests/watcher.patterns.spec.ts ================================================ import * as fs from '../src/utils/file-system.js'; import type { SubscribeCallback } from '@parcel/watcher'; import { assertBuildTriggers } from './watcher-test-helpers/assert-watcher-build-triggers.js'; import { join } from 'path'; import { createWatcher } from '../src/utils/watcher.js'; import { CodegenContext } from '../src/config.js'; import type { Mock } from 'vitest'; const unsubscribeMock = vi.fn(); const subscribeMock = vi.fn(); let subscribeCallbackMock: Mock; vi.mock('@parcel/watcher', () => ({ subscribe: subscribeMock.mockImplementation((watchDirectory: string, subscribeCallback: SubscribeCallback) => { subscribeCallbackMock = vi.fn(subscribeCallback); return { unsubscribe: unsubscribeMock, }; }), })); const setupMockWatcher = async ( codegenContext: ConstructorParameters[0], onNext: Mock = vi.fn().mockResolvedValue([]) ) => { const { stopWatching } = createWatcher(new CodegenContext(codegenContext), onNext); const dispatchChange = async (path: string) => subscribeCallbackMock(undefined, [{ type: 'update', path }]); // createWatcher doesn't set up subscription immediately, so we wait for a tick before continuing await new Promise(resolve => setTimeout(resolve, 100)); return { stopWatching, dispatchChange }; }; describe('Watch patterns', () => { beforeEach(() => { vi.clearAllMocks(); // Silence logs vi.spyOn(console, 'log').mockImplementation(() => {}); vi.spyOn(console, 'info').mockImplementation(() => {}); }); test('watches the longest common prefix directory', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const { stopWatching } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: vi.fn() }, schema: './foo/something.ts', generates: { ['./foo/some-output.ts']: { documents: ['./foo/bar/*.graphql'], }, }, }, }); expect(subscribeMock).toHaveBeenCalledTimes(1); expect(subscribeMock.mock.calls[0][0]).toBe(join(process.cwd(), 'foo')); await stopWatching(); }); test('ignores schema URLs when detecting common prefix directory', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const { stopWatching } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: vi.fn() }, schema: 'http://localhost/graphql', generates: { ['./foo/some-output.ts']: { documents: ['./foo/bar/*.graphql'], }, }, }, }); expect(subscribeMock).toHaveBeenCalledTimes(1); expect(subscribeMock.mock.calls[0][0]).toBe(join(process.cwd(), 'foo')); await stopWatching(); }); test('watches process.cwd() when longest common prefix directory is not accessible', async () => { vi.spyOn(fs, 'access').mockImplementation(async path => { if (path === join(process.cwd(), 'foo')) { throw new Error(); } }); const { stopWatching } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: vi.fn() }, schema: './foo/something.ts', generates: { ['./foo/some-output.ts']: { documents: ['./foo/bar/*.graphql'], }, }, }, }); expect(subscribeMock).toHaveBeenCalledTimes(1); expect(subscribeMock.mock.calls[0][0]).toBe(process.cwd()); await stopWatching(); }); // This test uses manual assertions to make sure they're tested individually, // but note that `assertBuildTriggers` can do most of this work for you test('triggers a rebuild for basic case', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, schema: './foo/something.ts', generates: { ['./foo/some-output.ts']: { documents: ['./foo/bar/*.graphql'], }, }, }, }); expect(subscribeMock).toHaveBeenCalledTimes(1); expect(subscribeMock.mock.calls[0][0]).toBe(join(process.cwd(), 'foo')); const shouldTriggerBuild = join(process.cwd(), './foo/bar/fizzbuzz.graphql'); const shouldNotTriggerBuild = join(process.cwd(), './foo/bar/something.ts'); await dispatchChange(shouldTriggerBuild); expect(subscribeCallbackMock).toHaveBeenLastCalledWith(undefined, [{ path: shouldTriggerBuild, type: 'update' }]); expect(onWatchTriggeredMock).toHaveBeenLastCalledWith('update', shouldTriggerBuild); await dispatchChange(shouldNotTriggerBuild); expect(subscribeCallbackMock).toHaveBeenLastCalledWith(undefined, [ { path: shouldNotTriggerBuild, type: 'update' }, ]); expect(onWatchTriggeredMock).not.toHaveBeenLastCalledWith('update', shouldNotTriggerBuild); expect(onWatchTriggeredMock).toHaveBeenCalledTimes(1); expect(subscribeCallbackMock).toHaveBeenCalledTimes(2); await stopWatching(); expect(unsubscribeMock).toHaveBeenCalled(); }); test('globally included paths should be included even when a local pattern negates them', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, schema: ['./foo/**/match-schema-everywhere.graphql'], watch: [ 'foo/**/match-watch-everywhere.graphql', 'foo/**/match-watch-doc-everywhere.graphql', 'foo/**/match-watch-schema-everywhere.graphql', ], documents: ['foo/**/match-doc-everywhere.graphql'], generates: { // globally inclued paths should be included even when a local pattern negates them ['./foo/local-exclusions-dont-precede-global-inclusions.ts']: { watchPattern: ['!foo/global-beats-local/match-watch-everywhere.graphql'], documents: [ '!foo/global-beats-local/match-doc-everywhere.graphql', '!foo/global-beats-local/match-watch-doc-everywhere.graphql', ], schema: [ '!foo/global-beats-local/match-schema-everywhere.graphql', '!foo/global-beats-local/match-watch-schema-everywhere.graphql', ], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'foo'), subscribeOpts: { ignore: ['**/.git/**', 'local-exclusions-dont-precede-global-inclusions.ts'], }, }, { shouldTriggerBuild: [ // watch './foo/match-watch-everywhere.graphql', './foo/fizz/match-watch-everywhere.graphql', './foo/fizz/buzz/match-watch-everywhere.graphql', './foo/fizz/buzz/foobarbaz/match-watch-everywhere.graphql', // watch-doc (matched in global watch, excluded in local doc) './foo/match-watch-doc-everywhere.graphql', './foo/fizz/match-watch-doc-everywhere.graphql', './foo/fizz/buzz/match-watch-doc-everywhere.graphql', './foo/fizz/buzz/foobarbaz/match-watch-doc-everywhere.graphql', // watch-schema (matched in global watch, excluded in local schema) './foo/match-watch-schema-everywhere.graphql', './foo/fizz/match-watch-schema-everywhere.graphql', './foo/fizz/buzz/match-watch-schema-everywhere.graphql', './foo/fizz/buzz/foobarbaz/match-watch-schema-everywhere.graphql', // doc './foo/match-doc-everywhere.graphql', './foo/fizz/match-doc-everywhere.graphql', './foo/fizz/buzz/match-doc-everywhere.graphql', './foo/fizz/buzz/foobarbaz/match-doc-everywhere.graphql', // schema './foo/match-schema-everywhere.graphql', './foo/fizz/match-schema-everywhere.graphql', './foo/fizz/buzz/match-schema-everywhere.graphql', './foo/fizz/buzz/foobarbaz/match-schema-everywhere.graphql', ], } ); }); test('globally negated paths should be excluded even when a local pattern matches them', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, schema: ['!**/exclude-schema-everywhere.graphql'], watch: [ '!**/exclude-watch-everywhere.graphql', '!**/exclude-watch-doc-everywhere.graphql', '!**/exclude-watch-schema-everywhere.graphql', ], documents: ['!**/exclude-doc-everywhere.graphql'], generates: { ['./foo/local-inclusions-dont-precede-global-exclusions.ts']: { watchPattern: [ 'foo/global-beats-local/exclude-watch-everywhere.graphql', 'foo/global-beats-local/exclude-watch-doc-everywhere.graphql', 'foo/global-beats-local/exclude-watch-schema-everywhere.graphql', ], documents: [ 'foo/global-beats-local/exclude-doc-everywhere.graphql', 'foo/global-beats-local/exclude-watch-doc-everywhere.graphql', ], schema: [ 'foo/global-beats-local/exclude-schema-everywhere.graphql', 'foo/global-beats-local/exclude-watch-schema-everywhere.graphql', ], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'foo'), subscribeOpts: { ignore: ['**/.git/**', 'local-inclusions-dont-precede-global-exclusions.ts'], }, }, { shouldNotTriggerBuild: [ 'foo/global-beats-local/exclude-watch-everywhere.graphql', 'foo/global-beats-local/exclude-doc-everywhere.graphql', 'foo/global-beats-local/exclude-schema-everywhere.graphql', 'foo/global-beats-local/exclude-watch-doc-everywhere.graphql', 'foo/global-beats-local/exclude-watch-schema-everywhere.graphql', ], } ); }); test('local watchPattern negation should override local documents match', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, schema: './foo/something.ts', generates: { ['./foo/some-output.ts']: { watchPattern: '!./foo/bar/never-watch.graphql', documents: ['./foo/bar/*.graphql'], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'foo'), subscribeOpts: { ignore: ['**/.git/**', 'some-output.ts'], }, }, { shouldTriggerBuild: ['./foo/bar/okay-doc.graphql'], shouldNotTriggerBuild: ['./foo/bar/never-watch.graphql'], } ); }); test('local negations in documents set should override match in same documents set', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, schema: './foo/something.ts', generates: { ['./foo/some-output.ts']: { documents: ['./foo/bar/*.graphql', '!./foo/bar/never.graphql'], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'foo'), subscribeOpts: { ignore: ['**/.git/**', 'some-output.ts'], }, }, { shouldTriggerBuild: ['./foo/bar/okay.graphql'], shouldNotTriggerBuild: ['./foo/bar/never.graphql'], } ); }); test('local watchPattern negation should override local schema match', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, schema: './foo/something.ts', generates: { ['./foo/some-output.ts']: { watchPattern: '!./foo/bar/never-watch.graphql', schema: ['./foo/bar/*.graphql'], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'foo'), subscribeOpts: { ignore: ['**/.git/**', 'some-output.ts'], }, }, { shouldTriggerBuild: ['./foo/bar/okay-doc.graphql'], shouldNotTriggerBuild: ['./foo/bar/never-watch.graphql'], } ); }); test('local negations in schema set should override match in same schema set', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, schema: './foo/something.ts', generates: { ['./foo/some-output.ts']: { schema: ['./foo/bar/*.graphql', '!./foo/bar/never.graphql'], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'foo'), subscribeOpts: { ignore: ['**/.git/**', 'some-output.ts'], }, }, { shouldTriggerBuild: ['./foo/bar/okay.graphql'], shouldNotTriggerBuild: ['./foo/bar/never.graphql'], } ); }); test('match in one local group, negated in another group, should still match', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, schema: './foo/something.ts', generates: { // match in one local group, negation in another local group, should still match ['./foo/alphabet/types-no-sigma.ts']: { schema: [ './foo/alphabet/schema/delta.graphql', // delta explicitly included './foo/alphabet/schema/zeta.graphql', // zeta explicitly included '!foo/alphabet/schema/sigma.graphql', // sigma explicitly excluded ], documents: [ './foo/alphabet/docs/*.graphql', // zeta implicitly included '!**/sigma.graphql', // sigma excluded here ], }, // match in one local group, negation in another local group, should still match ['./foo/alphabet/types-no-zeta.ts']: { watchPattern: [ // local watch pattern doesnt take priority over other groups schema '!./foo/alphabet/schema/delta.graphql', // delta explicitly excluded ], schema: [ './foo/alphabet/schema/sigma.graphql', // sigma explicitly included '!foo/alphabet/schema/zeta.graphql', // zeta explicitly excluded ], documents: [ './foo/alphabet/docs/sigma.graphql', // sigma explicitly included (should always match) '!./foo/alphabet/docs/zeta.graphql', // zeta excluded here ], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'foo'), subscribeOpts: { ignore: ['**/.git/**', 'alphabet/types-no-sigma.ts', 'alphabet/types-no-zeta.ts'], }, }, { shouldTriggerBuild: [ './foo/alphabet/docs/zeta.graphql', './foo/alphabet/docs/sigma.graphql', './foo/alphabet/schema/zeta.graphql', './foo/alphabet/schema/sigma.graphql', './foo/alphabet/schema/delta.graphql', ], } ); }); test('output directories with presetConfig create glob patterns ignored by parcel watcher', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, generates: { ['./foo/some-preset-bar/']: { preset: 'near-operation-file', presetConfig: { extension: '.generated.tsx', baseTypesPath: 'types.ts', }, documents: ['./foo/some-preset-bar/*.graphql'], }, ['./foo/some-preset-without-trailing-slash']: { // no trailing slash after directory preset: 'near-operation-file', presetConfig: { extension: '.fizzbuzz.tsx', baseTypesPath: 'types.ts', }, documents: ['./foo/some-preset-without-trailing-slash/*.graphql'], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'foo'), subscribeOpts: { ignore: [ '**/.git/**', 'some-preset-bar/**/*.generated.tsx', 'some-preset-without-trailing-slash/**/*.fizzbuzz.tsx', ], }, }, { // note: since our mock does not implement ParcelWatcher's shouldIgnore logic, // we can't actually test shouldNotTriggerBuild, because the subscription callback // will still be called. For that reason, we only check that the globs were passed // to ParcelWatcher.Options["ignore"] as expected (hence _would_BeIgnoredByParcelWatcher) shouldNotTriggerBuild: [], globsWouldBeIgnoredByParcelWatcher: [ // note: globs are tested for exact match with argument passed to subscribe options, // so they should be specified relative from watchDirectory, _not_ cwd (see typedoc) 'some-preset-bar/**/*.generated.tsx', 'some-preset-without-trailing-slash/**/*.fizzbuzz.tsx', ], } ); }); test('output files are ignored by parcel watcher, but would not trigger rebuild anyway', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './foo/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, generates: { ['./foo/some-output.ts']: { documents: ['./foo/bar/*.graphql', '!./foo/bar/never.graphql'], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'foo'), subscribeOpts: { ignore: ['**/.git/**', 'some-output.ts'], }, }, { // NOTE: Unlike the test with output _directories_, we can actually assert // that we wouldn't build output files, even if they were _not_ passed // to ParcelWatcher.Options[ignore], because we don't include output files // in our pattern matching (but there is no logic for output directories) shouldNotTriggerBuild: [ './foo/some-output.ts', // output file (note: should be ignored by parcel anyway) ], pathsWouldBeIgnoredByParcelWatcher: [ // note: expectations should be relative from cwd; assertion helper converts // the values received by parcelWatcher to match before testing them (see typedoc) './foo/some-output.ts', // output file 'foo/some-output.ts', // output file ], } ); }); // NOTE: Each individual aspect of this test should be covered by its own isolated test above, // so if one of those is failing, this should be failing too. This big test was written first, // and then broken into the individual tests, but we may as well keep it here. // However, all instances of "foo" have been changed to "fuzz", so that if a test fails, // ctrl+f for the failing expectation will be easier to find the right place test('all expectations also work in a big combined config', async () => { vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); const onWatchTriggeredMock = vi.fn(); const { stopWatching, dispatchChange } = await setupMockWatcher({ filepath: './fuzz/some-config.ts', config: { hooks: { onWatchTriggered: onWatchTriggeredMock }, schema: [ './fuzz/something.ts', './fuzz/**/match-schema-everywhere.graphql', '!**/exclude-schema-everywhere.graphql', ], watch: ['!**/exclude-watch-everywhere.graphql', 'fuzz/**/match-watch-everywhere.graphql'], documents: ['fuzz/**/match-doc-everywhere.graphql', '!**/exclude-doc-everywhere.graphql'], generates: { // globally inclued paths should be included even when a local pattern negates them ['./fuzz/local-exclusions-dont-precede-global-inclusions.ts']: { watchPattern: ['!fuzz/global-beats-local/match-watch-everywhere.graphql'], documents: ['!fuzz/global-beats-local/match-doc-everywhere.graphql'], schema: ['!fuzz/global-beats-local/match-schema-everywhere.graphql'], }, // globally negated paths should be excluded even when a local pattern matches them ['./fuzz/local-inclusions-dont-precede-global-exclusions.ts']: { watchPattern: ['fuzz/global-beats-local/exclude-watch-everywhere.graphql'], documents: ['fuzz/global-beats-local/exclude-doc-everywhere.graphql'], schema: ['fuzz/global-beats-local/exclude-schema-everywhere.graphql'], }, // local watchPattern negation should override local documents match ['./fuzz/some-output.ts']: { watchPattern: '!./fuzz/bar/never-watch.graphql', documents: ['./fuzz/bar/*.graphql', '!./fuzz/bar/never.graphql'], }, // local watchPattern negation should override local schema match ['./fuzz/some-other-output.ts']: { documents: './fuzz/some-other-bar/*.graphql', watchPattern: ['!fuzz/some-other-bar/schemas/never-watch-schema.graphql'], schema: ['./fuzz/some-other-bar/schemas/*.graphql', '!fuzz/some-other-bar/schemas/never-schema.graphql'], }, // match in one local group, negation in another local group, should still match ['./fuzz/alphabet/types-no-sigma.ts']: { schema: './fuzz/alphabet/schema/no-sigma.graphql', documents: [ './fuzz/alphabet/queries/*.graphql', // zeta implicitly included (should always match) '!**/sigma.graphql', // sigma excluded here ], }, // match in one local group, negation in another local group, should still match ['./fuzz/alphabet/types-no-zeta.ts']: { schema: './fuzz/alphabet/schema/no-sigma.graphql', documents: [ './fuzz/alphabet/queries/sigma.graphql', // sigma explicitly included (should always match) '!./fuzz/alphabet/queries/zeta.graphql', // zeta excluded here ], }, ['./fuzz/some-preset-bar/']: { preset: 'near-operation-file', presetConfig: { extension: '.generated.tsx', baseTypesPath: 'types.ts', }, documents: ['./fuzz/some-preset-bar/*.graphql'], }, }, }, }); await assertBuildTriggers( { onWatchTriggeredMock, dispatchChange, stopWatching, subscribeCallbackMock, subscribeMock, unsubscribeMock, watchDirectory: join(process.cwd(), 'fuzz'), subscribeOpts: { ignore: [ '**/.git/**', 'local-exclusions-dont-precede-global-inclusions.ts', 'local-inclusions-dont-precede-global-exclusions.ts', 'some-output.ts', 'some-other-output.ts', 'alphabet/types-no-sigma.ts', 'alphabet/types-no-zeta.ts', 'some-preset-bar/**/*.generated.tsx', ], }, }, { shouldTriggerBuild: [ './fuzz/some-config.ts', // config file './fuzz/bar/fizzbuzz.graphql', './fuzz/some-other-bar/schemas/fizzbuzz.graphql', // included by wildcard // // match in one local group, negation in another local group, should still match './fuzz/alphabet/queries/zeta.graphql', // excluded in types-no-zeta, but included in types-no-sigma './fuzz/alphabet/queries/sigma.graphql', // excluded in types-no-sigma, but included in types-no-sigma // // globally inclued paths should be included even when a local pattern negates them // watch './fuzz/match-watch-everywhere.graphql', './fuzz/fizz/match-watch-everywhere.graphql', './fuzz/fizz/buzz/match-watch-everywhere.graphql', './fuzz/fizz/buzz/fuzzbarbaz/match-watch-everywhere.graphql', // doc './fuzz/match-doc-everywhere.graphql', './fuzz/fizz/match-doc-everywhere.graphql', './fuzz/fizz/buzz/match-doc-everywhere.graphql', './fuzz/fizz/buzz/fuzzbarbaz/match-doc-everywhere.graphql', // schema './fuzz/match-schema-everywhere.graphql', './fuzz/fizz/match-schema-everywhere.graphql', './fuzz/fizz/buzz/match-schema-everywhere.graphql', './fuzz/fizz/buzz/fuzzbarbaz/match-schema-everywhere.graphql', ], shouldNotTriggerBuild: [ // // paths outside of watch directory should be excluded '.git/index.lock', // totally unrelated 'match-watch-everywhere.graphql', // would match pattern if under fuzz // // pattern matching should work as expected './fuzz/bar/something.ts', // unrelated file (non-matching extension) './fuzz/some-other-bar/nested/directory/blah.graphql', // no greedy pattern (**/*) to match // // output files should be excluded './fuzz/some-output.ts', // output file (note: should be ignored by parcel anyway) // // locally negated paths should be excluded even when a local pattern matches them './fuzz/bar/never.graphql', // excluded in same document set './fuzz/bar/never-watch.graphql', // excluded by local watchPattern, matched by local docs './fuzz/some-other-bar/schemas/never-schema.graphql', // excluded by local schema group './fuzz/some-other-bar/schemas/never-watch-schema.graphql', // excluded by local watchPattern group // // globally negated paths should be excluded even when a local pattern matches them './fuzz/alphabet/queries/exclude-watch-everywhere.graphql', // included in types-no-sigma.ts, but globaly excluded 'fuzz/global-beats-local/exclude-watch-everywhere.graphql', 'fuzz/global-beats-local/exclude-doc-everywhere.graphql', 'fuzz/global-beats-local/exclude-schema-everywhere.graphql', ], pathsWouldBeIgnoredByParcelWatcher: [ // note: expectations should be relative from cwd; assertion helper converts // the values received by parcelWatcher to match before testing them (see typedoc) './fuzz/some-output.ts', // output file 'fuzz/some-output.ts', // output file ], globsWouldBeIgnoredByParcelWatcher: [ // note: globs are tested for exact match with argument passed to subscribe options, // so they should be specified relative from watchDirectory, _not_ cwd (see typedoc) 'some-preset-bar/**/*.generated.tsx', // output of preset ], } ); }); }); ================================================ FILE: packages/graphql-codegen-cli/tests/watcher.run.spec.ts ================================================ import type { Mock } from 'vitest'; import * as path from 'path'; import { mkdtempSync, mkdirSync, writeFileSync } from 'fs'; import { createWatcher } from '../src/utils/watcher.js'; import { CodegenContext } from '../src/config.js'; /** * waitForNextEvent * @description This function waits for a short amount of time to let async things run * e.g. watcher subscription setup, watcher to react to change/create events, etc. */ const waitForNextEvent = async () => { return await new Promise(resolve => setTimeout(resolve, 500)); }; type TestFilePaths = { absolute: string; relative: string }; const setupTestFiles = (): { testDir: string; schemaFile: TestFilePaths; documentFile: TestFilePaths } => { const tempDir = path.join(__dirname, '..', 'temp'); mkdirSync(tempDir, { recursive: true }); const testDir = mkdtempSync(path.join(tempDir, 'watcher-run-spec-')); const schemaFileAbsolute = path.join(testDir, 'schema.graphql'); const schemaFile = { absolute: schemaFileAbsolute, relative: path.relative(process.cwd(), schemaFileAbsolute), }; const documentFileAbsolute = path.join(testDir, 'document.graphql'); const documentFile = { absolute: documentFileAbsolute, relative: path.relative(process.cwd(), documentFileAbsolute), }; return { testDir, schemaFile, documentFile, }; }; const onNextMock = vi.fn(); const setupMockWatcher = async ( codegenContext: ConstructorParameters[0], onNext: Mock = vi.fn().mockResolvedValue([]) ) => { const { stopWatching } = createWatcher(new CodegenContext(codegenContext), onNext); // After creating watcher, wait for a tick for subscription to be completely set up await waitForNextEvent(); return { stopWatching }; }; describe('Watch runs', () => { test('calls onNext correctly on initial runs and subsequent runs', async () => { const { testDir, schemaFile, documentFile } = setupTestFiles(); writeFileSync( schemaFile.absolute, /* GraphQL */ ` type Query { me: User } type User { id: ID! name: String! } ` ); writeFileSync( documentFile.absolute, /* GraphQL */ ` query { me { id } } ` ); await waitForNextEvent(); const { stopWatching } = await setupMockWatcher( { filepath: path.join(testDir, 'codegen.ts'), config: { schema: schemaFile.relative, documents: documentFile.relative, generates: { [path.join(testDir, 'types.ts')]: { plugins: ['typescript'], }, }, }, }, onNextMock ); // 1. Initial setup: onNext in initial run should be called because no errors expect(onNextMock).toHaveBeenCalledTimes(1); // 2. Subsequent run 1: correct document file, so `onNext` is called again because no errors writeFileSync( documentFile.absolute, /* GraphQL */ ` query { me { id name } } ` ); await waitForNextEvent(); expect(onNextMock).toHaveBeenCalledTimes(2); // 3. Subsequent run 2: incorrect document file, so `onNext` is NOT called writeFileSync( documentFile.absolute, /* GraphQL */ ` query { me { id name zzzz # should throw error } } ` ); await waitForNextEvent(); expect(onNextMock).toHaveBeenCalledTimes(2); await stopWatching(); await waitForNextEvent(); }); }); ================================================ FILE: packages/graphql-codegen-cli/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'cli', setupFiles: './vitest.setup.ts', include: ['**/*.spec.ts'], server: { deps: { inline: [ // `@graphql-tools/url-loader` needs to be inlined // because there is a test that triggers dynamically importing `some-fetch` mocked package // Without this, `@graphql-tools/url-loader` acts outside of Vitest mocking // i.e. does not know about the `some-fetch` mocked package '@graphql-tools/url-loader', ], }, }, }, }) ); ================================================ FILE: packages/graphql-codegen-cli/vitest.setup.ts ================================================ import { vi } from 'vitest'; process.env.NO_COLOR = '1'; // When running listr2 tests in generate-and-save.spec.ts, do not add colors to avoid failure in CI as different OS may treat colours differently vi.spyOn(process, 'cwd').mockImplementation(() => __dirname); vi.mock('some-fetch', () => require('./tests/__mocks__/some-fetch.cjs')); ================================================ FILE: packages/graphql-codegen-core/CHANGELOG.md ================================================ # @graphql-codegen/core ## 5.0.1 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^11.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/11.0.0) (from `^10.0.0`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/plugin-helpers@6.0.0 ## 4.0.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/plugin-helpers@5.0.3 ## 4.0.1 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 ## 4.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-tools/schema@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/schema/v/10.0.0) (from `^9.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/utils@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/10.0.0) (from `^9.1.1`, in `dependencies`) - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0)]: - @graphql-codegen/plugin-helpers@5.0.0 ## 3.1.0 ### Minor Changes - [#8723](https://github.com/dotansimha/graphql-code-generator/pull/8723) [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15) Thanks [@kazekyo](https://github.com/kazekyo)! - Introduce a new feature called DocumentTransform. DocumentTransform is a functionality that allows you to modify `documents` before they are processed by plugins. You can use functions passed to the `documentTransforms` option to make changes to GraphQL documents. To use this feature, you can write `documentTransforms` as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { // Make some changes to the documents return documents } } ] } } } export default config ``` For instance, to remove a `@localOnlyDirective` directive from `documents`, you can write the following code: ```js import type { CodegenConfig } from '@graphql-codegen/cli' import { visit } from 'graphql' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { return documents.map(documentFile => { documentFile.document = visit(documentFile.document, { Directive: { leave(node) { if (node.name.value === 'localOnlyDirective') return null } } }) return documentFile }) } } ] } } } export default config ``` DocumentTransform can also be specified by file name. You can create a custom file for a specific transformation and pass it to `documentTransforms`. Let's create the document transform as a file: ```js module.exports = { transform: ({ documents }) => { // Make some changes to the documents return documents } } ``` Then, you can specify the file name as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: ['./my-document-transform.js'] } } } export default config ``` ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - [#8871](https://github.com/dotansimha/graphql-code-generator/pull/8871) [`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5) Thanks [@B2o5T](https://github.com/B2o5T)! - eslint fixes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/plugin-helpers@4.0.0 ## 2.6.8 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81)]: - @graphql-codegen/plugin-helpers@3.1.1 ## 2.6.7 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 ## 2.6.6 ### Patch Changes - [#8606](https://github.com/dotansimha/graphql-code-generator/pull/8606) [`45eb2b18a`](https://github.com/dotansimha/graphql-code-generator/commit/45eb2b18adf25366248bf8d67ef696431db5ee0e) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^9.1.1` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.1.1) (from `9.0.0`, in `dependencies`) - [#8606](https://github.com/dotansimha/graphql-code-generator/pull/8606) [`45eb2b18a`](https://github.com/dotansimha/graphql-code-generator/commit/45eb2b18adf25366248bf8d67ef696431db5ee0e) Thanks [@charlypoly](https://github.com/charlypoly)! - Fix validation issue on fragment/ops naming conflict ## 2.6.5 ### Patch Changes - [#8556](https://github.com/dotansimha/graphql-code-generator/pull/8556) [`64e553c3f`](https://github.com/dotansimha/graphql-code-generator/commit/64e553c3f62618a2aedf122d292e2700fd93d6e1) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.8.0`, in `dependencies`) ## 2.6.4 ### Patch Changes - [#8548](https://github.com/dotansimha/graphql-code-generator/pull/8548) [`516170ef6`](https://github.com/dotansimha/graphql-code-generator/commit/516170ef6cb636c950d560ddf12fa1d2f7ee1c57) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.8.0`, in `dependencies`) - [#8548](https://github.com/dotansimha/graphql-code-generator/pull/8548) [`516170ef6`](https://github.com/dotansimha/graphql-code-generator/commit/516170ef6cb636c950d560ddf12fa1d2f7ee1c57) Thanks [@charlypoly](https://github.com/charlypoly)! - Improve codegen documents and schema validation ## 2.6.3 ### Patch Changes - [#8525](https://github.com/dotansimha/graphql-code-generator/pull/8525) [`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127) Thanks [@charlypoly](https://github.com/charlypoly)! - remove `DetailledError`, not supported by Listr renderer - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/plugin-helpers@2.7.2 ## 2.6.2 ### Patch Changes - [#8207](https://github.com/dotansimha/graphql-code-generator/pull/8207) [`6c7d3e54b`](https://github.com/dotansimha/graphql-code-generator/commit/6c7d3e54bb3cb53d8bbbd25e31c45b66f29f4640) Thanks [@renovate](https://github.com/apps/renovate)! - ### Dependencies Updates - Updated dependency ([`@graphql-tools/schema@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/schema/v/^9.0.0)) (was `^8.5.0`, in `dependencies`) ## 2.6.1 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f)]: - @graphql-codegen/plugin-helpers@2.6.2 ## 2.6.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/plugin-helpers@2.5.0 ## 2.5.1 ### Patch Changes - cb9adeb96: Cache validation of documents - Updated dependencies [cb9adeb96] - @graphql-codegen/plugin-helpers@2.4.1 ## 2.5.0 ### Minor Changes - 754a33715: Performance Profiler --profile ### Patch Changes - Updated dependencies [754a33715] - @graphql-codegen/plugin-helpers@2.4.0 ## 2.4.0 ### Minor Changes - b61dc57cf: feat(core): add graphql@16 in peer dependencies ### Patch Changes - 8643b3bf3: Add GraphQL 16 as a peerDependency - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/plugin-helpers@2.3.2 ## 2.3.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/plugin-helpers@2.3.0 ## 2.2.0 ### Minor Changes - 7c60e5acc: feat(core): ability to skip some specific validation rules with skipDocumentsValidation option ### Patch Changes - Updated dependencies [7c60e5acc] - @graphql-codegen/plugin-helpers@2.2.0 ## 2.1.0 ### Minor Changes - 39773f59b: enhance(plugins): use getDocumentNodeFromSchema and other utilities from @graphql-tools/utils - 440172cfe: support ESM ### Patch Changes - 24185985a: bump graphql-tools package versions - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/plugin-helpers@2.1.0 ## 2.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - d80efdec4: Removed `typescript-compatiblity` since it's no longer maintained. Please migrate your codebase to use the latest output of codegen. - Updated dependencies [b0cb13df4] - @graphql-codegen/plugin-helpers@2.0.0 ## 1.17.10 ### Patch Changes - dfd25caf: chore(deps): bump graphql-tools versions - Updated dependencies [dfd25caf] - @graphql-codegen/plugin-helpers@1.18.7 ## 1.17.9 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/plugin-helpers@1.18.2 ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - ac067ea0: Filter `prepend` and `append` coming from plugins, make sure not to add empty lines when not needed - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/plugin-helpers@1.17.8 ================================================ FILE: packages/graphql-codegen-core/README.md ================================================ # GraphQL Code Generator

    Live demo and full documentation: [the-guild.dev/graphql/codegen](https://the-guild.dev/graphql/codegen) Project repository: [graphql-code-generator](https://github.com/dotansimha/graphql-code-generator) ================================================ FILE: packages/graphql-codegen-core/package.json ================================================ { "name": "@graphql-codegen/core", "version": "5.0.1", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/graphql-codegen-core" }, "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "keywords": [ "gql", "generator", "code", "types", "interfaces", "graphql", "codegen", "apollo", "node", "typescript", "ts", "flow", "types", "d.ts", "typings" ], "author": "Dotan Simha ", "bugs": { "url": "https://github.com/dotansimha/graphql-codegen/issues" }, "homepage": "https://github.com/dotansimha/graphql-codegen#readme", "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-tools/schema": "^10.0.0", "@graphql-tools/utils": "^11.0.0", "tslib": "~2.6.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/graphql-codegen-core/src/codegen.ts ================================================ import { AddToSchemaResult, createNoopProfiler, federationSpec, getCachedDocumentNodeFromSchema, isComplexPluginOutput, Types, } from '@graphql-codegen/plugin-helpers'; import { mergeSchemas } from '@graphql-tools/schema'; import { asArray, Source, validateGraphQlDocuments } from '@graphql-tools/utils'; import { DefinitionNode, DocumentNode, Kind, NameNode, print, specifiedRules, visit } from 'graphql'; import { executePlugin } from './execute-plugin.js'; import { extractHashFromSchema, getSkipDocumentsValidationOption, hasFederationSpec, pickFlag, prioritize, shouldValidateDocumentsAgainstSchema, shouldValidateDuplicateDocuments, } from './utils.js'; import { transformDocuments } from './transform-document.js'; export async function codegen(options: Types.GenerateOptions): Promise { const documents = options.documents || []; const profiler = options.profiler ?? createNoopProfiler(); const skipDocumentsValidation = getSkipDocumentsValidationOption(options); if (documents.length > 0 && shouldValidateDuplicateDocuments(skipDocumentsValidation)) { await profiler.run(async () => validateDuplicateDocuments(documents), 'validateDuplicateDocuments'); } const pluginPackages = Object.keys(options.pluginMap).map(key => options.pluginMap[key]); // merged schema with parts added by plugins const additionalTypeDefs: AddToSchemaResult[] = []; for (const plugin of pluginPackages) { const addToSchema = typeof plugin.addToSchema === 'function' ? plugin.addToSchema(options.config) : plugin.addToSchema; if (addToSchema) { additionalTypeDefs.push(addToSchema); } } const federationInConfig: boolean = pickFlag('federation', options.config); const isFederation = prioritize(federationInConfig, false); if (isFederation && !hasFederationSpec(options.schemaAst || options.schema)) { additionalTypeDefs.push(federationSpec); } // Use mergeSchemas, only if there is no GraphQLSchema provided or the schema should be extended const mergeNeeded = !options.schemaAst || additionalTypeDefs.length > 0; const schemaInstance = await profiler.run(async () => { return mergeNeeded ? mergeSchemas({ // If GraphQLSchema provided, use it schemas: options.schemaAst ? [options.schemaAst] : [], // If GraphQLSchema isn't provided but DocumentNode is, use it to get the final GraphQLSchema typeDefs: options.schemaAst ? additionalTypeDefs : [options.schema, ...additionalTypeDefs], convertExtensions: true, assumeValid: true, assumeValidSDL: true, ...options.config, } as any) : options.schemaAst; }, 'Create schema instance'); const schemaDocumentNode = mergeNeeded || !options.schema ? getCachedDocumentNodeFromSchema(schemaInstance) : options.schema; const documentTransforms = Array.isArray(options.documentTransforms) ? options.documentTransforms : []; const transformedDocuments = await transformDocuments({ ...options, documentTransforms, schema: schemaDocumentNode, schemaAst: schemaInstance, profiler, }); if ( schemaInstance && transformedDocuments.length > 0 && shouldValidateDocumentsAgainstSchema(skipDocumentsValidation) ) { const ignored = ['NoUnusedFragments', 'NoUnusedVariables', 'KnownDirectives']; if (typeof skipDocumentsValidation === 'object' && skipDocumentsValidation.ignoreRules) { ignored.push(...asArray(skipDocumentsValidation.ignoreRules)); } const extraFragments: { importFrom: string; node: DefinitionNode }[] = pickFlag('externalFragments', options.config) || []; const errors = await profiler.run(() => { const fragments = extraFragments.map(f => ({ location: f.importFrom, document: { kind: Kind.DOCUMENT, definitions: [f.node] } as DocumentNode, })); const rules = specifiedRules.filter(rule => !ignored.some(ignoredRule => rule.name.startsWith(ignoredRule))); const schemaHash = extractHashFromSchema(schemaInstance); if (!schemaHash || !options.cache || transformedDocuments.some(d => typeof d.hash !== 'string')) { return Promise.resolve( validateGraphQlDocuments( schemaInstance, [...transformedDocuments.flatMap(d => d.document), ...fragments.flatMap(f => f.document)], rules ) ); } const cacheKey = [schemaHash] .concat(transformedDocuments.map(doc => doc.hash)) .concat(JSON.stringify(fragments)) .join(','); return options.cache('documents-validation', cacheKey, () => Promise.resolve( validateGraphQlDocuments( schemaInstance, [...transformedDocuments.flatMap(d => d.document), ...fragments.flatMap(f => f.document)], rules ) ) ); }, 'Validate documents against schema'); if (errors.length > 0) { throw new Error( `GraphQL Document Validation failed with ${errors.length} errors; ${errors.map((error, index) => `Error ${index}: ${error.stack}`).join('\n\n')}` ); } } const prepend: Set = new Set(); const append: Set = new Set(); const output = await Promise.all( options.plugins.map(async plugin => { const name = Object.keys(plugin)[0]; const pluginPackage = options.pluginMap[name]; const pluginConfig = plugin[name] || {}; const execConfig = typeof pluginConfig === 'object' ? { ...options.config, ...pluginConfig } : pluginConfig; const result = await profiler.run( () => executePlugin( { name, config: execConfig, parentConfig: options.config, schema: schemaDocumentNode, schemaAst: schemaInstance, documents: transformedDocuments, outputFilename: options.filename, allPlugins: options.plugins, skipDocumentsValidation: options.skipDocumentsValidation, pluginContext: options.pluginContext, profiler, }, pluginPackage ), `Plugin ${name}` ); if (typeof result === 'string') { return result || ''; } if (isComplexPluginOutput(result)) { if (result.append && result.append.length > 0) { for (const item of result.append) { if (item) { append.add(item); } } } if (result.prepend && result.prepend.length > 0) { for (const item of result.prepend) { if (item) { prepend.add(item); } } } return result.content || ''; } return ''; }) ); return [...sortPrependValues(Array.from(prepend.values())), ...output, ...Array.from(append.values())] .filter(Boolean) .join('\n'); } function resolveCompareValue(a: string) { if (a.startsWith('/*') || a.startsWith('//') || a.startsWith(' *') || a.startsWith(' */') || a.startsWith('*/')) { return 0; } if (a.startsWith('package')) { return 1; } if (a.startsWith('import')) { return 2; } return 3; } export function sortPrependValues(values: string[]): string[] { return values.sort((a: string, b: string) => { const aV = resolveCompareValue(a); const bV = resolveCompareValue(b); if (aV < bV) { return -1; } if (aV > bV) { return 1; } return 0; }); } function validateDuplicateDocuments(files: Types.DocumentFile[]) { // duplicated names const definitionMap: { [kind: string]: { [name: string]: { paths: Set; contents: Set; }; }; } = {}; function addDefinition( file: Source, node: DefinitionNode & { name?: NameNode }, deduplicatedDefinitions: Set ) { if (typeof node.name !== 'undefined') { definitionMap[node.kind] ||= {}; definitionMap[node.kind][node.name.value] ||= { paths: new Set(), contents: new Set(), }; const definitionKindMap = definitionMap[node.kind]; const length = definitionKindMap[node.name.value].contents.size; definitionKindMap[node.name.value].paths.add(file.location); definitionKindMap[node.name.value].contents.add(print(node)); if (length === definitionKindMap[node.name.value].contents.size) { return null; } } return deduplicatedDefinitions.add(node); } for (const file of files) { const deduplicatedDefinitions = new Set(); visit(file.document, { OperationDefinition(node) { addDefinition(file, node, deduplicatedDefinitions); }, FragmentDefinition(node) { addDefinition(file, node, deduplicatedDefinitions); }, }); (file.document as any).definitions = Array.from(deduplicatedDefinitions); } const kinds = Object.keys(definitionMap); for (const kind of kinds) { const definitionKindMap = definitionMap[kind]; const names = Object.keys(definitionKindMap); if (names.length) { const duplicated = names.filter(name => definitionKindMap[name].contents.size > 1); if (!duplicated.length) { continue; } const list = duplicated .map(name => ` * ${name} found in: ${[...definitionKindMap[name].paths] .map(filepath => { return ` - ${filepath} `.trimEnd(); }) .join('')} `.trimEnd() ) .join(''); const definitionKindName = kind.replace('Definition', '').toLowerCase(); throw new Error( `Not all ${definitionKindName}s have an unique name: ${duplicated.join(', ')}: \n ${list} ` ); } } } ================================================ FILE: packages/graphql-codegen-core/src/execute-plugin.ts ================================================ import { CodegenPlugin, createNoopProfiler, Profiler, Types } from '@graphql-codegen/plugin-helpers'; import { buildASTSchema, DocumentNode, GraphQLSchema } from 'graphql'; export interface ExecutePluginOptions { name: string; config: Types.PluginConfig; parentConfig: Types.PluginConfig; schema: DocumentNode; schemaAst?: GraphQLSchema; documents: Types.DocumentFile[]; outputFilename: string; allPlugins: Types.ConfiguredPlugin[]; skipDocumentsValidation?: Types.SkipDocumentsValidationOptions; pluginContext?: { [key: string]: any }; profiler?: Profiler; } export async function executePlugin(options: ExecutePluginOptions, plugin: CodegenPlugin): Promise { if (!plugin?.plugin || typeof plugin.plugin !== 'function') { throw new Error( `Invalid Custom Plugin "${options.name}" \n Plugin ${options.name} does not export a valid JS object with "plugin" function. Make sure your custom plugin is written in the following form: module.exports = { plugin: (schema, documents, config) => { return 'my-custom-plugin-content'; }, }; ` ); } const outputSchema: GraphQLSchema = options.schemaAst || buildASTSchema(options.schema, options.config as any); const documents = options.documents || []; const pluginContext = options.pluginContext || {}; const profiler = options.profiler ?? createNoopProfiler(); if (plugin.validate && typeof plugin.validate === 'function') { try { // FIXME: Sync validate signature with plugin signature await profiler.run( async () => plugin.validate( outputSchema, documents, options.config, options.outputFilename, options.allPlugins, pluginContext ), `Plugin ${options.name} validate` ); } catch (e) { throw new Error( `Plugin "${options.name}" validation failed: \n ${e.message} ` ); } } return profiler.run( () => Promise.resolve( plugin.plugin( outputSchema, documents, typeof options.config === 'object' ? { ...options.config } : options.config, { outputFile: options.outputFilename, allPlugins: options.allPlugins, pluginContext, } ) ), `Plugin ${options.name} execution` ); } ================================================ FILE: packages/graphql-codegen-core/src/index.ts ================================================ export { codegen } from './codegen.js'; export { executePlugin, ExecutePluginOptions } from './execute-plugin.js'; ================================================ FILE: packages/graphql-codegen-core/src/transform-document.ts ================================================ import { createNoopProfiler, Types } from '@graphql-codegen/plugin-helpers'; export async function transformDocuments(options: Types.GenerateOptions): Promise { const documentTransforms = options.documentTransforms || []; let documents = options.documents; if (documentTransforms.length === 0 || options.documents.length === 0) { return documents; } const profiler = options.profiler ?? createNoopProfiler(); for (const documentTransform of documentTransforms) { const config = typeof documentTransform.config === 'object' ? { ...options.config, ...documentTransform.config, } : {}; const { transform } = documentTransform.transformObject; if (transform && typeof transform === 'function') { const name = documentTransform.name; try { await profiler.run(async () => { documents = await transform({ documents, schema: options.schema, config, pluginContext: options.pluginContext, }); }, `DocumentTransform "${name}" execution`); } catch (e) { throw new Error( `DocumentTransform "${name}" failed: \n ${e.message} ` ); } } else { throw new Error(`Missing 'transform' function in "${documentTransform.name}"`); } } return documents; } ================================================ FILE: packages/graphql-codegen-core/src/utils.ts ================================================ import { Types } from '@graphql-codegen/plugin-helpers'; import { isDocumentNode } from '@graphql-tools/utils'; import { DocumentNode, GraphQLSchema, isSchema, Kind } from 'graphql'; export function isObjectMap(obj: any): obj is Types.PluginConfig { return obj && typeof obj === 'object' && !Array.isArray(obj); } export function prioritize(...values: T[]): T { const picked = values.find(val => typeof val === 'boolean'); if (typeof picked !== 'boolean') { return values[values.length - 1]; } return picked; } export function pickFlag(flag: TKey, config: TConfig): TConfig[TKey] | undefined { return isObjectMap(config) ? config[flag] : undefined; } export function shouldValidateDuplicateDocuments( skipDocumentsValidationOption: Types.GenerateOptions['skipDocumentsValidation'] ) { // If the value is true, skip all if (skipDocumentsValidationOption === true) { return false; } // If the value is object with the specific flag, only skip this one if (typeof skipDocumentsValidationOption === 'object' && skipDocumentsValidationOption.skipDuplicateValidation) { return false; } // If the value is falsy or the specific flag is not set, validate return true; } export function shouldValidateDocumentsAgainstSchema( skipDocumentsValidationOption: Types.GenerateOptions['skipDocumentsValidation'] ) { // If the value is true, skip all if (skipDocumentsValidationOption === true) { return false; } // If the value is object with the specific flag, only skip this one if (typeof skipDocumentsValidationOption === 'object' && skipDocumentsValidationOption.skipValidationAgainstSchema) { return false; } // If the value is falsy or the specific flag is not set, validate return true; } export function getSkipDocumentsValidationOption(options: Types.GenerateOptions): Types.SkipDocumentsValidationOptions { // If the value is set on the root level if (options.skipDocumentsValidation) { return options.skipDocumentsValidation; } // If the value is set under `config` property const flagFromConfig: Types.SkipDocumentsValidationOptions = pickFlag('skipDocumentsValidation', options.config); if (flagFromConfig) { return flagFromConfig; } return false; } const federationDirectives = ['key', 'requires', 'provides', 'external']; export function hasFederationSpec(schemaOrAST: GraphQLSchema | DocumentNode) { if (isSchema(schemaOrAST)) { return federationDirectives.some(directive => schemaOrAST.getDirective(directive)); } if (isDocumentNode(schemaOrAST)) { return schemaOrAST.definitions.some( def => def.kind === Kind.DIRECTIVE_DEFINITION && federationDirectives.includes(def.name.value) ); } return false; } export function extractHashFromSchema(schema: GraphQLSchema): string | null { schema.extensions ||= {}; return (schema.extensions['hash'] as string) ?? null; } ================================================ FILE: packages/graphql-codegen-core/tests/prepend.spec.ts ================================================ import { sortPrependValues } from '../src/codegen.js'; describe('sortPrependValues', () => { it('Should sort and use the correct order', () => { const strings: string[] = [`import `, '/* comment */', `// This is a comment`]; const sorted = sortPrependValues(strings); expect(sorted).toEqual(['/* comment */', `// This is a comment`, `import `]); }); }); ================================================ FILE: packages/graphql-codegen-core/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'core', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/other/add/CHANGELOG.md ================================================ # @graphql-codegen/add ## 6.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/plugin-helpers@6.0.0 ## 5.0.3 ### Patch Changes - [#9987](https://github.com/dotansimha/graphql-code-generator/pull/9987) [`5501c62`](https://github.com/dotansimha/graphql-code-generator/commit/5501c621f19eb5ef8e703a21f7367e07e41f199c) Thanks [@taro-28](https://github.com/taro-28)! - Export configuration types (e.g. `AddPluginConfig`) from the entry point. ```ts import type { AddPluginConfig } from '@graphql-codegen/add' ``` ## 5.0.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/plugin-helpers@5.0.3 ## 5.0.1 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 ## 5.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0)]: - @graphql-codegen/plugin-helpers@5.0.0 ## 4.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 ## 4.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/plugin-helpers@4.0.0 ## 3.2.3 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81)]: - @graphql-codegen/plugin-helpers@3.1.1 ## 3.2.2 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 ## 3.2.1 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f)]: - @graphql-codegen/plugin-helpers@2.6.2 ## 3.2.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/plugin-helpers@2.5.0 ## 3.1.1 ### Patch Changes - 8643b3bf3: Add GraphQL 16 as a peerDependency - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/plugin-helpers@2.3.2 ## 3.1.0 ### Minor Changes - 440172cfe: support ESM ### Patch Changes - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/plugin-helpers@2.1.0 ## 3.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [b0cb13df4] - @graphql-codegen/plugin-helpers@2.0.0 ## 2.0.2 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/plugin-helpers@1.18.2 ## 2.0.1 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - ac067ea0: Fix for empty lines added by add plugin - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/plugin-helpers@1.17.8 ## 2.0.0 ### Major Changes - bc6e5c08: Update plugin configuration API to use object only (`string` is no longer supported) ## Migration Notes #### Before ```yaml plugins: - add: 'some string' ``` #### After ```yaml plugins: - add: content: 'some string' ``` ================================================ FILE: packages/plugins/other/add/package.json ================================================ { "name": "@graphql-codegen/add", "version": "6.0.0", "description": "GraphQL Code Generator plugin for adding custom content to your output file", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/other/add" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/other/add/src/config.ts ================================================ export interface AddPluginConfig { /** * @default prepend * @description Allow you to choose where to add the content. */ placement?: 'prepend' | 'content' | 'append'; /** * @description The actual content you wish to add, either a string or array of strings. * You can also specify a path to a local file and the content if it will be loaded by codegen. */ content: string | string[]; } export const VALID_PLACEMENTS: AddPluginConfig['placement'][] = ['prepend', 'content', 'append']; ================================================ FILE: packages/plugins/other/add/src/index.ts ================================================ import { PluginFunction, Types } from '@graphql-codegen/plugin-helpers'; import { GraphQLSchema } from 'graphql'; import { AddPluginConfig, VALID_PLACEMENTS } from './config.js'; export * from './config.js'; export const plugin: PluginFunction = async ( schema: GraphQLSchema, documents: Types.DocumentFile[], config: AddPluginConfig ): Promise => { const placement: AddPluginConfig['placement'] = config.placement || 'prepend'; const { content } = config; if (!VALID_PLACEMENTS.includes(placement)) { throw Error( `Configuration provided for 'add' plugin is invalid: value of 'placement' field is not valid (valid values are: ${VALID_PLACEMENTS.join( ', ' )})` ); } if (!content) { throw Error(`Configuration provided for 'add' plugin is invalid: "content" is missing!`); } return { content: null, [placement]: Array.isArray(content) ? content : [content], }; }; export default { plugin }; ================================================ FILE: packages/plugins/other/add/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'add', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/other/fragment-matcher/CHANGELOG.md ================================================ # @graphql-codegen/fragment-matcher ## 6.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/plugin-helpers@6.0.0 ## 5.1.0 ### Minor Changes - [#10214](https://github.com/dotansimha/graphql-code-generator/pull/10214) [`81b20f5`](https://github.com/dotansimha/graphql-code-generator/commit/81b20f5ab35bf73e7797580ba22c910aecdeddbd) Thanks [@tgandrews](https://github.com/tgandrews)! - Add new flag to make the fragment matcher results deterministic ## 5.0.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/plugin-helpers@5.0.3 ## 5.0.1 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 ## 5.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0)]: - @graphql-codegen/plugin-helpers@5.0.0 ## 4.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 ## 4.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/plugin-helpers@4.0.0 ## 3.3.3 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81)]: - @graphql-codegen/plugin-helpers@3.1.1 ## 3.3.2 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 ## 3.3.1 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f)]: - @graphql-codegen/plugin-helpers@2.6.2 ## 3.3.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/plugin-helpers@2.5.0 ## 3.2.1 ### Patch Changes - 8643b3bf3: Add GraphQL 16 as a peerDependency - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/plugin-helpers@2.3.2 ## 3.2.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/plugin-helpers@2.3.0 ## 3.1.0 ### Minor Changes - 440172cfe: support ESM ### Patch Changes - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/plugin-helpers@2.1.0 ## 3.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [b0cb13df4] - @graphql-codegen/plugin-helpers@2.0.0 ## 2.0.1 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/plugin-helpers@1.18.2 ## 2.0.0 ### Major Changes - 5e792ff3: **BREAKING CHANGE:** Change the default Apollo-Client version to be "3". If you are upgrading from v1 of this plugin, and you are using apollo-client v2, please make sure to add to your config: ```yaml apolloClientVersion: 2 ``` ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/plugin-helpers@1.17.8 ================================================ FILE: packages/plugins/other/fragment-matcher/package.json ================================================ { "name": "@graphql-codegen/fragment-matcher", "version": "6.0.0", "description": "graphql-code-generate plugin for generating fragments matcher introspection file", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/other/fragment-matcher" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/other/fragment-matcher/src/index.ts ================================================ import { extname } from 'path'; import { PluginFunction, PluginValidateFn, removeFederation, Types } from '@graphql-codegen/plugin-helpers'; import { execute, GraphQLSchema, parse } from 'graphql'; interface IntrospectionResultData { __schema: { types: { kind: string; name: string; possibleTypes: | { name: string; }[] | null; }[]; }; } interface PossibleTypesResultData { possibleTypes: { [key: string]: string[]; }; } /** * @description This plugin generates an introspection file but only with Interfaces and Unions, based on your GraphQLSchema. * * If you are using `apollo-client` and your schema contains `interface` or `union` declaration, it's recommended to use Apollo's Fragment Matcher and the result generated by the plugin. * * You can read more about it in [`apollo-client` documentation](https://apollographql.com/docs/react/data/fragments/#fragments-on-unions-and-interfaces). * * Fragment Matcher plugin accepts a TypeScript / JavaScript or a JSON file as an output _(`.ts, .tsx, .js, .jsx, .json`)_. * * Both in TypeScript and JavaScript a default export is being used. * * > The output is based on the output you choose for the output file name. */ export interface FragmentMatcherConfig { /** * @description Compatible only with JSON extension, allow you to choose the export type, either `module.exports` or `export default`. Allowed values are: `commonjs`, `es2015`. * @default es2015 * * @exampleMarkdown * ```tsx {10} filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * schema: 'https://localhost:4000/graphql', * documents: ['src/**\/*.tsx'], * generates: { * 'path/to/file.json': { * plugins: ['fragment-matcher'], * config: { * module: 'commonjs', * }, * }, * }, * }; * export default config; * ``` */ module?: 'commonjs' | 'es2015'; /** * @description Compatible only with TS/TSX/JS/JSX extensions, allow you to generate output based on your Apollo Client version. Note: `3` also works for version 4. * @default 3 * * @exampleMarkdown * ```tsx {10} filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * schema: 'https://localhost:4000/graphql', * documents: ['src/**\/*.tsx'], * generates: { * 'path/to/file.json': { * plugins: ['fragment-matcher'], * config: { * apolloClientVersion: 3, * }, * }, * }, * }; * export default config; * ``` */ apolloClientVersion?: 2 | 3; /** * @description Create an explicit type based on your schema. This can help IDEs autofill your fragment matcher. This is mostly useful if you do more with your fragment matcher than just pass it to an Apollo-Client. * @default false * * @exampleMarkdown * ```tsx {10} filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * schema: 'https://localhost:4000/graphql', * documents: ['src/**\/*.tsx'], * generates: { * 'path/to/file.json': { * plugins: ['fragment-matcher'], * config: { * useExplicitTyping: true * }, * }, * }, * }; * export default config; * ``` */ useExplicitTyping?: boolean; federation?: boolean; /** * @description When enabled sorts the fragment types lexicographically. This is useful for deterministic output. * @default false */ deterministic?: boolean; } const extensions = { ts: ['.ts', '.tsx'], js: ['.js', '.jsx'], json: ['.json'], }; export const plugin: PluginFunction = async ( schema: GraphQLSchema, _documents, pluginConfig: FragmentMatcherConfig, info ): Promise => { const config: Required = { module: 'es2015', federation: false, apolloClientVersion: 3, useExplicitTyping: false, deterministic: false, ...pluginConfig, }; const apolloClientVersion = parseInt(config.apolloClientVersion as any); const cleanSchema = config.federation ? removeFederation(schema) : schema; const { useExplicitTyping } = config; const introspection = (await execute({ schema: cleanSchema, document: parse(` { __schema { types { kind name possibleTypes { name } } } } `), })) as any; const ext = extname(info.outputFile).toLowerCase(); if (!introspection.data) { throw new Error(`Plugin "fragment-matcher" couldn't introspect the schema`); } const sortStringsLexicographically = (a: string, b: string) => { if (!config.deterministic) { return 0; } return a.localeCompare(b); }; const unionAndInterfaceTypes = introspection.data.__schema.types .filter(type => type.kind === 'UNION' || type.kind === 'INTERFACE') .sort((a, b) => sortStringsLexicographically(a.name, b.name)); const createPossibleTypesCollection = (acc, type) => { return { ...acc, [type.name]: type.possibleTypes.map(possibleType => possibleType.name).sort(sortStringsLexicographically), }; }; const filteredData: IntrospectionResultData | PossibleTypesResultData = apolloClientVersion === 2 ? { __schema: { ...introspection.data.__schema, types: unionAndInterfaceTypes, }, } : { possibleTypes: unionAndInterfaceTypes.reduce(createPossibleTypesCollection, {}), }; const content = JSON.stringify(filteredData, null, 2); if (extensions.json.includes(ext)) { return content; } if (extensions.js.includes(ext)) { const defaultExportStatement = config.module === 'es2015' ? `export default` : 'module.exports ='; return ` ${defaultExportStatement} ${content} `; } if (extensions.ts.includes(ext)) { let typename: string; if (apolloClientVersion === 2) { typename = `IntrospectionResultData`; } else if (apolloClientVersion === 3) { typename = `PossibleTypesResultData`; } let type: string; if (useExplicitTyping) { type = `export type ${typename} = ${content};`; } else if (apolloClientVersion === 2) { type = `export interface ${typename} { __schema: { types: { kind: string; name: string; possibleTypes: { name: string; }[]; }[]; }; }`; } else if (apolloClientVersion === 3) { type = `export interface ${typename} { possibleTypes: { [key: string]: string[] } }`; } return ` ${type} const result: ${typename} = ${content}; export default result; `; } throw new Error(`Extension ${ext} is not supported`); }; export const validate: PluginValidateFn = async ( _schema: GraphQLSchema, _documents: Types.DocumentFile[], config: FragmentMatcherConfig, outputFile: string ) => { const ext = extname(outputFile).toLowerCase(); const all = Object.values(extensions).reduce((acc, exts) => [...acc, ...exts], []); if (!all.includes(ext)) { throw new Error( `Plugin "fragment-matcher" requires extension to be one of ${all.map(val => val.replace('.', '')).join(', ')}!` ); } if (config.module === 'commonjs' && extensions.ts.includes(ext)) { throw new Error(`Plugin "fragment-matcher" doesn't support commonjs modules combined with TypeScript!`); } }; ================================================ FILE: packages/plugins/other/fragment-matcher/tests/plugin.spec.ts ================================================ import '@graphql-codegen/testing'; import { codegen } from '@graphql-codegen/core'; import { buildASTSchema, parse } from 'graphql'; import gql from 'graphql-tag'; import { plugin, validate } from '../src/index.js'; const schema = buildASTSchema(gql` type Character { name: String } type Jedi { side: String } type Droid { model: String } union People = Character | Jedi | Droid type Query { allPeople: [People] } `); // should only contain Unions and Interfaces const introspection = JSON.stringify( { __schema: { types: [ { kind: 'UNION', name: 'People', possibleTypes: [ { name: 'Character', }, { name: 'Jedi', }, { name: 'Droid', }, ], }, ], }, }, null, 2 ); const apolloClient3Result = JSON.stringify( { possibleTypes: { People: ['Character', 'Jedi', 'Droid'], }, }, null, 2 ); describe('Fragment Matcher Plugin', () => { describe('validate', () => { it('should not throw on tsx?, jsx?, json files, both in lower and upper case', async () => { const extensions = ['.json', '.js', '.jsx', '.ts', '.tsx']; const allCases = extensions.concat(extensions.map(val => val.toUpperCase())); try { await Promise.all(allCases.map(ext => validate(schema, [], {}, `foo${ext}`, []))); throw new Error('DONE'); } catch (e) { expect(e.message).toEqual('DONE'); } }); it('should throw on commonjs + ts', async () => { try { await validate(schema, [], { module: 'commonjs' }, 'foo.ts', []); throw new Error('SHOULD_NOT_BE_HERE'); } catch (e) { expect(e.message).toContain('commonjs'); } }); it('should throw on unsupported extension', async () => { try { await validate(schema, [], {}, 'foo.yml', []); throw new Error('SHOULD_NOT_BE_HERE'); } catch (e) { expect(e.message).toContain('extension'); } }); }); describe('JSON', () => { it('should stringify the result', async () => { const content = await plugin( schema, [], { apolloClientVersion: 2, }, { outputFile: 'foo.json', } ); expect(content).toEqual(introspection); }); }); describe('JavaScript', () => { it('should use es2015 module by default', async () => { const jsContent = await plugin( schema, [], { apolloClientVersion: 2, }, { outputFile: 'foo.js', } ); const jsxContent = await plugin( schema, [], { apolloClientVersion: 2, }, { outputFile: 'foo.jsx', } ); const output = ` export default ${introspection} `; expect(jsContent).toBeSimilarStringTo(output); expect(jsxContent).toBeSimilarStringTo(output); }); it('should be able to use commonjs', async () => { const jsContent = await plugin( schema, [], { apolloClientVersion: 2, module: 'commonjs', }, { outputFile: 'foo.js', } ); const jsxContent = await plugin( schema, [], { apolloClientVersion: 2, module: 'commonjs', }, { outputFile: 'foo.jsx', } ); const output = ` module.exports = ${introspection} `; expect(jsContent).toBeSimilarStringTo(output); expect(jsxContent).toBeSimilarStringTo(output); }); }); describe('TypeScript', () => { it('should use es2015 module by default', async () => { const tsContent = await plugin( schema, [], { apolloClientVersion: 2, }, { outputFile: 'foo.ts', } ); const tsxContent = await plugin( schema, [], { apolloClientVersion: 2, }, { outputFile: 'foo.tsx', } ); const output = ` export interface IntrospectionResultData { __schema: { types: { kind: string; name: string; possibleTypes: { name: string; }[]; }[]; }; } const result: IntrospectionResultData = ${introspection}; export default result; `; expect(tsContent).toBeSimilarStringTo(output); expect(tsxContent).toBeSimilarStringTo(output); }); it('should use es2015 module by default - apollo client 3', async () => { const tsContent = await plugin( schema, [], { apolloClientVersion: 3, }, { outputFile: 'foo.ts', } ); const tsxContent = await plugin( schema, [], { apolloClientVersion: 3, }, { outputFile: 'foo.tsx', } ); const output = ` export interface PossibleTypesResultData { possibleTypes: { [key: string]: string[] } } const result: PossibleTypesResultData = ${apolloClient3Result}; export default result; `; expect(tsContent).toBeSimilarStringTo(output); expect(tsxContent).toBeSimilarStringTo(output); }); it('should use es2015 even though commonjs is requested', async () => { const tsContent = await plugin( schema, [], { module: 'commonjs', }, { outputFile: 'foo.ts', } ); const tsxContent = await plugin( schema, [], { module: 'commonjs', }, { outputFile: 'foo.tsx', } ); const output = ` export default result; `; expect(tsContent).toBeSimilarStringTo(output); expect(tsxContent).toBeSimilarStringTo(output); }); it('should support exportAsConst for apolloClientVersion 2', async () => { const tsContent = await plugin( schema, [], { apolloClientVersion: 2, useExplicitTyping: true, }, { outputFile: 'foo.ts', } ); const tsxContent = await plugin( schema, [], { apolloClientVersion: 2, useExplicitTyping: true, }, { outputFile: 'foo.tsx', } ); const output = ` export type IntrospectionResultData = ${introspection}; const result: IntrospectionResultData = ${introspection}; export default result; `; expect(tsContent).toBeSimilarStringTo(output); expect(tsxContent).toBeSimilarStringTo(output); }); it('should support useExplicitTyping for apolloClientVersion 3', async () => { const tsContent = await plugin( schema, [], { apolloClientVersion: 3, useExplicitTyping: true, }, { outputFile: 'foo.ts', } ); const tsxContent = await plugin( schema, [], { apolloClientVersion: 3, useExplicitTyping: true, }, { outputFile: 'foo.tsx', } ); const output = ` export type PossibleTypesResultData = ${apolloClient3Result}; const result: PossibleTypesResultData = ${apolloClient3Result}; export default result; `; expect(tsContent).toBeSimilarStringTo(output); expect(tsxContent).toBeSimilarStringTo(output); }); }); it('should support Apollo Federation', async () => { const federatedSchema = parse(/* GraphQL */ ` type Character @key(fields: "id") { id: ID name: String } type Jedi @key(fields: "id") { id: ID side: String } type Droid @key(fields: "id") { id: ID model: String } union People = Character | Jedi | Droid type Query { allPeople: [People] } `); const content = await codegen({ filename: 'foo.json', schema: federatedSchema, documents: [], plugins: [ { 'fragment-matcher': {}, }, ], config: { federation: true, apolloClientVersion: 2, }, pluginMap: { 'fragment-matcher': { plugin, validate, }, }, }); expect(content).toEqual(introspection); }); it('should support Apollo Federation with predefined directive definitions', async () => { const federatedSchema = parse(/* GraphQL */ ` directive @key(fields: String!) on FIELD_DEFINITION type Character @key(fields: "id") { id: ID name: String } type Jedi @key(fields: "id") { id: ID side: String } type Droid @key(fields: "id") { id: ID model: String } union People = Character | Jedi | Droid type Query { allPeople: [People] } `); const content = await codegen({ filename: 'foo.json', schema: federatedSchema, documents: [], plugins: [ { 'fragment-matcher': {}, }, ], config: { apolloClientVersion: 2, federation: true, }, pluginMap: { 'fragment-matcher': { plugin, validate, }, }, }); expect(content).toEqual(introspection); }); it('should create the result deterministically when configured to', async () => { const complexSchema = buildASTSchema(gql` type Droid { model: String } type Character { name: String } type Jedi { side: String } union People = Jedi | Droid | Character union People2 = Droid | Jedi | Character type Query { allPeople: [People] } `); const reorderedComplexSchema = buildASTSchema(gql` type Droid { model: String } type Character { name: String } type Jedi { side: String } union People2 = Droid | Jedi | Character union People = Jedi | Droid | Character type Query { allPeople: [People] } `); const contentA = await plugin( complexSchema, [], { apolloClientVersion: 2, deterministic: true, }, { outputFile: 'foo.json', } ); const contentB = await plugin( reorderedComplexSchema, [], { apolloClientVersion: 2, deterministic: true, }, { outputFile: 'foo.json', } ); expect(contentA).toEqual(contentB); }); }); ================================================ FILE: packages/plugins/other/fragment-matcher/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'fragment-matcher', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/other/introspection/CHANGELOG.md ================================================ # @graphql-codegen/introspection ## 5.0.1 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-codegen/visitor-plugin-common@^6.2.3` ↗︎](https://www.npmjs.com/package/@graphql-codegen/visitor-plugin-common/v/6.2.3) (from `^6.0.0`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 - @graphql-codegen/visitor-plugin-common@6.2.4 ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/visitor-plugin-common@6.0.0 - @graphql-codegen/plugin-helpers@6.0.0 ## 4.0.3 ### Patch Changes - Updated dependencies [[`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5)]: - @graphql-codegen/visitor-plugin-common@5.0.0 ## 4.0.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/visitor-plugin-common@4.1.2 - @graphql-codegen/plugin-helpers@5.0.3 ## 4.0.1 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 - @graphql-codegen/visitor-plugin-common@4.1.0 ## 4.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96), [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c), [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d), [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0), [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c)]: - @graphql-codegen/plugin-helpers@5.0.0 - @graphql-codegen/visitor-plugin-common@4.0.0 ## 3.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 - @graphql-codegen/visitor-plugin-common@3.0.1 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/visitor-plugin-common@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 ## 2.2.3 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/visitor-plugin-common@2.13.5 ## 2.2.2 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/visitor-plugin-common@2.13.4 ## 2.2.1 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f), [`47d0a57e2`](https://github.com/dotansimha/graphql-code-generator/commit/47d0a57e27dd0d2334670bfc6c81c45e00ff4e74)]: - @graphql-codegen/visitor-plugin-common@2.12.1 - @graphql-codegen/plugin-helpers@2.6.2 ## 2.2.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [68bb30e19] - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/visitor-plugin-common@2.11.0 - @graphql-codegen/plugin-helpers@2.5.0 ## 2.1.1 ### Patch Changes - 8643b3bf3: Add GraphQL 16 as a peerDependency - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/plugin-helpers@2.3.2 ## 2.1.0 ### Minor Changes - 440172cfe: support ESM ### Patch Changes - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/plugin-helpers@2.1.0 ## 2.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [b0cb13df4] - @graphql-codegen/plugin-helpers@2.0.0 ## 1.18.2 ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - @graphql-codegen/plugin-helpers@1.18.5 ## 1.18.1 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/plugin-helpers@1.18.2 ## 1.18.0 ### Minor Changes - 1731ae2b: allow to pass configuration to introspection plugin ### Patch Changes - Updated dependencies [da8bdd17] - @graphql-codegen/plugin-helpers@1.17.9 ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/plugin-helpers@1.17.8 ================================================ FILE: packages/plugins/other/introspection/package.json ================================================ { "name": "@graphql-codegen/introspection", "version": "5.0.1", "description": "GraphQL Code Generator plugin for generating an introspection JSON file for a GraphQLSchema", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/other/introspection" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-codegen/visitor-plugin-common": "^6.2.4", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/other/introspection/src/index.ts ================================================ import { extname } from 'path'; import { PluginFunction, PluginValidateFn, removeFederation, Types } from '@graphql-codegen/plugin-helpers'; import { getConfigValue } from '@graphql-codegen/visitor-plugin-common'; import { GraphQLSchema, introspectionFromSchema } from 'graphql'; /** * @description This plugin generates a GraphQL introspection file based on your GraphQL schema. */ export interface IntrospectionPluginConfig { /** * @description Set to `true` in order to minify the JSON output. * @default false * * @exampleMarkdown * ```tsx {10} filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * schema: 'https://localhost:4000/graphql', * documents: ['src/**\/*.tsx'], * generates: { * 'introspection.json': { * plugins: ['introspection'], * config: { * minify: true * }, * }, * }, * }; * export default config; * ``` */ minify?: boolean; /** * @description Whether to include descriptions in the introspection result. * @default true */ descriptions?: boolean; /** * @description Whether to include `specifiedByUrl` in the introspection result. * @default false */ specifiedByUrl?: boolean; /** * @description Whether to include `isRepeatable` flag on directives. * @default true */ directiveIsRepeatable?: boolean; /** * @description Whether to include `description` field on schema. * @default false */ schemaDescription?: boolean; // Internal federation?: boolean; } export const plugin: PluginFunction = async ( schema: GraphQLSchema, _documents, pluginConfig: IntrospectionPluginConfig ): Promise => { const cleanSchema = pluginConfig.federation ? removeFederation(schema) : schema; const descriptions = getConfigValue(pluginConfig.descriptions, true); const directiveIsRepeatable = getConfigValue(pluginConfig.directiveIsRepeatable, true); const schemaDescription = getConfigValue(pluginConfig.schemaDescription, undefined); const specifiedByUrl = getConfigValue(pluginConfig.specifiedByUrl, undefined); const introspection = introspectionFromSchema(cleanSchema, { descriptions, directiveIsRepeatable, schemaDescription, specifiedByUrl, }); return pluginConfig.minify ? JSON.stringify(introspection) : JSON.stringify(introspection, null, 2); }; export const validate: PluginValidateFn = async ( schema: GraphQLSchema, documents: Types.DocumentFile[], config: any, outputFile: string ) => { if (extname(outputFile) !== '.json') { throw new Error(`Plugin "introspection" requires extension to be ".json"!`); } }; ================================================ FILE: packages/plugins/other/introspection/tests/introspection.spec.ts ================================================ import { codegen } from '@graphql-codegen/core'; import { buildSchema, introspectionFromSchema, IntrospectionObjectType, IntrospectionQuery, parse } from 'graphql'; import { plugin } from '../src/index.js'; describe('Introspection template', () => { it('should output a JSON file', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { fieldTest: String } schema { query: Query } `); const content = await plugin(schema, [], {}, { outputFile: '' }); const introspection = JSON.stringify( introspectionFromSchema(schema, { descriptions: true, schemaDescription: false, specifiedByUrl: false }), null, 2 ); expect(introspection).toEqual(content); }); it('should output a JSON file minified', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { fieldTest: String } schema { query: Query } `); const content = await plugin(schema, [], { minify: true }, { outputFile: '' }); const introspection = JSON.stringify( introspectionFromSchema(schema, { descriptions: true, schemaDescription: false, specifiedByUrl: false }) ); expect(introspection).toEqual(content); }); it('should support Apollo Federation', async () => { const schema = parse(/* GraphQL */ ` type Character @key(fields: "id") { id: ID name: String } type Jedi @key(fields: "id") { id: ID side: String } type Droid @key(fields: "id") { id: ID model: String } union People = Character | Jedi | Droid type Query { allPeople: [People] } `); const content = await codegen({ filename: 'foo.json', schema, documents: [], plugins: [ { introspection: {}, }, ], config: { federation: true, }, pluginMap: { introspection: { plugin, }, }, }); const introspection: IntrospectionQuery = JSON.parse(content); const { types } = introspection.__schema; const queryType = types.find( type => type.name === introspection.__schema.queryType.name ) as IntrospectionObjectType; // scalar _Any expect(types.some(type => type.name === '_Any')).toBe(false); // union _Entity expect(types.some(type => type.name === '_Entity')).toBe(false); // type _Service expect(types.some(type => type.name === '_Service')).toBe(false); // type Query { _entities, _service } expect(queryType.fields.some(f => f.name === '_entities')).toBe(false); expect(queryType.fields.some(f => f.name === '_service')).toBe(false); }); }); ================================================ FILE: packages/plugins/other/introspection/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'introspection', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/other/schema-ast/CHANGELOG.md ================================================ # @graphql-codegen/schema-ast ## 5.0.1 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^11.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/11.0.0) (from `^10.0.0`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/plugin-helpers@6.0.0 ## 4.1.0 ### Minor Changes - [#10023](https://github.com/dotansimha/graphql-code-generator/pull/10023) [`8f864ef`](https://github.com/dotansimha/graphql-code-generator/commit/8f864ef8aad11f233330c71c467a61c449bf270a) Thanks [@eddeee888](https://github.com/eddeee888)! - Allow .graphqls as schema extension ## 4.0.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/plugin-helpers@5.0.3 ## 4.0.1 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 ## 4.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/10.0.0) (from `^9.0.0`, in `dependencies`) - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0)]: - @graphql-codegen/plugin-helpers@5.0.0 ## 3.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/plugin-helpers@4.0.0 ## 2.6.1 ### Patch Changes - [#8771](https://github.com/dotansimha/graphql-code-generator/pull/8771) [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.8.0`, in `dependencies`) - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 ## 2.6.0 ### Minor Changes - [#8712](https://github.com/dotansimha/graphql-code-generator/pull/8712) [`fedd71cbb`](https://github.com/dotansimha/graphql-code-generator/commit/fedd71cbb7f37440a59032d942cb228df78d52e5) Thanks [@danielwaltz](https://github.com/danielwaltz)! - support gql file extension for schema-ast output ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81)]: - @graphql-codegen/plugin-helpers@3.1.1 ## 2.5.2 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 ## 2.5.1 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f)]: - @graphql-codegen/plugin-helpers@2.6.2 ## 2.5.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/plugin-helpers@2.5.0 ## 2.4.1 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/plugin-helpers@2.3.2 ## 2.4.0 ### Minor Changes - f3833243d: added includeIntrospectionTypes option ### Patch Changes - 6c898efe5: list all dependencies used by the package in the package.json ## 2.3.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/plugin-helpers@2.3.0 ## 2.2.0 ### Minor Changes - 3e38de399: enhance: sort the schema before processing to have more consistent results. You can disable it with `sort: false`. ## 2.1.0 ### Minor Changes - 39773f59b: enhance(plugins): use getDocumentNodeFromSchema and other utilities from @graphql-tools/utils - 440172cfe: support ESM ### Patch Changes - 24185985a: bump graphql-tools package versions - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/plugin-helpers@2.1.0 ## 2.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [b0cb13df4] - @graphql-codegen/plugin-helpers@2.0.0 ## 1.18.3 ### Patch Changes - dfd25caf: chore(deps): bump graphql-tools versions - Updated dependencies [dfd25caf] - @graphql-codegen/plugin-helpers@1.18.7 ## 1.18.2 ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - @graphql-codegen/plugin-helpers@1.18.5 ## 1.18.1 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/plugin-helpers@1.18.2 ## 1.18.0 ### Minor Changes - 2e6f20a6: added support for sorting schemas before printing ### Patch Changes - Updated dependencies [eaf45d1f] - @graphql-codegen/plugin-helpers@1.18.1 ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/plugin-helpers@1.17.8 ================================================ FILE: packages/plugins/other/schema-ast/package.json ================================================ { "name": "@graphql-codegen/schema-ast", "version": "5.0.1", "description": "GraphQL Code Generator plugin for generating a .graphql file from a given schema", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/other/schema-ast" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-tools/utils": "^11.0.0", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/other/schema-ast/src/index.ts ================================================ import { extname } from 'path'; import { getCachedDocumentNodeFromSchema, PluginFunction, PluginValidateFn, removeFederation, Types, } from '@graphql-codegen/plugin-helpers'; import { buildASTSchema, extendSchema, GraphQLSchema, parse, print, printIntrospectionSchema, printSchema, visit, } from 'graphql'; /** * @description This plugin prints the merged schema as string. If multiple schemas are provided, they will be merged and printed as one schema. */ export interface SchemaASTConfig { /** * @description Include directives to Schema output. * @default false * * @exampleMarkdown * ```tsx {9} filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * schema: './src/schema.graphql', * generates: { * 'path/to/file.graphql': { * plugins: ['schema-ast'], * config: { * includeDirectives: true * }, * }, * }, * }; * export default config; * ``` */ includeDirectives?: boolean; /** * @description Include introspection types to Schema output. * @default false * * @exampleMarkdown * ```tsx {9} filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * schema: './src/schema.graphql', * generates: { * 'path/to/file.graphql': { * plugins: ['schema-ast'], * config: { * includeIntrospectionTypes: true * }, * }, * }, * }; * export default config; * ``` */ includeIntrospectionTypes?: boolean; /** * @description Set to true in order to print description as comments (using `#` instead of `"""`) * @default false * * @exampleMarkdown * ```tsx {9} filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * schema: './src/schema.graphql', * generates: { * 'path/to/file.graphql': { * plugins: ['schema-ast'], * config: { * commentDescriptions: true * }, * }, * }, * }; * export default config; * ``` */ commentDescriptions?: boolean; /** * @description Set to false to disable sorting * @default true */ sort?: boolean; federation?: boolean; } export const plugin: PluginFunction = async ( schema: GraphQLSchema, _documents, { commentDescriptions = false, includeDirectives = false, includeIntrospectionTypes = false, sort = false, federation, } ): Promise => { const transformedSchemaAndAst = transformSchemaAST(schema, { sort, federation, includeIntrospectionTypes }); return [ includeIntrospectionTypes ? printIntrospectionSchema(transformedSchemaAndAst.schema) : null, includeDirectives ? print(transformedSchemaAndAst.ast) : (printSchema as any)(transformedSchemaAndAst.schema, { commentDescriptions }), ] .filter(Boolean) .join('\n'); }; export const validate: PluginValidateFn = async ( _schema: GraphQLSchema, _documents: Types.DocumentFile[], _config: SchemaASTConfig, outputFile: string, allPlugins: Types.ConfiguredPlugin[] ) => { const singlePlugin = allPlugins.length === 1; const allowedExtensions = ['.graphql', '.gql', '.graphqls']; const isAllowedExtension = allowedExtensions.includes(extname(outputFile)); if (singlePlugin && !isAllowedExtension) { const allowedExtensionsOutput = allowedExtensions.map(extension => `"${extension}"`).join(' or '); throw new Error(`Plugin "schema-ast" requires extension to be ${allowedExtensionsOutput}!`); } }; export function transformSchemaAST(schema: GraphQLSchema, config: { [key: string]: any }) { schema = config.federation ? removeFederation(schema) : schema; if (config.includeIntrospectionTypes) { // See: https://spec.graphql.org/June2018/#sec-Schema-Introspection const introspectionAST = parse(` extend type Query { __schema: __Schema! __type(name: String!): __Type } `); schema = extendSchema(schema, introspectionAST); } let ast = getCachedDocumentNodeFromSchema(schema); ast = config.disableDescriptions ? visit(ast, { leave: node => ({ ...node, description: undefined, }), }) : ast; schema = config.disableDescriptions ? buildASTSchema(ast) : schema; return { schema, ast, }; } ================================================ FILE: packages/plugins/other/schema-ast/tests/schema-ast.spec.ts ================================================ import '@graphql-codegen/testing'; import { codegen } from '@graphql-codegen/core'; import { Types } from '@graphql-codegen/plugin-helpers'; import { buildSchema, parse, versionInfo } from 'graphql'; import { plugin, validate } from '../src/index.js'; const SHOULD_THROW_ERROR = 'SHOULD_THROW_ERROR'; describe('Schema AST', () => { describe('Validation', () => { it('Should enforce graphql extension when its the only plugin', async () => { const fileName = 'output.ts'; const plugins: Types.ConfiguredPlugin[] = [ { 'schema-ast': {}, }, ]; try { await validate(null, null, null, fileName, plugins); throw new Error(SHOULD_THROW_ERROR); } catch (e) { expect(e.message).not.toBe(SHOULD_THROW_ERROR); expect(e.message).toBe('Plugin "schema-ast" requires extension to be ".graphql" or ".gql" or ".graphqls"!'); } }); it('Should not enforce graphql extension when its not the only plugin', async () => { const fileName = 'output.ts'; const plugins: Types.ConfiguredPlugin[] = [ { add: {}, }, { 'schema-ast': {}, }, ]; try { await validate(null, null, null, fileName, plugins); } catch { expect(true).toBeFalsy(); } }); it('Should allow .graphql extension when its the only plugin', async () => { const fileName = 'output.graphql'; const plugins: Types.ConfiguredPlugin[] = [ { 'schema-ast': {}, }, ]; try { await validate(null, null, null, fileName, plugins); } catch { expect(true).toBeFalsy(); } }); it('Should allow .gql extension when its the only plugin', async () => { const fileName = 'output.gql'; const plugins: Types.ConfiguredPlugin[] = [ { 'schema-ast': {}, }, ]; try { await validate(null, null, null, fileName, plugins); } catch { expect(true).toBeFalsy(); } }); it('Should allow .graphqls extension when its the only plugin', async () => { const fileName = 'output.graphqls'; const plugins: Types.ConfiguredPlugin[] = [ { 'schema-ast': {}, }, ]; try { await validate(null, null, null, fileName, plugins); } catch { expect(true).toBeFalsy(); } }); }); describe('Output', () => { const typeDefs = /* GraphQL */ ` directive @modify(limit: Int) on FIELD_DEFINITION type Query { fieldTest: String @modify(limit: 1) } schema { query: Query } `; const schema = buildSchema(typeDefs); it('Should print schema without directives when "includeDirectives" is unset', async () => { const content = await plugin(schema, [], { includeDirectives: false }); expect(content).toBeSimilarStringTo(` type Query { fieldTest: String } `); }); it('Should print schema with as """ comment as default', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { """ test """ fieldTest: String } `); const content = await plugin(testSchema, [], { includeDirectives: false }); expect(content).toBeSimilarStringTo(` type Query { """test""" fieldTest: String } `); }); if (versionInfo.major < 16) { it('Should print schema with as # when commentDescriptions=true', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { """ test """ fieldTest: String } `); const content = await plugin(testSchema, [], { commentDescriptions: true, includeDirectives: false }); expect(content).toBeSimilarStringTo(` type Query { # test fieldTest: String } `); }); } it('Should print schema with directives when "includeDirectives" is set', async () => { const content = await plugin(schema, [], { includeDirectives: true }); expect(content).toBeSimilarStringTo(` directive @modify(limit: Int) on FIELD_DEFINITION `); expect(content).toBeSimilarStringTo(` type Query { fieldTest: String @modify(limit: 1) } `); }); it('Should print schema with introspection when "includeIntrospectionTypes" is set', async () => { const content = await plugin(schema, [], { includeIntrospectionTypes: true }); expect(content).toBeSimilarStringTo(` type __Schema `); expect(content).toBeSimilarStringTo(` type Query { fieldTest: String __schema: __Schema! __type(name: String!): __Type } `); }); it('Should print schema without introspection when "includeIntrospectionTypes" is unset', async () => { const content = await plugin(schema, [], { includeIntrospectionTypes: false }); expect(content).not.toBeSimilarStringTo(` type __Schema `); expect(content).toBeSimilarStringTo(` type Query { fieldTest: String } `); }); it('should support Apollo Federation', async () => { const federatedSchema = parse(/* GraphQL */ ` type Character @key(fields: "id") { id: ID name: String } type Jedi @key(fields: "id") { id: ID side: String } type Droid @key(fields: "id") { id: ID model: String } union People = Character | Jedi | Droid type Query { allPeople: [People] } `); const content = await codegen({ filename: 'foo.graphql', schema: federatedSchema, documents: [], plugins: [ { 'schema-ast': {}, }, ], config: { federation: true, }, pluginMap: { 'schema-ast': { plugin, validate, }, }, }); expect(content).not.toContain(`scalar _Any`); expect(content).not.toContain(`union _Entity`); expect(content).not.toContain(`type _Service`); expect(content).toBeSimilarStringTo(` type Character { id: ID name: String } type Jedi { id: ID side: String } type Droid { id: ID model: String } union People = Character | Jedi | Droid type Query { allPeople: [People] } `); }); }); }); ================================================ FILE: packages/plugins/other/schema-ast/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'schema-ast', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/other/time/CHANGELOG.md ================================================ # @graphql-codegen/time ## 6.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/plugin-helpers@6.0.0 ## 5.0.1 ### Patch Changes - [#9881](https://github.com/dotansimha/graphql-code-generator/pull/9881) [`68ea5d4`](https://github.com/dotansimha/graphql-code-generator/commit/68ea5d4d18969840c34e42bf4f8237e849af7aab) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`moment@~2.30.0` ↗︎](https://www.npmjs.com/package/moment/v/2.30.0) (from `~2.29.1`, in `dependencies`) ## 5.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0)]: - @graphql-codegen/plugin-helpers@5.0.0 ## 4.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/plugin-helpers@4.0.0 ## 3.2.3 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81)]: - @graphql-codegen/plugin-helpers@3.1.1 ## 3.2.2 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 ## 3.2.1 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f)]: - @graphql-codegen/plugin-helpers@2.6.2 ## 3.2.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/plugin-helpers@2.5.0 ## 3.1.1 ### Patch Changes - 8643b3bf3: Add GraphQL 16 as a peerDependency - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/plugin-helpers@2.3.2 ## 3.1.0 ### Minor Changes - 440172cfe: support ESM ### Patch Changes - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/plugin-helpers@2.1.0 ## 3.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [b0cb13df4] - @graphql-codegen/plugin-helpers@2.0.0 ## 2.0.2 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/plugin-helpers@1.18.2 ## 2.0.1 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/plugin-helpers@1.17.8 ## 2.0.0 ### Major Changes - bc6e5c08: Update plugin configuration API to use object only (`string` is no longer supported) ## Migration Notes This only effects developers who used to override the `format`. You now need to specify it with a key! #### Before ```yaml plugins: - time: 'DD-MM-YYYY' ``` #### After ```yaml plugins: - time: format: 'DD-MM-YYYY' ``` ## 1.17.10 ### Patch Changes - ee2b01a3: Fixes for issues with publish command ## 1.17.9 ### Patch Changes - 6cb9c96d: Fixes issues with previous release ## 1.17.8 ### Patch Changes - bccfd28c: Fix issues with adding time to .graphql files ================================================ FILE: packages/plugins/other/time/package.json ================================================ { "name": "@graphql-codegen/time", "version": "6.0.0", "description": "GraphQL Code Generator plugin for adding the current time for an output file", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/other/time" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", "moment": "~2.30.0" }, "devDependencies": { "moment": "2.30.1" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/other/time/src/config.ts ================================================ export interface TimePluginConfig { /** * @description Customize the Moment format of the output time. * @default YYYY-MM-DDTHH:mm:ssZ * * @exampleMarkdown * ```tsx {10} filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * schema: 'https://localhost:4000/graphql', * documents: ['src/**\/*.tsx'], * generates: { * 'path/to/file.ts': { * plugins: ['time'], * config: { * format: 'DD.MM.YY' * }, * }, * }, * }; * export default config; * ``` */ format?: string; /** * @description Customize the comment message * @default 'Generated on' * * @exampleMarkdown * ```tsx {10} filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * schema: 'https://localhost:4000/graphql', * documents: ['src/**\/*.tsx'], * generates: { * 'path/to/file.ts': { * plugins: ['time'], * config: { * message: 'The file generated on: ' * }, * }, * }, * }; * export default config; * ``` */ message?: string; } ================================================ FILE: packages/plugins/other/time/src/index.ts ================================================ import { extname } from 'path'; import { PluginFunction, Types } from '@graphql-codegen/plugin-helpers'; import { GraphQLSchema } from 'graphql'; // eslint-disable-next-line n/no-restricted-import -- todo: replace moment in v3 import moment from 'moment'; import { TimePluginConfig } from './config.js'; export const plugin: PluginFunction = async ( schema: GraphQLSchema, documents: Types.DocumentFile[], config: TimePluginConfig, { outputFile } ): Promise => { let format: string; let message = 'Generated on '; if (config && typeof config === 'object') { if (config.format) { format = config.format; } if (config.message) { message = config.message; } } const outputFileExtension = outputFile && extname(outputFile); let commentPrefix = '//'; if ((outputFileExtension || '').toLowerCase() === '.graphql') { commentPrefix = '#'; } return commentPrefix + ' ' + message + moment().format(format) + '\n'; }; ================================================ FILE: packages/plugins/other/time/tests/time.spec.ts ================================================ import { plugin } from '../src/index.js'; describe('Time', () => { it('Should use default comment when extension is unknown', async () => { const result = await plugin(null as any, [], null, { outputFile: null }); expect(result).toContain('// Generated on'); }); it('Should use # prefix for comment when extension is graphql', async () => { const result = await plugin(null as any, [], null, { outputFile: 'schema.graphql' }); expect(result).toContain('# Generated on'); }); }); ================================================ FILE: packages/plugins/other/time/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'time', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/other/visitor-plugin-common/CHANGELOG.md ================================================ # @graphql-codegen/visitor-plugin-common ## 6.2.4 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-tools/relay-operation-optimizer@^7.1.1` ↗︎](https://www.npmjs.com/package/@graphql-tools/relay-operation-optimizer/v/7.1.1) (from `^7.0.0`, in `dependencies`) - Updated dependency [`@graphql-tools/utils@^11.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/11.0.0) (from `^10.0.0`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 ## 6.2.3 ### Patch Changes - [#10580](https://github.com/dotansimha/graphql-code-generator/pull/10580) [`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf) Thanks [@Georgegriff](https://github.com/Georgegriff)! - fixed invalid extracted concrete type name on shared interface ## 6.2.2 ### Patch Changes - [#10530](https://github.com/dotansimha/graphql-code-generator/pull/10530) [`f588d91`](https://github.com/dotansimha/graphql-code-generator/commit/f588d91ac43ea0aa5931915ce980d2e6876bb59c) Thanks [@Georgegriff](https://github.com/Georgegriff)! - fix fragment type generation names ## 6.2.1 ### Patch Changes - [#10503](https://github.com/dotansimha/graphql-code-generator/pull/10503) [`b995ed1`](https://github.com/dotansimha/graphql-code-generator/commit/b995ed13a49379ea05e0e313fac68b557527523a) Thanks [@Georgegriff](https://github.com/Georgegriff)! - Use parent type name on interface types without fragments ## 6.2.0 ### Minor Changes - [#10510](https://github.com/dotansimha/graphql-code-generator/pull/10510) [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670) Thanks [@nickmessing](https://github.com/nickmessing)! - add importExtension configuration option ### Patch Changes - [#10512](https://github.com/dotansimha/graphql-code-generator/pull/10512) [`f821e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f821e8ab9351f23a9f7e5d5e6fc69c8e8868cad8) Thanks [@realies](https://github.com/realies)! - fix: allow mappers to override root types (Query, Mutation, Subscription) Previously, mappers configured for root types were ignored because root types were checked before mappers. This fix moves the mapper check before the root type check, allowing mappers to override `rootValueType` when configured. - Updated dependencies [[`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/plugin-helpers@6.1.0 ## 6.1.2 ### Patch Changes - [#10499](https://github.com/dotansimha/graphql-code-generator/pull/10499) [`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix nested fragment not getting correct meta field in Client Preset ## 6.1.1 ### Patch Changes - [#10498](https://github.com/dotansimha/graphql-code-generator/pull/10498) [`6715330`](https://github.com/dotansimha/graphql-code-generator/commit/67153304646694d75aee24afd70c3fce12e9f1f2) Thanks [@ardatan](https://github.com/ardatan)! - Handle schema extension nodes correctly When a schema doesn't have an operation type defined but has `schema extension` definitions with directives like below, schema extensions are not converted to schema definitions by GraphQL Tools. So the visitor should handle schema extension nodes correctly. Follow-up to https://github.com/ardatan/graphql-tools/pull/7679 ```graphql extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"]) type Foo { id: ID! @key name: String } ``` ## 6.1.0 ### Minor Changes - [#10449](https://github.com/dotansimha/graphql-code-generator/pull/10449) [`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26) Thanks [@eddeee888](https://github.com/eddeee888)! - Add addInterfaceFieldResolverTypes option to support custom Interface resolver inheritance ## 6.0.1 ### Patch Changes - [#10412](https://github.com/dotansimha/graphql-code-generator/pull/10412) [`accdab6`](https://github.com/dotansimha/graphql-code-generator/commit/accdab69106605241933e9d66d64dc7077656f30) Thanks [@thekevinbrown](https://github.com/thekevinbrown)! - Add special handling for identifiers that consist entirely of _ characters when transformUnderscore is true. This prevents _ values in GraphQL enums from being emitted without identifers in the resulting types. ## 6.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGES: Do not generate \_\_isTypeOf for non-implementing types or non-union members - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Remove deprecated config option `dedupeFragments` - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Remove NameNode override - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGE: Use Record instead of {} for empty object type - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Ensure Federation Interfaces have `__resolveReference` if they are resolvable entities BREAKING CHANGES: Deprecate `onlyResolveTypeForInterfaces` because majority of use cases cannot implement resolvers in Interfaces. BREAKING CHANGES: Deprecate `generateInternalResolversIfNeeded.__resolveReference` because types do not have `__resolveReference` if they are not Federation entities or are not resolvable. Users should not have to manually set this option. This option was put in to wait for this major version. - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGE: Improve Federation Entity's resolvers' parent param type: These types were using reference types inline. This makes it hard to handle mappers. The Parent type now all comes from ParentResolverTypes to make handling mappers and parent types simpler. - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Bump dependencies major versions: - dependency-graph to v1 - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix `mappers` usage with Federation `mappers` was previously used as `__resolveReference`'s first param (usually called "reference"). However, this is incorrect because `reference` interface comes directly from `@key` and `@requires` directives. This patch fixes the issue by creating a new `FederationTypes` type and use it as the base for federation entity types when being used to type entity references. BREAKING CHANGES: No longer generate `UnwrappedObject` utility type, as this was used to support the wrong previously generated type. - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Minor Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Report to meta user defined objects whether they have isTypeOf resolver ### Patch Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Update @requires type - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix fields or object types marked with @external being wrongly generated - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/plugin-helpers@6.0.0 ## 5.8.0 ### Minor Changes - [#10315](https://github.com/dotansimha/graphql-code-generator/pull/10315) [`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc) Thanks [@eddeee888](https://github.com/eddeee888)! - Implement semanticNonNull custom directive ## 5.7.1 ### Patch Changes - [#10302](https://github.com/dotansimha/graphql-code-generator/pull/10302) [`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix Apollo unmask directive incorrectly generating fragmentRefs ## 5.7.0 ### Minor Changes - [#10270](https://github.com/dotansimha/graphql-code-generator/pull/10270) [`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c) Thanks [@adapap](https://github.com/adapap)! - feat: implement `includeExternalFragments: boolean` option ## 5.6.1 ### Patch Changes - [#10230](https://github.com/dotansimha/graphql-code-generator/pull/10230) [`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix generateInternalResolversIfNeeded.\_\_resolveReference making the resolver required `__resolveReference`'s default behaviour when not declared is to pass the ref to subsequent resolvers i.e. becoming the `parent`. So, it means we don't have to make this resolver required. This patch makes `__resolveReference` optional when `generateInternalResolversIfNeeded.__resolveReference` is set to true. ## 5.6.0 ### Minor Changes - [#10163](https://github.com/dotansimha/graphql-code-generator/pull/10163) [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Add support for Apollo Client `@unmask` directive with fragment masking. ### Patch Changes - [#10187](https://github.com/dotansimha/graphql-code-generator/pull/10187) [`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a) Thanks [@gilgardosh](https://github.com/gilgardosh)! - Fix: type naming for imported enums ## 5.5.0 ### Minor Changes - [#9989](https://github.com/dotansimha/graphql-code-generator/pull/9989) [`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc) Thanks [@eddeee888](https://github.com/eddeee888)! - Add `generateInternalResolversIfNeeded` option This option can be used to generate more correct types for internal resolvers. For example, only generate `__resolveReference` if the federation object has a resolvable `@key`. In the future, this option can be extended to support other internal resolvers e.g. `__isTypeOf` is only generated for implementing types and union members. - [#10141](https://github.com/dotansimha/graphql-code-generator/pull/10141) [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03) Thanks [@eddeee888](https://github.com/eddeee888)! - Add avoidCheckingAbstractTypesRecursively to avoid checking and generating abstract types recursively For users that already sets recursive default mappers e.g. `Partial<{T}>` or `DeepPartial<{T}>`, having both options on will cause a nested loop which eventually crashes Codegen. In such case, setting `avoidCheckingAbstractTypesRecursively: true` allows users to continue to use recursive default mappers as before. ### Patch Changes - Updated dependencies [[`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc)]: - @graphql-codegen/plugin-helpers@5.1.0 ## 5.4.0 ### Minor Changes - [#10077](https://github.com/dotansimha/graphql-code-generator/pull/10077) [`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4) Thanks [@eddeee888](https://github.com/eddeee888)! - Extend `config.avoidOptions` to support query, mutation and subscription Previously, `config.avoidOptions.resolvers` was being used to make query, mutation and subscription fields non-optional. Now, `config.avoidOptions.query`, `config.avoidOptions.mutation` and `config.avoidOptions.subscription` can be used to target the respective types. ## 5.3.1 ### Patch Changes - [#10014](https://github.com/dotansimha/graphql-code-generator/pull/10014) [`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix object types with fields being abstract types not pointing to resolver types correctly ## 5.3.0 ### Minor Changes - [#10007](https://github.com/dotansimha/graphql-code-generator/pull/10007) [`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3) Thanks [@eddeee888](https://github.com/eddeee888)! - Add generated resolvers map type name to typescript-resolvers plugin meta ### Patch Changes - [#10019](https://github.com/dotansimha/graphql-code-generator/pull/10019) [`14ce39e`](https://github.com/dotansimha/graphql-code-generator/commit/14ce39e41dfee38c652be736664177fa2b1df421) Thanks [@vhfmag](https://github.com/vhfmag)! - Improve code generation performance by computing `ClientSideBaseVisitor`'s `fragmentsGraph` once at instantiation time. ## 5.2.0 ### Minor Changes - [#9961](https://github.com/dotansimha/graphql-code-generator/pull/9961) [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e) Thanks [@eddeee888](https://github.com/eddeee888)! - Update typescript-resolvers to report generated resolver types in the run to meta field in the output ### Patch Changes - [#9944](https://github.com/dotansimha/graphql-code-generator/pull/9944) [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431) Thanks [@eddeee888](https://github.com/eddeee888)! - Add \_ prefix to generated `RefType` in `ResolversInterfaceTypes` and `ResolversUnionTypes` as it is sometimes unused - [#9962](https://github.com/dotansimha/graphql-code-generator/pull/9962) [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix interface mappers not working in nested/self-referencing scenarios - Updated dependencies [[`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e)]: - @graphql-codegen/plugin-helpers@5.0.4 ## 5.1.0 ### Minor Changes - [#9652](https://github.com/dotansimha/graphql-code-generator/pull/9652) [`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53) Thanks [@gmurphey](https://github.com/gmurphey)! - Added allowUndefinedQueryVariables as config option ### Patch Changes - [#9842](https://github.com/dotansimha/graphql-code-generator/pull/9842) [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d) Thanks [@henryqdineen](https://github.com/henryqdineen)! - properly handle aliased conditionals ## 5.0.0 ### Major Changes - [#9845](https://github.com/dotansimha/graphql-code-generator/pull/9845) [`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5) Thanks [@productdevbook](https://github.com/productdevbook)! - path starts with "#" ## 4.1.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/plugin-helpers@5.0.3 ## 4.1.1 ### Patch Changes - [#9673](https://github.com/dotansimha/graphql-code-generator/pull/9673) [`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f) Thanks [@maclockard](https://github.com/maclockard)! - Respect avoidOptionals when all arguments are optional ## 4.1.0 ### Minor Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - fix: out-of-memory crash (fixes #7720) perf: implement a caching mechanism that makes sure the type originating at the same location is never generated twice, as long as the combination of selected fields and possible types matches feat: implement `extractAllFieldsToTypes: boolean` feat: implement `printFieldsOnNewLines: boolean` ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - Avoid reading from null values when selection sets only contain fragments. - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 ## 4.0.1 ### Patch Changes - [#9497](https://github.com/dotansimha/graphql-code-generator/pull/9497) [`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a) Thanks [@eddeee888](https://github.com/eddeee888)! - Revert default ID scalar input type to string We changed the ID Scalar input type from `string` to `string | number` in the latest major version of `typescript` plugin. This causes issues for server plugins (e.g. typescript-resolvers) that depends on `typescript` plugin. This is because the scalar type needs to be manually inverted on setup which is confusing. ## 4.0.0 ### Major Changes - [#9375](https://github.com/dotansimha/graphql-code-generator/pull/9375) [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929) Thanks [@eddeee888](https://github.com/eddeee888)! - Implement Scalars with input/output types In GraphQL, Scalar types can be different for client and server. For example, given the native GraphQL ID: - A client may send `string` or `number` in the input - A client receives `string` in its selection set (i.e output) - A server receives `string` in the resolver (GraphQL parses `string` or `number` received from the client to `string`) - A server may return `string` or `number` (GraphQL serializes the value to `string` before sending it to the client ) Currently, we represent every Scalar with only one type. This is what codegen generates as base type: ```ts export type Scalars = { ID: string } ``` Then, this is used in both input and output type e.g. ```ts export type Book = { __typename?: 'Book' id: Scalars['ID'] // Output's ID can be `string` 👍 } export type QueryBookArgs = { id: Scalars['ID'] // Input's ID can be `string` or `number`. However, the type is only `string` here 👎 } ``` This PR extends each Scalar to have input and output: ```ts export type Scalars = { ID: { input: string | number output: string } } ``` Then, each input/output GraphQL type can correctly refer to the correct input/output scalar type: ```ts export type Book = { __typename?: 'Book' id: Scalars['ID']['output'] // Output's ID can be `string` 👍 } export type QueryBookArgs = { id: Scalars['ID']['input'] // Input's ID can be `string` or `number` 👍 } ``` Note that for `typescript-resolvers`, the type of ID needs to be inverted. However, the referenced types in GraphQL input/output types should still work correctly: ```ts export type Scalars = { ID: { input: string; output: string | number; } } export type Book = { __typename?: "Book"; id: Scalars["ID"]['output']; // Resolvers can return `string` or `number` in ID fields 👍 }; export type QueryBookArgs = { id: Scalars["ID"]['input']; // Resolvers receive `string` in ID fields 👍 }; export type ResolversTypes = { ID: ID: ResolverTypeWrapper; // Resolvers can return `string` or `number` in ID fields 👍 } export type ResolversParentTypes = { ID: Scalars['ID']['output']; // Resolvers receive `string` or `number` from parents 👍 }; ``` *** Config changes: 1. Scalars option can now take input/output types: ```ts config: { scalars: { ID: { input: 'string', output: 'string | number' } } } ``` 2. If a string is given (instead of an object with input/output fields), it will be used as both input and output types: ```ts config: { scalars: { ID: 'string' // This means `string` will be used for both ID's input and output types } } ``` 3. BREAKING CHANGE: External module Scalar types need to be an object with input/output fields ```ts config: { scalars: { ID: './path/to/scalar-module' } } ``` If correctly, wired up, the following will be generated: ```ts // Previously, imported `ID` type can be a primitive type, now it must be an object with input/output fields import { ID } from './path/to/scalar-module' export type Scalars = { ID: { input: ID['input']; output: ID['output'] } } ``` *** BREAKING CHANGE: This changes Scalar types which could be referenced in other plugins. If you are a plugin maintainer and reference Scalar, please update your plugin to use the correct input/output types. - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Minor Changes - [#9196](https://github.com/dotansimha/graphql-code-generator/pull/9196) [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96) Thanks [@beerose](https://github.com/beerose)! - Add `@defer` directive support When a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved. Once start using the `@defer` directive in your queries, the generated code will automatically include support for the directive. ```jsx // src/index.tsx import { graphql } from './gql' const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `) const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `) ``` The generated type for `GetUserQuery` will have information that the fragment is _incremental,_ meaning it may not be available right away. ```tsx // gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query' } & { ' $fragmentRefs'?: { OrdersFragment: Incremental } }) ``` Apart from generating code that includes support for the `@defer` directive, the Codegen also exports a utility function called `isFragmentReady`. You can use it to conditionally render components based on whether the data for a deferred fragment is available: ```jsx const OrdersList = (props: { data: FragmentType }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && } )} ); } export default App; ``` - [#9339](https://github.com/dotansimha/graphql-code-generator/pull/9339) [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c) Thanks [@AaronMoat](https://github.com/AaronMoat)! - Add excludeTypes config to resolversNonOptionalTypename This disables the adding of `__typename` in resolver types for any specified typename. This could be useful e.g. if you're wanting to enable this for all new types going forward but not do a big migration. Usage example: ```typescript const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: { unionMember: true, excludeTypes: ['MyType'] } } } } } ``` - [#9229](https://github.com/dotansimha/graphql-code-generator/pull/9229) [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c) Thanks [@eddeee888](https://github.com/eddeee888)! - Use generic to simplify ResolversUnionTypes This follows the `ResolversInterfaceTypes`'s approach where the `RefType` generic is used to refer back to `ResolversTypes` or `ResolversParentTypes` in cases of nested Union types - [#9304](https://github.com/dotansimha/graphql-code-generator/pull/9304) [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823) Thanks [@esfomeado](https://github.com/esfomeado)! - Added support for disabling suffixes on Enums. - [#9229](https://github.com/dotansimha/graphql-code-generator/pull/9229) [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c) Thanks [@eddeee888](https://github.com/eddeee888)! - Extract interfaces to ResolversInterfaceTypes and add to resolversNonOptionalTypename 1. `ResolversInterfaceTypes` is a new type that keeps track of a GraphQL interface and its implementing types. For example, consider this schema: ```graphql extend type Query { character(id: ID!): CharacterNode } interface CharacterNode { id: ID! } type Wizard implements CharacterNode { id: ID! screenName: String! spells: [String!]! } type Fighter implements CharacterNode { id: ID! screenName: String! powerLevel: Int! } ``` The generated types will look like this: ```ts export type ResolversInterfaceTypes> = { CharacterNode: Fighter | Wizard } export type ResolversTypes = { // other types... CharacterNode: ResolverTypeWrapper['CharacterNode']> Fighter: ResolverTypeWrapper Wizard: ResolverTypeWrapper // other types... } export type ResolversParentTypes = { // other types... CharacterNode: ResolversInterfaceTypes['CharacterNode'] Fighter: Fighter Wizard: Wizard // other types... } ``` The `RefType` generic is used to reference back to `ResolversTypes` and `ResolversParentTypes` in some cases such as field returning a Union. 2. `resolversNonOptionalTypename` also affects `ResolversInterfaceTypes` Using the schema above, if we use `resolversNonOptionalTypename` option: ```typescript const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: true // Or `resolversNonOptionalTypename: { interfaceImplementingType: true }` } } } } ``` Then, the generated type looks like this: ```ts export type ResolversInterfaceTypes> = { CharacterNode: (Fighter & { __typename: 'Fighter' }) | (Wizard & { __typename: 'Wizard' }) } export type ResolversTypes = { // other types... CharacterNode: ResolverTypeWrapper['CharacterNode']> Fighter: ResolverTypeWrapper Wizard: ResolverTypeWrapper // other types... } export type ResolversParentTypes = { // other types... CharacterNode: ResolversInterfaceTypes['CharacterNode'] Fighter: Fighter Wizard: Wizard // other types... } ``` ### Patch Changes - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-tools/optimize@^2.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/optimize/v/2.0.0) (from `^1.3.0`, in `dependencies`) - Updated dependency [`@graphql-tools/relay-operation-optimizer@^7.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/relay-operation-optimizer/v/7.0.0) (from `^6.5.0`, in `dependencies`) - Updated dependency [`@graphql-tools/utils@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/10.0.0) (from `^9.0.0`, in `dependencies`) - [#9414](https://github.com/dotansimha/graphql-code-generator/pull/9414) [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d) Thanks [@beerose](https://github.com/beerose)! - Include nested fragments in string documentMode - [#9369](https://github.com/dotansimha/graphql-code-generator/pull/9369) [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30) Thanks [@asmundg](https://github.com/asmundg)! - Output valid type names with mergeFragmentTypes - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0)]: - @graphql-codegen/plugin-helpers@5.0.0 ## 3.1.1 ### Patch Changes - [#9301](https://github.com/dotansimha/graphql-code-generator/pull/9301) [`386cf9044`](https://github.com/dotansimha/graphql-code-generator/commit/386cf9044a41d87ed45069b22d26b30f4b262a85) Thanks [@wassim-k](https://github.com/wassim-k)! - Fix fragment imports for near-operation-file with graphQLTag - [#9231](https://github.com/dotansimha/graphql-code-generator/pull/9231) [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00) Thanks [@eddeee888](https://github.com/eddeee888)! - Implement resolversNonOptionalTypename for mapper cases ## 3.1.0 ### Minor Changes - [#9146](https://github.com/dotansimha/graphql-code-generator/pull/9146) [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd) Thanks [@eddeee888](https://github.com/eddeee888)! - [typescript-resolvers] Add `resolversNonOptionalTypename` config option. This is extending on `ResolversUnionTypes` implemented in https://github.com/dotansimha/graphql-code-generator/pull/9069 `resolversNonOptionalTypename` adds non-optional `__typename` to union members of `ResolversUnionTypes`, without affecting the union members' base intefaces. A common use case for non-optional `__typename` of union members is using it as the common field to work out the final schema type. This makes implementing the union's `__resolveType` very simple as we can use `__typename` to decide which union member the resolved object is. Without this, we have to check the existence of field/s on the incoming object which could be verbose. For example, consider this schema: ```graphql type Query { book(id: ID!): BookPayload! } type Book { id: ID! isbn: String! } type BookResult { node: Book } type PayloadError { message: String! } union BookPayload = BookResult | PayloadError ``` _With optional `__typename`:_ We need to check existence of certain fields to resolve type in the union resolver: ```ts // Query/book.ts export const book = async () => { try { const book = await fetchBook() // 1. No `__typename` in resolver results... return { node: book } } catch (e) { return { message: 'Failed to fetch book' } } } // BookPayload.ts export const BookPayload = { __resolveType: parent => { // 2. ... means more checks in `__resolveType` if ('message' in parent) { return 'PayloadError' } return 'BookResult' } } ``` _With non-optional `__typename`:_ Resolvers declare the type. This which gives us better TypeScript support in resolvers and simplify `__resolveType` implementation: ```ts // Query/book.ts export const book = async () => { try { const book = await fetchBook() // 1. `__typename` is declared in resolver results... return { __typename: 'BookResult', // 1a. this also types `node` for us 🎉 node: book } } catch (e) { return { __typename: 'PayloadError', message: 'Failed to fetch book' } } } // BookPayload.ts export const BookPayload = { __resolveType: parent => parent.__typename // 2. ... means a very simple check in `__resolveType` } ``` _Using `resolversNonOptionalTypename`:_ add it into `typescript-resolvers` plugin config: ```ts // codegen.ts const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: true // Or `resolversNonOptionalTypename: { unionMember: true }` } } } } ``` ### Patch Changes - [#9206](https://github.com/dotansimha/graphql-code-generator/pull/9206) [`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix `ResolversUnionTypes` being used in `ResolversParentTypes` Previously, objects with mappable fields are converted to Omit format that references its own type group or `ResolversTypes` or `ResolversParentTypes` e.g. ```ts export type ResolversTypes = { Book: ResolverTypeWrapper BookPayload: ResolversTypes['BookResult'] | ResolversTypes['StandardError'] // Note: `result` on the next line references `ResolversTypes["Book"]` BookResult: ResolverTypeWrapper & { result?: Maybe }> StandardError: ResolverTypeWrapper } export type ResolversParentTypes = { Book: BookMapper BookPayload: ResolversParentTypes['BookResult'] | ResolversParentTypes['StandardError'] // Note: `result` on the next line references `ResolversParentTypes["Book"]` BookResult: Omit & { result?: Maybe } StandardError: StandardError } ``` In https://github.com/dotansimha/graphql-code-generator/pull/9069, we extracted resolver union types to its own group: ```ts export type ResolversUnionTypes = { // Note: `result` on the next line references `ResolversTypes["Book"]` which is only correct for the `ResolversTypes` case BookPayload: (Omit & { result?: Maybe }) | StandardError } export type ResolversTypes = { Book: ResolverTypeWrapper BookPayload: ResolverTypeWrapper BookResult: ResolverTypeWrapper & { result?: Maybe }> StandardError: ResolverTypeWrapper } export type ResolversParentTypes = { Book: BookMapper BookPayload: ResolversUnionTypes['BookPayload'] BookResult: Omit & { result?: Maybe } StandardError: StandardError } ``` This change creates an extra `ResolversUnionParentTypes` that is referenced by `ResolversParentTypes` to ensure backwards compatibility: ```ts export type ResolversUnionTypes = { BookPayload: (Omit & { result?: Maybe }) | StandardError } // ... and the reference is changed in ResolversParentTypes: export type ResolversParentTypes = { // ... other fields BookPayload: ResolversUnionParentTypes['BookPayload'] } ``` - [#9194](https://github.com/dotansimha/graphql-code-generator/pull/9194) [`acb647e4e`](https://github.com/dotansimha/graphql-code-generator/commit/acb647e4efbddecf732b6e55dc47ac40c9bdaf08) Thanks [@dstaley](https://github.com/dstaley)! - Don't emit import statements for unused fragments - Updated dependencies [[`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087)]: - @graphql-codegen/plugin-helpers@4.2.0 ## 3.0.2 ### Patch Changes - [#9110](https://github.com/dotansimha/graphql-code-generator/pull/9110) [`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a) Thanks [@gilgardosh](https://github.com/gilgardosh)! - Custom mappers with placeholder will apply omit - [#9069](https://github.com/dotansimha/graphql-code-generator/pull/9069) [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc) Thanks [@eddeee888](https://github.com/eddeee888)! - Extract union types to ResolversUnionTypes - [#8895](https://github.com/dotansimha/graphql-code-generator/pull/8895) [`b343626c9`](https://github.com/dotansimha/graphql-code-generator/commit/b343626c978b9ee0f14e314cea6c01ae3dad057c) Thanks [@benkroeger](https://github.com/benkroeger)! - Preserve .js extension when importDocumentNodeExternallyFrom and emitLegacyCommonJSImports is false ## 3.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - [#8971](https://github.com/dotansimha/graphql-code-generator/pull/8971) [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Always inline referenced fragments within their document. This prevents issues with duplicated fragments or missing fragments. - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - [#8871](https://github.com/dotansimha/graphql-code-generator/pull/8871) [`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5) Thanks [@B2o5T](https://github.com/B2o5T)! - eslint fixes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/plugin-helpers@4.0.0 ## 2.13.8 ### Patch Changes - [#8816](https://github.com/dotansimha/graphql-code-generator/pull/8816) [`a98198524`](https://github.com/dotansimha/graphql-code-generator/commit/a9819852443884b43de7c15040ccffc205f9177a) Thanks [@charle692](https://github.com/charle692)! - Fix issue where visitor-plugin-common emitted ESM imports for Operations when emitLegacyCommonJSImports is true ## 2.13.7 ### Patch Changes - [#8755](https://github.com/dotansimha/graphql-code-generator/pull/8755) [`eb454d06c`](https://github.com/dotansimha/graphql-code-generator/commit/eb454d06c977f11f7d4a7b0b07eb80f8fd590560) Thanks [@schmod](https://github.com/schmod)! - avoid using TypeScript namespace imports for enums ## 2.13.6 ### Patch Changes - [#8771](https://github.com/dotansimha/graphql-code-generator/pull/8771) [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.8.0`, in `dependencies`) - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 ## 2.13.5 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81)]: - @graphql-codegen/plugin-helpers@3.1.1 ## 2.13.4 ### Patch Changes - [#8686](https://github.com/dotansimha/graphql-code-generator/pull/8686) [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`change-case-all@1.0.15` ↗︎](https://www.npmjs.com/package/change-case-all/v/1.0.15) (from `1.0.14`, in `dependencies`) - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 ## 2.13.3 ### Patch Changes - [#8664](https://github.com/dotansimha/graphql-code-generator/pull/8664) [`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe) Thanks [@jdmoody](https://github.com/jdmoody)! - Fix issue where selection set flattening uses the wrong parent type ## 2.13.2 ### Patch Changes - [#8586](https://github.com/dotansimha/graphql-code-generator/pull/8586) [`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122) Thanks [@levrik](https://github.com/levrik)! - Fix incompatibility between `@oneOf` input types and declaration kind other than `type` ## 2.13.1 ### Patch Changes - [#8525](https://github.com/dotansimha/graphql-code-generator/pull/8525) [`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127) Thanks [@charlypoly](https://github.com/charlypoly)! - remove `DetailledError`, not supported by Listr renderer - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/plugin-helpers@2.7.2 ## 2.13.0 ### Minor Changes - [#8498](https://github.com/dotansimha/graphql-code-generator/pull/8498) [`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b) Thanks [@charlypoly](https://github.com/charlypoly)! - Fragment masking ` $fragmentName` and ` $fragmentRefs` are optionals ## 2.12.2 ### Patch Changes - [#8432](https://github.com/dotansimha/graphql-code-generator/pull/8432) [`1bd7f771c`](https://github.com/dotansimha/graphql-code-generator/commit/1bd7f771ccb949a5a37395c7c57cb41c19340714) Thanks [@mvestergaard](https://github.com/mvestergaard)! - Remove extension from operations file import ## 2.12.1 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - [#8185](https://github.com/dotansimha/graphql-code-generator/pull/8185) [`47d0a57e2`](https://github.com/dotansimha/graphql-code-generator/commit/47d0a57e27dd0d2334670bfc6c81c45e00ff4e74) Thanks [@chrisands](https://github.com/chrisands)! - Fix emitLegacyCommonJSImports to being passed - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f)]: - @graphql-codegen/plugin-helpers@2.6.2 ## 2.12.0 ### Minor Changes - 2cbcbb371: Add new flag to emit legacy common js imports. Default it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065). You can use the option in your config: ```yaml schema: 'schema.graphql' documents: - 'src/**/*.graphql' emitLegacyCommonJSImports: true ``` Alternative you can use the CLI to set this option: ```bash $ codegen --config-file=config.yml --emit-legacy-common-js-imports ``` ### Patch Changes - Updated dependencies [2cbcbb371] - @graphql-codegen/plugin-helpers@2.6.0 ## 2.11.1 ### Patch Changes - 525ad580b: Revert breaking change for Next.js applications that are incapable of resolving an import with a `.js` extension. ## 2.11.0 ### Minor Changes - 68bb30e19: Attach `.js` extension to imports starting with either a `.` or `/` character. - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/plugin-helpers@2.5.0 ## 2.10.0 ### Minor Changes - aa1e6eafd: Add @Deprecated support for input ### Patch Changes - a42fcbfe4: docs: Swapping rootValueType with directiveContextTypes for correctness - 8b10f22be: Ensure falsy enum values are still mapped ## 2.9.1 ### Patch Changes - d16bebacb: Update @graphql-tools/relay-operation-optimizer package; - Previously that package used relay-compiler@12 which has graphql v15 as a peer dependency and it was causing peer dependency warnings if user installs a different version of `graphql` package. Now we forked and released v12 under a different name and removed version range for `graphql` in `peerDependencies` of `relay-compiler` ## 2.9.0 ### Minor Changes - c3d7b7226: support the `@oneOf` directive on input types. ## 2.8.0 ### Minor Changes - f1fb77bd4: feat: Add option to squash exactly similar fragment types ## 2.7.6 ### Patch Changes - 9a5f31cb6: New option `onlyEnums` for Typescript ## 2.7.5 ### Patch Changes - 2966686e9: Generate $fragmentName for fragment subtypes for fragment masking ## 2.7.4 ### Patch Changes - 337fd4f77: WP: [typescript-resolvers] Add directiveContextTypes option ## 2.7.3 ### Patch Changes - 54718c039: Improve @Deprecated Enum Type developer experience ## 2.7.2 ### Patch Changes - 11d05e361: fix(resolvers): fix conflict between `typesPrefix: true` and `enumPrefix: false` ## 2.7.1 ### Patch Changes - fd55e2039: fix incorrect type generation when using the inlineFragmentTypes 'combine' option that resulted in generating masked fragment output. ## 2.7.0 ### Minor Changes - 1479233df: Add new `inlineFragmentTypes` mode `'mask'`, which allows generating masked fragment types. ## 2.6.0 ### Minor Changes - bef4376d5: fix: RequireFields generic making all other fields optional ### Patch Changes - c8ef37ae0: fix(typescript-resolvers): Fix optional field types - be7cb3a82: Performance work: resolvers plugins, documents loading - Updated dependencies [754a33715] - @graphql-codegen/plugin-helpers@2.4.0 ## 2.5.2 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/plugin-helpers@2.3.2 ## 2.5.1 ### Patch Changes - a9f1f1594: Use maybeValue as default output for optionals on preResolveTypes: true - 9ea6621ec: add missing ListType method parameters ## 2.5.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/plugin-helpers@2.3.0 ## 2.4.0 ### Minor Changes - ad02cb9b8: Fixed an issue where ResolversParentTypes referenced non-existing fields of ResolversParentTypes when the corresponding type was a mapped enum. ## 2.3.0 ### Minor Changes - b9e85adae: feat(visitor-plugin-common): support custom scalar type from extensions ### Patch Changes - 3c2c847be: Fix dedupleFragments option for typescript-react-query (and possibly others) - Updated dependencies [7c60e5acc] - @graphql-codegen/plugin-helpers@2.2.0 ## 2.2.1 ### Patch Changes - 0b090e31a: Apply proper indentation to DirectiveArgs types ## 2.2.0 ### Minor Changes - d6c2d4c09: Allow declaring Argument and InputType field mappings based on directive annotations. **WARNING:** Using this option does only change the type definitions. For actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://www.graphql-tools.com/docs/schema-directives)) that apply those rules! Otherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors. Please use this configuration option with care! ```yaml plugins: config: directiveArgumentAndInputFieldMappings: asNumber: number ``` ```graphql directive @asNumber on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION input MyInput { id: ID! @asNumber } type User { id: ID! } type Query { user(id: ID! @asNumber): User } ``` Usage e.g. with `typescript-resolvers` ```ts const Query: QueryResolvers = { user(_, args) { // args.id is of type 'number' } } ``` - 5086791ac: Allow overwriting the resolver type signature based on directive usages. **WARNING:** Using this option does only change the generated type definitions. For actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://www.graphql-tools.com/docs/schema-directives)) that apply those rules! Otherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors. Example configuration: ```yaml config: # This was possible before customResolverFn: ../resolver-types.ts#UnauthenticatedResolver # This is new directiveResolverMappings: authenticated: ../resolvers-types.ts#AuthenticatedResolver ``` Example mapping file (`resolver-types.ts`): ```ts export type UnauthenticatedContext = { user: null } export type AuthenticatedContext = { user: { id: string } } export type UnauthenticatedResolver = ( parent: TParent, args: TArgs, context: UnauthenticatedContext, info: GraphQLResolveInfo ) => Promise | TResult export type AuthenticatedResolver = ( parent: TParent, args: TArgs, context: AuthenticatedContext, info: GraphQLResolveInfo ) => Promise | TResult ``` Example Schema: ```graphql directive @authenticated on FIELD_DEFINITION type Query { yee: String foo: String @authenticated } ``` ### Patch Changes - feeae1c66: Do not throw an error when trying to merge inline fragment usages. ## 2.1.2 ### Patch Changes - 6470e6cc9: fix(plugin-helpers): remove unnecessary import - 263570e50: Don't generate duplicate imports for the same identifier - Updated dependencies [6470e6cc9] - Updated dependencies [35199dedf] - @graphql-codegen/plugin-helpers@2.1.1 ## 2.1.1 ### Patch Changes - aabeff181: Don't generate import statements for fragments declared in the file we're outputting to ## 2.1.0 ### Minor Changes - 290170262: add getOperationVariableName function to ClientSideBasePluginConfig class - 440172cfe: support ESM ### Patch Changes - 24185985a: bump graphql-tools package versions - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/plugin-helpers@2.1.0 ## 2.0.0 ### Major Changes - d80efdec4: Change `preResolveTypes` default to be `true` for more readable types - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - d80efdec4: Add option `inlineFragmentTypes` for deep inlining fragment types within operation types. This `inlineFragmentTypes` is set to `inline` by default (Previous behaviour is `combine`). This behavior is the better default for users that only use Fragments for building operations and then want to have access to all the data via the operation type (instead of accessing slices of the data via fragments). - Updated dependencies [b0cb13df4] - @graphql-codegen/plugin-helpers@2.0.0 ## 1.22.0 ### Minor Changes - 9005cc17: add `allowEnumStringTypes` option for allowing string literals as valid return types from resolvers in addition to enum values.\_ ### Patch Changes - df19a4ed: Allow multiple `{T}` instances in defaultMapper - Updated dependencies [470336a1] - @graphql-codegen/plugin-helpers@1.18.8 ## 1.21.3 ### Patch Changes - 6762aff5: Fix for array types with @skip @include directives ## 1.21.2 ### Patch Changes - 6aaecf1c: Fix issues with missing sub-fragments when skipTypename: true ## 1.21.1 ### Patch Changes - cf1e5abc: Introduce new feature for removing duplicated fragments ## 1.21.0 ### Minor Changes - 8da7dff6: Skip typechecking on generated values by casting to unknown ### Patch Changes - dfd25caf: chore(deps): bump graphql-tools versions - Updated dependencies [dfd25caf] - @graphql-codegen/plugin-helpers@1.18.7 ## 1.20.0 ### Minor Changes - f0b5ea53: Add entireFieldWrapperValue configuration option, to wrap arrays - 097bea2f: Added new configuration settings for scalars: `strictScalars` and `defaultScalarType` ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - @graphql-codegen/plugin-helpers@1.18.5 ## 1.19.1 ### Patch Changes - 23862e7e: fix(naming-convention): revert and pin change-case-all dependency for workaround #3256 - Updated dependencies [23862e7e] - @graphql-codegen/plugin-helpers@1.18.4 ## 1.19.0 ### Minor Changes - d4942d04: NEW CONFIG (`onlyResolveTypeForInterfaces`): Allow to generate only \_\_resolveType for interfaces ### Patch Changes - e947f8e3: Allow to have declarationKind of type: class, interface: interface - 29b75b1e: enhance(docs): improve docs for naming convention - 1f6f3db6: Fix for @skip @include directives upon arrays - 29b75b1e: enhance(namingConvention): use change-case-all instead of individual packages for naming convention - Updated dependencies [29b75b1e] - @graphql-codegen/plugin-helpers@1.18.3 ## 1.18.3 ### Patch Changes - 5749cb8a: chore: fix type-level incompatibilities of the `avoidOptionals` - 5a12fe58: fix type error on parsing enums ## 1.18.2 ### Patch Changes - ca66569f: Fix issues with undefined calls for str.replace ## 1.18.1 ### Patch Changes - 63be0f40: Fix issues with empty interfaces causing syntax issues - 190482a1: add support for fragment variables - 4444348d: Correctly escape enum values defined in the GraphQLSchema object - 142b32b3: Better support for @skip/@include directives with complex selection sets - 42213fa0: Strip trailing whitespace from some output ## 1.18.0 ### Minor Changes - bd4bf7cf: feat(visitor-plugin-common): add ignoreEnumValuesFromSchema to ignore enum values from GraphQLSchema ## 1.17.22 ### Patch Changes - 64293437: Support for input lists coercion - fd5843a7: Fixed a bug where some import namespacing is missed when generating resolver types. - d75051f5: generate correct types for fragments with an interface type condition that are spread on an interface field. ## 1.17.21 ### Patch Changes - 8356f8a2: Extended behaviour to allow support in `internalResolversPrefix` flag for resolvers plugin ## 1.17.20 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/plugin-helpers@1.18.2 ## 1.17.19 ### Patch Changes - 99819bf1: Improve DocumentNode optimization for plugins that generate it - c3b59e81: Extract buildMapperImport to external function ## 1.17.18 ### Patch Changes - faa13973: Fixed a bug in `parseMapper` that were preventing to use mappers with complex type usages ## 1.17.17 ### Patch Changes - 612e5e52: remove broken isTypeOf call for expanding fragments with flattenGeneratedTypes = true - 9f2a4e2f: Expose `_hasRequiredVariables` to `buildOperation` in order to allow better type-safety for plugins that deals with `variables` - 0f35e775: Fix issues with incorrect naming of operation and variables when used with typesSuffix - Updated dependencies [eaf45d1f] - @graphql-codegen/plugin-helpers@1.18.1 ## 1.17.16 ### Patch Changes - 92d8f876: Fixed unquoted numeric enum identifiers ## 1.17.15 ### Patch Changes - d2cde3d5: fixed isTypeOf resolvers signature - 89a6aa80: Fixes issues with typesSuffix and arguments type name - f603b8f8: Support unnamed queries in operation visitors - Updated dependencies [da8bdd17] - @graphql-codegen/plugin-helpers@1.17.9 ## 1.17.14 ### Patch Changes - 07f9b1b2: Fix a bug caused numeric enum values defined in the GraphQLSchema to be printed incorrectly - 35f67120: bugfix: allow to specify mappers for GraphQL `interface` and override the default behaviour. ## 1.17.13 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/plugin-helpers@1.17.8 ## 1.17.12 ### Patch Changes - 4266a15f: Allow getDocumentNodeSignature to control the entire generation flow of the typed documents ## 1.17.11 ### Patch Changes - ee2b01a3: Fixes for issues with publish command ## 1.17.10 ### Patch Changes - 6cb9c96d: Fixes issues with previous release ## 1.17.9 ### Patch Changes - bccfd28c: Allow to set `gqlImport` to a clean `gql` string and skip import generating ## 1.17.8 ### Patch Changes - ce3a5798: Publish minor version to include fixes for client-side-base-visitor, required to v2 of ts-react-apollo plugin (for unified apollo import) ================================================ FILE: packages/plugins/other/visitor-plugin-common/package.json ================================================ { "name": "@graphql-codegen/visitor-plugin-common", "version": "6.2.4", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/other/visitor-plugin-common" }, "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "dependencies": { "@graphql-tools/optimize": "^2.0.0", "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-tools/relay-operation-optimizer": "^7.1.1", "@graphql-tools/utils": "^11.0.0", "auto-bind": "~4.0.0", "dependency-graph": "^1.0.0", "graphql-tag": "^2.11.0", "parse-filepath": "^1.0.2", "change-case-all": "1.0.15", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "devDependencies": { "@types/parse-filepath": "1.0.2" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/avoid-optionals.ts ================================================ import { AvoidOptionalsConfig, NormalizedAvoidOptionalsConfig } from './types.js'; export const DEFAULT_AVOID_OPTIONALS: NormalizedAvoidOptionalsConfig = { object: false, inputValue: false, field: false, defaultValue: false, resolvers: false, query: false, mutation: false, subscription: false, }; export function normalizeAvoidOptionals( avoidOptionals?: boolean | AvoidOptionalsConfig ): NormalizedAvoidOptionalsConfig { if (typeof avoidOptionals === 'boolean') { return { object: avoidOptionals, inputValue: avoidOptionals, field: avoidOptionals, defaultValue: avoidOptionals, resolvers: avoidOptionals, query: avoidOptionals, mutation: avoidOptionals, subscription: avoidOptionals, }; } return { ...DEFAULT_AVOID_OPTIONALS, ...avoidOptionals, }; } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/base-documents-visitor.ts ================================================ import autoBind from 'auto-bind'; import { pascalCase } from 'change-case-all'; import { FragmentDefinitionNode, GraphQLSchema, OperationDefinitionNode, OperationTypeNode, VariableDefinitionNode, } from 'graphql'; import { ParsedTypesConfig, RawTypesConfig } from './base-types-visitor.js'; import { BaseVisitor } from './base-visitor.js'; import { DEFAULT_SCALARS } from './scalars.js'; import { SelectionSetToObject } from './selection-set-to-object.js'; import { NormalizedScalarsMap, CustomDirectivesConfig } from './types.js'; import { buildScalarsFromConfig, DeclarationBlock, DeclarationBlockConfig, getConfigValue } from './utils.js'; import { OperationVariablesToObject } from './variables-to-object.js'; function getRootType(operation: OperationTypeNode, schema: GraphQLSchema) { switch (operation) { case 'query': return schema.getQueryType(); case 'mutation': return schema.getMutationType(); case 'subscription': return schema.getSubscriptionType(); } throw new Error(`Unknown operation type: ${operation}`); } export interface ParsedDocumentsConfig extends ParsedTypesConfig { addTypename: boolean; preResolveTypes: boolean; extractAllFieldsToTypes: boolean; globalNamespace: boolean; operationResultSuffix: string; dedupeOperationSuffix: boolean; omitOperationSuffix: boolean; namespacedImportName: string | null; exportFragmentSpreadSubTypes: boolean; skipTypeNameForRoot: boolean; experimentalFragmentVariables: boolean; mergeFragmentTypes: boolean; customDirectives: CustomDirectivesConfig; } export interface RawDocumentsConfig extends RawTypesConfig { /** * @default true * @description Uses primitive types where possible. * Set to `false` in order to use `Pick` and take use the types generated by `typescript` plugin. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * preResolveTypes: false * }, * }, * }, * }; * export default config; * ``` */ preResolveTypes?: boolean; /** * @default false * @description Avoid adding `__typename` for root types. This is ignored when a selection explicitly specifies `__typename`. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * skipTypeNameForRoot: true * }, * }, * }, * }; * export default config; * ``` */ skipTypeNameForRoot?: boolean; /** * @default false * @description Puts all generated code under `global` namespace. Useful for Stencil integration. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * globalNamespace: true * }, * }, * }, * }; * export default config; * ``` */ globalNamespace?: boolean; /** * @default "" * @description Adds a suffix to generated operation result type names */ operationResultSuffix?: string; /** * @default false * @description Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix. */ dedupeOperationSuffix?: boolean; /** * @default false * @description Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`. */ omitOperationSuffix?: boolean; /** * @default false * @description If set to true, it will export the sub-types created in order to make it easier to access fields declared under fragment spread. */ exportFragmentSpreadSubTypes?: boolean; /** * @default false * @description If set to true, it will enable support for parsing variables on fragments. */ experimentalFragmentVariables?: boolean; /** * @default false * @description If set to true, merge equal fragment interfaces. */ mergeFragmentTypes?: boolean; // The following are internal, and used by presets /** * @ignore */ namespacedImportName?: string; /** * @description Configures behavior for use with custom directives from * various GraphQL libraries. * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * customDirectives: { * apolloUnmask: true * } * }, * }, * }, * }; * export default config; * ``` */ customDirectives?: CustomDirectivesConfig; } export class BaseDocumentsVisitor< TRawConfig extends RawDocumentsConfig = RawDocumentsConfig, TPluginConfig extends ParsedDocumentsConfig = ParsedDocumentsConfig > extends BaseVisitor { protected _unnamedCounter = 1; protected _variablesTransfomer: OperationVariablesToObject; protected _selectionSetToObject: SelectionSetToObject; protected _globalDeclarations: Set = new Set(); constructor( rawConfig: TRawConfig, additionalConfig: TPluginConfig, protected _schema: GraphQLSchema, defaultScalars: NormalizedScalarsMap = DEFAULT_SCALARS ) { super(rawConfig, { exportFragmentSpreadSubTypes: getConfigValue(rawConfig.exportFragmentSpreadSubTypes, false), enumPrefix: getConfigValue(rawConfig.enumPrefix, true), enumSuffix: getConfigValue(rawConfig.enumSuffix, true), preResolveTypes: getConfigValue(rawConfig.preResolveTypes, true), dedupeOperationSuffix: getConfigValue(rawConfig.dedupeOperationSuffix, false), omitOperationSuffix: getConfigValue(rawConfig.omitOperationSuffix, false), skipTypeNameForRoot: getConfigValue(rawConfig.skipTypeNameForRoot, false), namespacedImportName: getConfigValue(rawConfig.namespacedImportName, null), experimentalFragmentVariables: getConfigValue(rawConfig.experimentalFragmentVariables, false), addTypename: !rawConfig.skipTypename, globalNamespace: !!rawConfig.globalNamespace, operationResultSuffix: getConfigValue(rawConfig.operationResultSuffix, ''), scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars), customDirectives: getConfigValue(rawConfig.customDirectives, { apolloUnmask: false }), ...((additionalConfig || {}) as any), }); autoBind(this); this._variablesTransfomer = new OperationVariablesToObject( this.scalars, this.convertName, this.config.namespacedImportName ); } public getGlobalDeclarations(noExport = false): string[] { return Array.from(this._globalDeclarations).map(t => (noExport ? t : `export ${t}`)); } setSelectionSetHandler(handler: SelectionSetToObject): void { this._selectionSetToObject = handler; } setDeclarationBlockConfig(config: DeclarationBlockConfig): void { this._declarationBlockConfig = config; } setVariablesTransformer(variablesTransfomer: OperationVariablesToObject): void { this._variablesTransfomer = variablesTransfomer; } public get schema(): GraphQLSchema { return this._schema; } public get addTypename(): boolean { return this._parsedConfig.addTypename; } private handleAnonymousOperation(node: OperationDefinitionNode): string { const name = node.name?.value; if (name) { return this.convertName(name, { useTypesPrefix: false, useTypesSuffix: false, }); } return this.convertName(String(this._unnamedCounter++), { prefix: 'Unnamed_', suffix: '_', useTypesPrefix: false, useTypesSuffix: false, }); } FragmentDefinition(node: FragmentDefinitionNode): string { const fragmentRootType = this._schema.getType(node.typeCondition.name.value); const selectionSet = this._selectionSetToObject.createNext(fragmentRootType, node.selectionSet); const fragmentSuffix = this.getFragmentSuffix(node); return [ selectionSet.transformFragmentSelectionSetToTypes(node.name.value, fragmentSuffix, this._declarationBlockConfig), this.config.experimentalFragmentVariables ? new DeclarationBlock({ ...this._declarationBlockConfig, blockTransformer: t => this.applyVariablesWrapper(t), }) .export() .asKind('type') .withName( this.convertName(node.name.value, { suffix: fragmentSuffix + 'Variables', }) ) .withBlock(this._variablesTransfomer.transform(node.variableDefinitions)).string : undefined, ] .filter(r => r) .join('\n\n'); } protected applyVariablesWrapper(variablesBlock: string, _operationType?: string): string { return variablesBlock; } OperationDefinition(node: OperationDefinitionNode): string { const name = this.handleAnonymousOperation(node); const operationRootType = getRootType(node.operation, this._schema); if (!operationRootType) { throw new Error(`Unable to find root schema type for operation type "${node.operation}"!`); } const selectionSet = this._selectionSetToObject.createNext(operationRootType, node.selectionSet); const visitedOperationVariables = this._variablesTransfomer.transform( node.variableDefinitions ); const operationType: string = pascalCase(node.operation); const operationTypeSuffix = this.getOperationSuffix(name, operationType); const selectionSetObjects = selectionSet.transformSelectionSet( this.convertName(name, { suffix: operationTypeSuffix, }) ); const operationResult = new DeclarationBlock(this._declarationBlockConfig) .export() .asKind('type') .withName( this.convertName(name, { suffix: operationTypeSuffix + this._parsedConfig.operationResultSuffix, }) ) .withContent(selectionSetObjects.mergedTypeString).string; const operationVariables = new DeclarationBlock({ ...this._declarationBlockConfig, blockTransformer: t => this.applyVariablesWrapper(t, operationType), }) .export() .asKind('type') .withName( this.convertName(name, { suffix: operationTypeSuffix + 'Variables', }) ) .withBlock(visitedOperationVariables).string; const dependentTypesContent = this._parsedConfig.extractAllFieldsToTypes ? selectionSetObjects.dependentTypes.map( i => new DeclarationBlock(this._declarationBlockConfig) .export() .asKind('type') .withName(i.name) .withContent(i.content).string ) : []; return [ ...(dependentTypesContent.length > 0 ? [dependentTypesContent.join('\n')] : []), operationVariables, operationResult, ] .filter(r => r) .join('\n\n'); } } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts ================================================ import { ApolloFederation, type FederationMeta, getBaseType } from '@graphql-codegen/plugin-helpers'; import { getRootTypeNames } from '@graphql-tools/utils'; import autoBind from 'auto-bind'; import { ASTNode, DirectiveDefinitionNode, EnumTypeDefinitionNode, FieldDefinitionNode, GraphQLInterfaceType, GraphQLNamedType, GraphQLObjectType, GraphQLSchema, GraphQLUnionType, InputValueDefinitionNode, InterfaceTypeDefinitionNode, isEnumType, isInterfaceType, isNonNullType, isObjectType, isUnionType, ListTypeNode, NamedTypeNode, NonNullTypeNode, ObjectTypeDefinitionNode, ScalarTypeDefinitionNode, UnionTypeDefinitionNode, } from 'graphql'; import { BaseVisitor, BaseVisitorConvertOptions, ParsedConfig, RawConfig } from './base-visitor.js'; import { parseEnumValues } from './enum-values.js'; import { buildMapperImport, ExternalParsedMapper, ParsedMapper, parseMapper, transformMappers } from './mappers.js'; import { DEFAULT_SCALARS } from './scalars.js'; import { AvoidOptionalsConfig, ConvertOptions, DeclarationKind, EnumValuesMap, NormalizedAvoidOptionalsConfig, NormalizedScalarsMap, ParsedEnumValuesMap, ResolversNonOptionalTypenameConfig, } from './types.js'; import { buildScalarsFromConfig, DeclarationBlock, DeclarationBlockConfig, getBaseTypeNode, getConfigValue, indent, OMIT_TYPE, REQUIRE_FIELDS_TYPE, stripMapperTypeInterpolation, wrapTypeWithModifiers, } from './utils.js'; import { OperationVariablesToObject } from './variables-to-object.js'; import { normalizeAvoidOptionals } from './avoid-optionals.js'; export interface ParsedResolversConfig extends ParsedConfig { contextType: ParsedMapper; fieldContextTypes: Array; directiveContextTypes: Array; rootValueType: ParsedMapper; mappers: { [typeName: string]: ParsedMapper; }; defaultMapper: ParsedMapper | null; avoidOptionals: NormalizedAvoidOptionalsConfig; addUnderscoreToArgsType: boolean; addInterfaceFieldResolverTypes: boolean; enumValues: ParsedEnumValuesMap; resolverTypeWrapperSignature: string; federation: boolean; enumPrefix: boolean; enumSuffix: boolean; optionalResolveType: boolean; immutableTypes: boolean; namespacedImportName: string; resolverTypeSuffix: string; allResolversTypeName: string; internalResolversPrefix: string; directiveResolverMappings: Record; resolversNonOptionalTypename: ResolversNonOptionalTypenameConfig; avoidCheckingAbstractTypesRecursively: boolean; } export interface FieldDefinitionResult { node: FieldDefinitionNode; printContent: FieldDefinitionPrintFn; } type FieldDefinitionPrintFn = ( parentNode: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, avoidResolverOptionals: boolean ) => { value: string | null; meta: { federation?: { isResolveReference: boolean } } }; export interface RootResolver { content: string; generatedResolverTypes: { resolversMap: { name: string }; userDefined: Record< string, { name: string; hasIsTypeOf: boolean; federation?: { hasResolveReference: boolean }; } >; }; } export interface RawResolversConfig extends RawConfig { /** * @description Adds `_` to generated `Args` types in order to avoid duplicate identifiers. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * addUnderscoreToArgsType: true * }, * }, * }, * }; * export default config; * ``` * */ addUnderscoreToArgsType?: boolean; /** * @description Use this configuration to set a custom type for your `context`, and it will * affect all the resolvers, without the need to override it using generics each time. * If you wish to use an external type and import it from another file, you can use `add` plugin * and add the required `import` statement, or you can use a `module#type` syntax. * * @exampleMarkdown * ## Custom Context Type * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * contextType: 'MyContext' * }, * }, * }, * }; * export default config; * ``` * * ## Custom Context Type by Path * * Note that the path should be relative to the generated file. * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * contextType: './my-types#MyContext' * }, * }, * }, * }; * export default config; * ``` */ contextType?: string; /** * @description Use this to set a custom type for a specific field `context`. * It will only affect the targeted resolvers. * You can either use `Field.Path#ContextTypeName` or `Field.Path#ExternalFileName#ContextTypeName` * * @exampleMarkdown * ## Custom Field Context Types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * fieldContextTypes: ['MyType.foo#CustomContextType', 'MyType.bar#./my-file#ContextTypeOne'] * }, * }, * }, * }; * export default config; * ``` * */ fieldContextTypes?: Array; /** * @description Use this configuration to set a custom type for the `rootValue`, and it will * affect resolvers of all root types (Query, Mutation and Subscription), without the need to override it using generics each time. * If you wish to use an external type and import it from another file, you can use `add` plugin * and add the required `import` statement, or you can use both `module#type` or `module#namespace#type` syntax. * * @exampleMarkdown * ## Custom RootValue Type * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * rootValueType: 'MyRootValue' * }, * }, * }, * }; * export default config; * ``` * * ## Custom RootValue Type * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * rootValueType: './my-types#MyRootValue' * }, * }, * }, * }; * export default config; * ``` */ rootValueType?: string; /** * @description Use this to set a custom type for a specific field `context` decorated by a directive. * It will only affect the targeted resolvers. * You can either use `Field.Path#ContextTypeName` or `Field.Path#ExternalFileName#ContextTypeName` * * ContextTypeName should by a generic Type that take the context or field context type as only type parameter. * * @exampleMarkdown * ## Directive Context Extender * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * directiveContextTypes: ['myCustomDirectiveName#./my-file#CustomContextExtender'] * }, * }, * }, * }; * export default config; * ``` * */ directiveContextTypes?: Array; /** * @description Adds a suffix to the imported names to prevent name clashes. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * mapperTypeSuffix: 'Model' * }, * }, * }, * }; * export default config; * ``` */ mapperTypeSuffix?: string; /** * @description Replaces a GraphQL type usage with a custom type, allowing you to return custom object from * your resolvers. * You can use both `module#type` and `module#namespace#type` syntax. * * @exampleMarkdown * ## Custom Context Type * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * mappers: { * User: './my-models#UserDbObject', * Book: './my-models#Collections', * } * }, * }, * }, * }; * export default config; * ``` */ mappers?: { [typeName: string]: string }; /** * @description Allow you to set the default mapper when it's not being override by `mappers` or generics. * You can specify a type name, or specify a string in `module#type` or `module#namespace#type` format. * The default value of mappers is the TypeScript type generated by `typescript` package. * * @exampleMarkdown * ## Replace with any * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * defaultMapper: 'any', * }, * }, * }, * }; * export default config; * ``` * * ## Custom Base Object * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * defaultMapper: './my-file#BaseObject', * }, * }, * }, * }; * export default config; * ``` * * ## Wrap default types with Partial * * You can also specify a custom wrapper for the original type, without overriding the original generated types, use `{T}` to specify the identifier. (for flow, use `$Shape<{T}>`) * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * defaultMapper: 'Partial<{T}>', * }, * }, * }, * }; * export default config; * ``` * * ## Allow deep partial with `utility-types` * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * plugins: ['typescript', 'typescript-resolver', { add: { content: "import { DeepPartial } from 'utility-types';" } }], * config: { * defaultMapper: 'DeepPartial<{T}>', * avoidCheckingAbstractTypesRecursively: true // required if you have complex nested abstract types * }, * }, * }, * }; * export default config; * ``` */ defaultMapper?: string; /** * @description This will cause the generator to avoid using optionals (`?`), * so all field resolvers must be implemented in order to avoid compilation errors. * @default false * * @exampleMarkdown * ## Override all definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * plugins: ['typescript', 'typescript-resolver'], * config: { * avoidOptionals: true * }, * }, * }, * }; * export default config; * ``` * * ## Override only specific definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * plugins: ['typescript', 'typescript-resolver'], * config: { * avoidOptionals: { * field: true, * inputValue: true, * object: true, * defaultValue: true, * query: true, * mutation: true, * subscription: true, * } * }, * }, * }, * }; * export default config; * ``` */ avoidOptionals?: boolean | AvoidOptionalsConfig; /** * @description Warns about unused mappers. * @default true * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * plugins: ['typescript', 'typescript-resolver'], * config: { * showUnusedMappers: true, * }, * }, * }, * }; * export default config; * ``` */ showUnusedMappers?: boolean; /** * @description Overrides the default value of enum values declared in your GraphQL schema, supported * in this plugin because of the need for integration with `typescript` package. * See documentation under `typescript` plugin for more information and examples. */ enumValues?: EnumValuesMap; /** * @default Promise | T * @description Allow you to override `resolverTypeWrapper` definition. */ resolverTypeWrapperSignature?: string; /** * @default false * @description Supports Apollo Federation */ federation?: boolean; /** * @default true * @description Allow you to disable prefixing for generated enums, works in combination with `typesPrefix`. * * @exampleMarkdown * ## Disable enum prefixes * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * plugins: ['typescript', 'typescript-resolver'], * config: { * typesPrefix: 'I', * enumPrefix: false * }, * }, * }, * }; * export default config; * ``` */ enumPrefix?: boolean; /** * @default true * @description Allow you to disable suffixing for generated enums, works in combination with `typesSuffix`. * * @exampleMarkdown * ## Disable enum suffixes * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * plugins: ['typescript', 'typescript-resolver'], * config: { * typesSuffix: 'I', * enumSuffix: false * }, * }, * }, * }; * export default config; * ``` */ enumSuffix?: boolean; /** * @description Configures behavior for custom directives from various GraphQL libraries. * @exampleMarkdown * ## `@semanticNonNull` * First, install `graphql-sock` peer dependency: * * ```sh npm2yarn * npm install -D graphql-sock * ``` * * Now, you can enable support for `@semanticNonNull` directive: * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript-resolvers'], * config: { * customDirectives: { * semanticNonNull: true * } * }, * }, * }, * }; * export default config; * ``` */ customDirectives?: { semanticNonNull?: boolean; }; /** * @default false * @description Sets the `__resolveType` field as optional field. */ optionalResolveType?: boolean; /** * @default false * @description Generates immutable types by adding `readonly` to properties and uses `ReadonlyArray`. */ immutableTypes?: boolean; /** * @default '' * @description Prefixes all GraphQL related generated types with that value, as namespaces import. * You can use this feature to allow separation of plugins to different files. */ namespacedImportName?: string; /** * @default Resolvers * @description Suffix we add to each generated type resolver. */ resolverTypeSuffix?: string; /** * @default Resolvers * @description The type name to use when exporting all resolvers signature as unified type. */ allResolversTypeName?: string; /** * @type string * @default '__' * @description Defines the prefix value used for `__resolveType` and `__isTypeOf` resolvers. * If you are using `mercurius-js`, please set this field to empty string for better compatibility. */ internalResolversPrefix?: string; /** * @description Makes `__typename` of resolver mappings non-optional without affecting the base types. * @default false * * @exampleMarkdown * ## Enable for all * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * plugins: ['typescript', 'typescript-resolver'], * config: { * resolversNonOptionalTypename: true // or { unionMember: true, interfaceImplementingType: true } * }, * }, * }, * }; * export default config; * ``` * * ## Enable except for some types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * plugins: ['typescript', 'typescript-resolver'], * config: { * resolversNonOptionalTypename: { * unionMember: true, * interfaceImplementingType: true, * excludeTypes: ['MyType'], * } * }, * }, * }, * }; * export default config; * ``` */ resolversNonOptionalTypename?: boolean | ResolversNonOptionalTypenameConfig; /** * @type boolean * @default false * @description If true, recursively goes through all object type's fields, checks if they have abstract types and generates expected types correctly. * This may not work for cases where provided default mapper types are also nested e.g. `defaultMapper: DeepPartial<{T}>` or `defaultMapper: Partial<{T}>`. */ avoidCheckingAbstractTypesRecursively?: boolean; /** * @description If true, add field resolver types to Interfaces. * By default, GraphQL Interfaces do not trigger any field resolvers, * meaning every implementing type must implement the same resolver for the shared fields. * * Some tools provide a way to change the default behaviour by making GraphQL Objects inherit * missing resolvers from their Interface types. In these cases, it is fine to turn this option to true. * * For example, if you are using `@graphql-tools/schema#makeExecutableSchema` with `inheritResolversFromInterfaces: true`, * you can make `addInterfaceFieldResolverTypes: true` as well * https://the-guild.dev/graphql/tools/docs/generate-schema#makeexecutableschema * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * plugins: ['typescript', 'typescript-resolver'], * config: { * addInterfaceFieldResolverTypes: true, * }, * }, * }, * }; * export default config; * ``` * * @type boolean * @default false */ addInterfaceFieldResolverTypes?: boolean; /** * @ignore */ directiveResolverMappings?: Record; } export type ResolverTypes = { [gqlType: string]: string }; export type ResolverParentTypes = { [gqlType: string]: string }; export type GroupedMappers = Record; type FieldContextTypeMap = Record; export class BaseResolversVisitor< TRawConfig extends RawResolversConfig = RawResolversConfig, TPluginConfig extends ParsedResolversConfig = ParsedResolversConfig > extends BaseVisitor { protected declare _parsedConfig: TPluginConfig; protected _declarationBlockConfig: DeclarationBlockConfig = {}; protected _collectedResolvers: { [key: string]: { typename: string; baseGeneratedTypename?: string; }; } = {}; protected _parsedSchemaMeta: { types: { interface: Record< string, { type: GraphQLInterfaceType; implementingTypes: Record; } >; union: Record< string, { type: GraphQLUnionType; unionMembers: Record; } >; }; typesWithIsTypeOf: Record; } = { types: { interface: {}, union: {}, }, typesWithIsTypeOf: {}, }; protected _collectedDirectiveResolvers: { [key: string]: string } = {}; protected _variablesTransformer: OperationVariablesToObject; protected _usedMappers: { [key: string]: boolean } = {}; protected _resolversTypes: ResolverTypes = {}; protected _resolversParentTypes: ResolverParentTypes = {}; protected _hasReferencedResolversUnionTypes = false; protected _hasReferencedResolversInterfaceTypes = false; protected _resolversUnionTypes: Record = {}; protected _resolversInterfaceTypes: Record = {}; protected _rootTypeNames = new Set(); protected _globalDeclarations = new Set(); protected _federation: ApolloFederation; protected _hasScalars = false; protected _fieldContextTypeMap: FieldContextTypeMap; protected _directiveContextTypesMap: FieldContextTypeMap; protected _checkedTypesWithNestedAbstractTypes: Record = {}; private _directiveResolverMappings: Record; private _shouldMapType: { [typeName: string]: boolean } = {}; constructor( rawConfig: TRawConfig, additionalConfig: TPluginConfig, private _schema: GraphQLSchema, defaultScalars: NormalizedScalarsMap = DEFAULT_SCALARS, federationMeta: FederationMeta = {} ) { super(rawConfig, { immutableTypes: getConfigValue(rawConfig.immutableTypes, false), optionalResolveType: getConfigValue(rawConfig.optionalResolveType, false), enumPrefix: getConfigValue(rawConfig.enumPrefix, true), enumSuffix: getConfigValue(rawConfig.enumSuffix, true), federation: getConfigValue(rawConfig.federation, false), resolverTypeWrapperSignature: getConfigValue(rawConfig.resolverTypeWrapperSignature, 'Promise | T'), enumValues: parseEnumValues({ schema: _schema, mapOrStr: rawConfig.enumValues, }), addUnderscoreToArgsType: getConfigValue(rawConfig.addUnderscoreToArgsType, false), addInterfaceFieldResolverTypes: getConfigValue(rawConfig.addInterfaceFieldResolverTypes, false), contextType: parseMapper(rawConfig.contextType || 'any', 'ContextType'), fieldContextTypes: getConfigValue(rawConfig.fieldContextTypes, []), directiveContextTypes: getConfigValue(rawConfig.directiveContextTypes, []), resolverTypeSuffix: getConfigValue(rawConfig.resolverTypeSuffix, 'Resolvers'), allResolversTypeName: getConfigValue(rawConfig.allResolversTypeName, 'Resolvers'), rootValueType: parseMapper(rawConfig.rootValueType || 'Record', 'RootValueType'), namespacedImportName: getConfigValue(rawConfig.namespacedImportName, ''), avoidOptionals: normalizeAvoidOptionals(rawConfig.avoidOptionals), defaultMapper: rawConfig.defaultMapper ? parseMapper(rawConfig.defaultMapper || 'any', 'DefaultMapperType') : null, mappers: transformMappers(rawConfig.mappers || {}, rawConfig.mapperTypeSuffix), scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars), internalResolversPrefix: getConfigValue(rawConfig.internalResolversPrefix, '__'), generateInternalResolversIfNeeded: {}, resolversNonOptionalTypename: normalizeResolversNonOptionalTypename( getConfigValue(rawConfig.resolversNonOptionalTypename, false) ), avoidCheckingAbstractTypesRecursively: getConfigValue(rawConfig.avoidCheckingAbstractTypesRecursively, false), ...additionalConfig, } as TPluginConfig); autoBind(this); this._federation = new ApolloFederation({ enabled: this.config.federation, schema: this.schema, meta: federationMeta, }); this._rootTypeNames = getRootTypeNames(_schema); this._variablesTransformer = new OperationVariablesToObject( this.scalars, this.convertName, this.config.namespacedImportName ); // 1. Parse schema meta at the start once, // so we can use it in subsequent generate functions this.parseSchemaMeta(); // 2. Generate types for resolvers this._resolversTypes = this.createResolversFields({ applyWrapper: type => this.applyResolverTypeWrapper(type), clearWrapper: type => this.clearResolverTypeWrapper(type), getTypeToUse: name => this.getTypeToUse(name), currentType: 'ResolversTypes', onNotMappedObjectType: ({ initialType }) => initialType, }); this._resolversParentTypes = this.createResolversFields({ applyWrapper: type => type, clearWrapper: type => type, getTypeToUse: name => this.getParentTypeToUse(name), currentType: 'ResolversParentTypes', shouldInclude: namedType => !isEnumType(namedType), onNotMappedObjectType: ({ typeName, initialType }) => { let result = initialType; if (this._federation.getMeta()[typeName]?.referenceSelectionSetsString) { result += ` | ${this.convertName('FederationReferenceTypes')}['${typeName}']`; } return result; }, }); this._resolversUnionTypes = this.createResolversUnionTypes(); this._resolversInterfaceTypes = this.createResolversInterfaceTypes(); this._fieldContextTypeMap = this.createFieldContextTypeMap(); this._directiveContextTypesMap = this.createDirectivedContextType(); this._directiveResolverMappings = rawConfig.directiveResolverMappings ?? {}; } public getResolverTypeWrapperSignature(): string { return `export type ResolverTypeWrapper = ${this.config.resolverTypeWrapperSignature};`; } protected shouldMapType(type: GraphQLNamedType, duringCheck: string[] = []): boolean { if (type.name.startsWith('__') || this.config.scalars[type.name]) { return false; } if (this.config.mappers[type.name]) { return true; } if (isObjectType(type) || isInterfaceType(type)) { const fields = type.getFields(); return Object.keys(fields) .filter(fieldName => { const field = fields[fieldName]; const fieldType = getBaseType(field.type); return !duringCheck.includes(fieldType.name); }) .some(fieldName => { const field = fields[fieldName]; const fieldType = getBaseType(field.type); if (this._shouldMapType[fieldType.name] !== undefined) { return this._shouldMapType[fieldType.name]; } if (this.config.mappers[type.name]) { return true; } duringCheck.push(type.name); const innerResult = this.shouldMapType(fieldType, duringCheck); return innerResult; }); } return false; } public convertName( node: ASTNode | string, options?: BaseVisitorConvertOptions & ConvertOptions, applyNamespacedImport = false ): string { const sourceType = super.convertName(node, options); return `${ applyNamespacedImport && this.config.namespacedImportName ? this.config.namespacedImportName + '.' : '' }${sourceType}`; } // Kamil: this one is heeeeavvyyyy protected createResolversFields({ applyWrapper, clearWrapper, getTypeToUse, currentType, shouldInclude, onNotMappedObjectType, }: { applyWrapper: (str: string) => string; clearWrapper: (str: string) => string; getTypeToUse: (str: string) => string; currentType: 'ResolversTypes' | 'ResolversParentTypes'; shouldInclude?: (type: GraphQLNamedType) => boolean; onNotMappedObjectType: (params: { initialType: string; typeName: string }) => string; }): ResolverTypes { const allSchemaTypes = this._schema.getTypeMap(); const typeNames = this._federation.filterTypeNames(Object.keys(allSchemaTypes)); // avoid checking all types recursively if we have no `mappers` defined if (Object.keys(this.config.mappers).length > 0) { for (const typeName of typeNames) { if (this._shouldMapType[typeName] === undefined) { const schemaType = allSchemaTypes[typeName]; this._shouldMapType[typeName] = this.shouldMapType(schemaType); } } } return typeNames.reduce((prev, typeName) => { const schemaType = allSchemaTypes[typeName]; if (typeName.startsWith('__') || (shouldInclude && !shouldInclude(schemaType))) { return prev; } const isRootType = this._rootTypeNames.has(typeName); const isMapped = this.config.mappers[typeName]; const isScalar = this.config.scalars[typeName]; const hasDefaultMapper = !!this.config.defaultMapper?.type; // Check for mappers first, even for root types, to allow overriding rootValueType if (isMapped && this.config.mappers[typeName].type && !hasPlaceholder(this.config.mappers[typeName].type)) { this.markMapperAsUsed(typeName); prev[typeName] = applyWrapper(this.config.mappers[typeName].type); return prev; } if (isRootType) { prev[typeName] = applyWrapper(this.config.rootValueType.type); return prev; } if (isEnumType(schemaType) && this.config.enumValues[typeName]) { const isExternalFile = !!this.config.enumValues[typeName].sourceFile; prev[typeName] = isExternalFile ? this.convertName(this.config.enumValues[typeName].typeIdentifier, { useTypesPrefix: false, useTypesSuffix: false, }) : this.config.enumValues[typeName].sourceIdentifier; } else if (hasDefaultMapper && !hasPlaceholder(this.config.defaultMapper.type)) { prev[typeName] = applyWrapper(this.config.defaultMapper.type); } else if (isScalar) { prev[typeName] = applyWrapper(this._getScalar(typeName)); } else if (isInterfaceType(schemaType)) { this._hasReferencedResolversInterfaceTypes = true; const type = this.convertName('ResolversInterfaceTypes'); const generic = this.convertName(currentType); prev[typeName] = applyWrapper(`${type}<${generic}>['${typeName}']`); return prev; } else if (isUnionType(schemaType)) { this._hasReferencedResolversUnionTypes = true; const type = this.convertName('ResolversUnionTypes'); const generic = this.convertName(currentType); prev[typeName] = applyWrapper(`${type}<${generic}>['${typeName}']`); } else if (isEnumType(schemaType)) { prev[typeName] = this.convertName( typeName, { useTypesPrefix: this.config.enumPrefix, useTypesSuffix: this.config.enumSuffix, }, true ); } else { prev[typeName] = this.convertName(typeName, {}, true); if (prev[typeName] !== 'any' && isObjectType(schemaType)) { const relevantFields = this.getRelevantFieldsToOmit({ schemaType, getTypeToUse, shouldInclude, }); // If relevantFields, puts ResolverTypeWrapper on top of an entire type let internalType = relevantFields.length > 0 ? this.replaceFieldsInType(prev[typeName], relevantFields) : prev[typeName]; if (isMapped) { // replace the placeholder with the actual type if (hasPlaceholder(internalType)) { internalType = replacePlaceholder(internalType, typeName); } if (this.config.mappers[typeName].type && hasPlaceholder(this.config.mappers[typeName].type)) { internalType = replacePlaceholder(this.config.mappers[typeName].type, internalType); } } else { internalType = onNotMappedObjectType({ typeName, initialType: internalType, }); } prev[typeName] = applyWrapper(internalType); } } if (!isMapped && hasDefaultMapper && hasPlaceholder(this.config.defaultMapper.type)) { const originalTypeName = isScalar ? this._getScalar(typeName) : prev[typeName]; if (isUnionType(schemaType)) { // Don't clear ResolverTypeWrapper from Unions prev[typeName] = replacePlaceholder(this.config.defaultMapper.type, originalTypeName); } else { const name = clearWrapper(originalTypeName); const replaced = replacePlaceholder(this.config.defaultMapper.type, name); prev[typeName] = applyWrapper(replaced); } } return prev; }, {}); } protected replaceFieldsInType( typeName: string, relevantFields: ReturnType ): string { this._globalDeclarations.add(OMIT_TYPE); return `Omit<${typeName}, ${relevantFields.map(f => `'${f.fieldName}'`).join(' | ')}> & { ${relevantFields .map(f => `${f.fieldName}${f.addOptionalSign ? '?' : ''}: ${f.replaceWithType}`) .join(', ')} }`; } protected applyMaybe(str: string): string { const namespacedImportPrefix = this.config.namespacedImportName ? this.config.namespacedImportName + '.' : ''; return `${namespacedImportPrefix}Maybe<${str}>`; } protected applyResolverTypeWrapper(str: string): string { return `ResolverTypeWrapper<${this.clearResolverTypeWrapper(str)}>`; } protected clearMaybe(str: string): string { const namespacedImportPrefix = this.config.namespacedImportName ? this.config.namespacedImportName + '.' : ''; if (str.startsWith(`${namespacedImportPrefix}Maybe<`)) { const maybeRe = new RegExp(`${namespacedImportPrefix.replace('.', '\\.')}Maybe<(.*?)>$`); return str.replace(maybeRe, '$1'); } return str; } protected clearResolverTypeWrapper(str: string): string { if (str.startsWith('ResolverTypeWrapper<')) { return str.replace(/ResolverTypeWrapper<(.*?)>$/, '$1'); } return str; } protected wrapWithArray(t: string): string { if (this.config.immutableTypes) { return `ReadonlyArray<${t}>`; } return `Array<${t}>`; } protected createResolversUnionTypes(): Record { if (!this._hasReferencedResolversUnionTypes) { return {}; } const unionTypes = Object.entries(this._parsedSchemaMeta.types.union).reduce>( (res, [typeName, { type: schemaType, unionMembers }]) => { if (isUnionType(schemaType)) { const { unionMember, excludeTypes } = this.config.resolversNonOptionalTypename; res[typeName] = this.getAbstractMembersType({ typeName, memberTypes: Object.values(unionMembers), isTypenameNonOptional: unionMember && !excludeTypes?.includes(typeName), }); } return res; }, {} ); return unionTypes; } protected createResolversInterfaceTypes(): Record { if (!this._hasReferencedResolversInterfaceTypes) { return {}; } const interfaceTypes = Object.entries(this._parsedSchemaMeta.types.interface).reduce>( (res, [typeName, { type: schemaType, implementingTypes }]) => { if (isInterfaceType(schemaType)) { const { interfaceImplementingType, excludeTypes } = this.config.resolversNonOptionalTypename; res[typeName] = this.getAbstractMembersType({ typeName, memberTypes: Object.values(implementingTypes), isTypenameNonOptional: interfaceImplementingType && !excludeTypes?.includes(typeName), }); } return res; }, {} ); return interfaceTypes; } /** * Function to generate the types of Abstract Type Members i.e. Union Members or Interface Implementing Types */ getAbstractMembersType({ typeName, memberTypes, isTypenameNonOptional, }: { typeName: string; memberTypes: readonly GraphQLObjectType[] | GraphQLObjectType[]; isTypenameNonOptional: boolean; }): string { const members = memberTypes .map(type => { const isTypeMapped = this.config.mappers[type.name]; // 1. If mapped without placehoder, just use it without doing extra checks if (isTypeMapped && !hasPlaceholder(isTypeMapped.type)) { return { typename: type.name, typeValue: isTypeMapped.type }; } // 2. Work out value for type // 2a. By default, use the typescript type let typeValue = this.convertName(type.name, {}, true); // 2b. Find fields to Omit if needed. // - If no field to Omit, "type with maybe Omit" is typescript type i.e. no Omit // - If there are fields to Omit, keep track of these "type with maybe Omit" to replace in original unionMemberValue const fieldsToOmit = this.getRelevantFieldsToOmit({ schemaType: type, getTypeToUse: baseType => `_RefType['${baseType}']`, }); if (fieldsToOmit.length > 0) { typeValue = this.replaceFieldsInType(typeValue, fieldsToOmit); } // 2c. If type is mapped with placeholder, use the "type with maybe Omit" as {T} if (isTypeMapped && hasPlaceholder(isTypeMapped.type)) { return { typename: type.name, typeValue: replacePlaceholder(isTypeMapped.type, typeValue) }; } // 2d. If has default mapper with placeholder, use the "type with maybe Omit" as {T} const hasDefaultMapper = !!this.config.defaultMapper?.type; const isScalar = this.config.scalars[typeName]; if (hasDefaultMapper && hasPlaceholder(this.config.defaultMapper.type)) { const finalTypename = isScalar ? this._getScalar(typeName) : typeValue; return { typename: type.name, typeValue: replacePlaceholder(this.config.defaultMapper.type, finalTypename), }; } return { typename: type.name, typeValue }; }) .map(({ typename, typeValue }) => { const nonOptionalTypenameModifier = isTypenameNonOptional ? ` & { __typename: '${typename}' }` : ''; return `( ${typeValue}${nonOptionalTypenameModifier} )`; // Must wrap every type in explicit "( )" to separate them }); const result = members.length === 0 ? 'never' : members.length > 1 ? `\n | ${members.map(m => m.replace(/\n/g, '\n ')).join('\n | ')}\n ` : members.join(' | '); return result; } protected createFieldContextTypeMap(): FieldContextTypeMap { return this.config.fieldContextTypes.reduce((prev, fieldContextType) => { const isScoped = fieldContextType.includes('\\#'); if (fieldContextType.includes('\\#')) { fieldContextType = fieldContextType.replace('\\#', ''); } const items = fieldContextType.split('#'); if (items.length === 3) { const [path, source, contextTypeName] = items; const sourceStr = isScoped ? `\\#${source}` : source; return { ...prev, [path]: parseMapper(`${sourceStr}#${contextTypeName}`) }; } const [path, contextType] = items; return { ...prev, [path]: parseMapper(contextType) }; }, {}); } protected createDirectivedContextType(): FieldContextTypeMap { return this.config.directiveContextTypes.reduce((prev, fieldContextType) => { const isScoped = fieldContextType.includes('\\#'); if (fieldContextType.includes('\\#')) { fieldContextType = fieldContextType.replace('\\#', ''); } const items = fieldContextType.split('#'); if (items.length === 3) { const [path, source, contextTypeName] = items; const sourceStr = isScoped ? `\\#${source}` : source; return { ...prev, [path]: parseMapper(`${sourceStr}#${contextTypeName}`) }; } const [path, contextType] = items; return { ...prev, [path]: parseMapper(contextType) }; }, {}); } public buildResolversTypes(): string { const declarationKind = 'type'; return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(this.convertName('ResolversTypes')) .withComment('Mapping between all available schema types and the resolvers types') .withBlock( Object.keys(this._resolversTypes) .map(typeName => indent(`${typeName}: ${this._resolversTypes[typeName]}${this.getPunctuation(declarationKind)}`) ) .join('\n') ).string; } public buildResolversParentTypes(): string { const declarationKind = 'type'; return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(this.convertName('ResolversParentTypes')) .withComment('Mapping between all available schema types and the resolvers parents') .withBlock( Object.keys(this._resolversParentTypes) .map(typeName => indent(`${typeName}: ${this._resolversParentTypes[typeName]}${this.getPunctuation(declarationKind)}`) ) .join('\n') ).string; } public buildResolversUnionTypes(): string { if (Object.keys(this._resolversUnionTypes).length === 0) { return ''; } const declarationKind = 'type'; return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(this.convertName('ResolversUnionTypes'), `<_RefType extends Record>`) .withComment('Mapping of union types') .withBlock( Object.entries(this._resolversUnionTypes) .map(([typeName, value]) => indent(`${typeName}: ${value}${this.getPunctuation(declarationKind)}`)) .join('\n') ).string; } public buildResolversInterfaceTypes(): string { if (Object.keys(this._resolversInterfaceTypes).length === 0) { return ''; } const declarationKind = 'type'; return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(this.convertName('ResolversInterfaceTypes'), `<_RefType extends Record>`) .withComment('Mapping of interface types') .withBlock( Object.entries(this._resolversInterfaceTypes) .map(([typeName, value]) => indent(`${typeName}: ${value}${this.getPunctuation(declarationKind)}`)) .join('\n') ).string; } public buildFederationTypes(): string { const federationMeta = this._federation.getMeta(); if (Object.keys(federationMeta).length === 0) { return ''; } const declarationKind = 'type'; return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(this.convertName('FederationTypes')) .withComment('Mapping of federation types') .withBlock( Object.keys(federationMeta) .map(typeName => { return indent(`${typeName}: ${this.convertName(typeName)}${this.getPunctuation(declarationKind)}`); }) .join('\n') ).string; } public buildFederationReferenceTypes(): string { const federationMeta = this._federation.getMeta(); if (Object.keys(federationMeta).length === 0) { return ''; } const declarationKind = 'type'; return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(this.convertName('FederationReferenceTypes')) .withComment('Mapping of federation reference types') .withBlock( Object.entries(federationMeta) .map(([typeName, { referenceSelectionSetsString }]) => { if (!referenceSelectionSetsString) { return undefined; } return indent(`${typeName}: ${referenceSelectionSetsString}${this.getPunctuation(declarationKind)}`); }) .filter(v => v) .join('\n') ).string; } public get schema(): GraphQLSchema { return this._schema; } public get defaultMapperType(): string { return this.config.defaultMapper.type; } public get unusedMappers() { return Object.keys(this.config.mappers).filter(name => !this._usedMappers[name]); } public get globalDeclarations(): string[] { return Array.from(this._globalDeclarations); } protected isMapperImported(groupedMappers: GroupedMappers, identifier: string, source: string): boolean { const exists = groupedMappers[source] ? !!groupedMappers[source].find(m => m.identifier === identifier) : false; const existsFromEnums = !!Object.keys(this.config.enumValues) .map(key => this.config.enumValues[key]) .find(o => o.sourceFile === source && o.typeIdentifier === identifier); return exists || existsFromEnums; } public get mappersImports(): string[] { const groupedMappers: GroupedMappers = {}; const addMapper = (source: string, identifier: string, asDefault: boolean) => { if (!this.isMapperImported(groupedMappers, identifier, source)) { groupedMappers[source] ||= []; groupedMappers[source].push({ identifier, asDefault }); } }; for (const { mapper } of Object.keys(this.config.mappers) .map(gqlTypeName => ({ gqlType: gqlTypeName, mapper: this.config.mappers[gqlTypeName] })) .filter(({ mapper }) => mapper.isExternal)) { const externalMapper = mapper as ExternalParsedMapper; const identifier = stripMapperTypeInterpolation(externalMapper.import); addMapper(externalMapper.source, identifier, externalMapper.default); } if (this.config.contextType.isExternal) { addMapper(this.config.contextType.source, this.config.contextType.import, this.config.contextType.default); } if (this.config.rootValueType.isExternal) { addMapper(this.config.rootValueType.source, this.config.rootValueType.import, this.config.rootValueType.default); } if (this.config.defaultMapper?.isExternal) { const identifier = stripMapperTypeInterpolation(this.config.defaultMapper.import); addMapper(this.config.defaultMapper.source, identifier, this.config.defaultMapper.default); } for (const parsedMapper of Object.values(this._fieldContextTypeMap)) { if (parsedMapper.isExternal) { addMapper(parsedMapper.source, parsedMapper.import, parsedMapper.default); } } for (const parsedMapper of Object.values(this._directiveContextTypesMap)) { if (parsedMapper.isExternal) { addMapper(parsedMapper.source, parsedMapper.import, parsedMapper.default); } } return Object.keys(groupedMappers) .map(source => buildMapperImport(source, groupedMappers[source], this.config.useTypeImports)) .filter(Boolean); } setDeclarationBlockConfig(config: DeclarationBlockConfig): void { this._declarationBlockConfig = config; } setVariablesTransformer(variablesTransfomer: OperationVariablesToObject): void { this._variablesTransformer = variablesTransfomer; } public hasScalars(): boolean { return this._hasScalars; } public hasFederation(): boolean { return Object.keys(this._federation.getMeta()).length > 0; } public getRootResolver(): RootResolver { const name = this.convertName(this.config.allResolversTypeName); const declarationKind = 'type'; const contextType = ``; const userDefinedTypes: RootResolver['generatedResolverTypes']['userDefined'] = {}; const content = [ new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(name, contextType) .withBlock( Object.keys(this._collectedResolvers) .map(schemaTypeName => { const resolverType = this._collectedResolvers[schemaTypeName]; if (resolverType.baseGeneratedTypename) { userDefinedTypes[schemaTypeName] = { name: resolverType.baseGeneratedTypename, hasIsTypeOf: this._parsedSchemaMeta.typesWithIsTypeOf[schemaTypeName] || false, }; const federationMeta = this._federation.getMeta()[schemaTypeName]; if (federationMeta) { userDefinedTypes[schemaTypeName].federation = { hasResolveReference: federationMeta.hasResolveReference, }; } } return indent(this.formatRootResolver(schemaTypeName, resolverType.typename, declarationKind)); }) .join('\n') ).string, ].join('\n'); return { content, generatedResolverTypes: { resolversMap: { name }, userDefined: userDefinedTypes, }, }; } protected formatRootResolver(schemaTypeName: string, resolverType: string, declarationKind: DeclarationKind): string { return `${schemaTypeName}${this.config.avoidOptionals.resolvers ? '' : '?'}: ${resolverType}${this.getPunctuation( declarationKind )}`; } public getAllDirectiveResolvers(): string { if (Object.keys(this._collectedDirectiveResolvers).length) { const declarationKind = 'type'; const name = this.convertName('DirectiveResolvers'); const contextType = ``; return [ new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(name, contextType) .withBlock( Object.keys(this._collectedDirectiveResolvers) .map(schemaTypeName => { const resolverType = this._collectedDirectiveResolvers[schemaTypeName]; return indent(this.formatRootResolver(schemaTypeName, resolverType, declarationKind)); }) .join('\n') ).string, ].join('\n'); } return ''; } ListType(node: ListTypeNode): string { const asString = node.type as any as string; return this.wrapWithArray(asString); } protected _getScalar(name: string): string { return `${ this.config.namespacedImportName ? this.config.namespacedImportName + '.' : '' }Scalars['${name}']['output']`; } NamedType(node: NamedTypeNode): string { const nameStr = node.name.value; if (this.config.scalars[nameStr]) { return this._getScalar(nameStr); } return this.convertName(node, null, true); } NonNullType(node: NonNullTypeNode): string { const asString = node.type as any as string; return asString; } protected markMapperAsUsed(name: string): void { this._usedMappers[name] = true; } protected getTypeToUse(name: string): string { const resolversType = this.convertName('ResolversTypes'); return `${resolversType}['${name}']`; } protected getParentTypeToUse(name: string): string { const resolversType = this.convertName('ResolversParentTypes'); return `${resolversType}['${name}']`; } protected getParentTypeForSignature(_node: FieldDefinitionNode): string { return 'ParentType'; } protected transformParentGenericType(parentType: string): string { return `ParentType extends ${parentType} = ${parentType}`; } FieldDefinition(node: FieldDefinitionNode, key: string | number, parent: any): FieldDefinitionResult { const hasArguments = node.arguments && node.arguments.length > 0; const declarationKind = 'type'; const original: FieldDefinitionNode = parent[key]; return { node: original, printContent: (parentNode, avoidResolverOptionals) => { const parentName = parentNode.name.value; const parentType = this.schema.getType(parentName); const meta: ReturnType['meta'] = {}; const typeName = node.name.value; const fieldsToGenerate = this._federation.findFieldNodesToGenerate({ node: parentNode }); const shouldGenerateField = fieldsToGenerate.some(field => field.name.value === typeName) || this._federation.isResolveReferenceField(node); if (!shouldGenerateField) { return { value: null, meta }; } const contextType = this.getContextType(parentName, node); let argsType = hasArguments ? this.convertName( parentName + (this.config.addUnderscoreToArgsType ? '_' : '') + this.convertName(typeName, { useTypesPrefix: false, useTypesSuffix: false, }) + 'Args', { useTypesPrefix: true, }, true ) : null; const avoidInputsOptionals = this.config.avoidOptionals.inputValue; if (argsType !== null) { const argsToForceRequire = original.arguments.filter( arg => !!arg.defaultValue || arg.type.kind === 'NonNullType' ); if (argsToForceRequire.length > 0) { argsType = this.applyRequireFields(argsType, argsToForceRequire); } else if (original.arguments.length > 0 && avoidInputsOptionals !== true) { argsType = this.applyOptionalFields(argsType, original.arguments); } } const { mappedTypeKey, resolverType } = ((): { mappedTypeKey: string; resolverType: string } => { const baseType = getBaseTypeNode(original.type); const realType = baseType.name.value; const typeToUse = this.getTypeToUse(realType); /** * Turns GraphQL type to TypeScript types (`mappedType`) e.g. * - String! -> ResolversTypes['String']> * - String -> Maybe * - [String] -> Maybe>> * - [String!]! -> Array */ const mappedType = this._variablesTransformer.wrapAstTypeWithModifiers(typeToUse, original.type); const subscriptionType = this._schema.getSubscriptionType(); const isSubscriptionType = subscriptionType && subscriptionType.name === parentName; if (isSubscriptionType) { return { mappedTypeKey: `${mappedType}, "${typeName}"`, resolverType: 'SubscriptionResolver', }; } const directiveMappings = node.directives ?.map(directive => this._directiveResolverMappings[directive.name.value]) .filter(Boolean) .reverse() ?? []; return { mappedTypeKey: mappedType, resolverType: directiveMappings[0] ?? 'Resolver', }; })(); const signature: { name: string; modifier: string; type: string; genericTypes: string[]; } = { name: typeName, modifier: avoidResolverOptionals ? '' : '?', type: resolverType, genericTypes: [mappedTypeKey, this.getParentTypeForSignature(node), contextType, argsType].filter(f => f), }; if (this._federation.isResolveReferenceField(node)) { if (!this._federation.getMeta()[parentType.name].hasResolveReference) { return { value: '', meta }; } const resultType = `${mappedTypeKey} | FederationReferenceType`; const referenceType = 'FederationReferenceType'; signature.type = 'ReferenceResolver'; signature.genericTypes = [resultType, referenceType, contextType]; meta.federation = { isResolveReference: true }; } return { value: indent( `${signature.name}${signature.modifier}: ${signature.type}<${signature.genericTypes.join( ', ' )}>${this.getPunctuation(declarationKind)}` ), meta, }; }, }; } private getFieldContextType(parentName: string, node: FieldDefinitionNode): string { if (this._fieldContextTypeMap[`${parentName}.${node.name.value}`]) { return this._fieldContextTypeMap[`${parentName}.${node.name.value}`].type; } return 'ContextType'; } private getContextType(parentName: string, node: FieldDefinitionNode): string { let contextType = this.getFieldContextType(parentName, node); for (const directive of node.directives) { const name = directive.name.value; const directiveMap = this._directiveContextTypesMap[name]; if (directiveMap) { contextType = `${directiveMap.type}<${contextType}>`; } } return contextType; } private parseSchemaMeta(): void { const allSchemaTypes = this._schema.getTypeMap(); const typeNames = this._federation.filterTypeNames(Object.keys(allSchemaTypes)); for (const typeName of typeNames) { const schemaType = allSchemaTypes[typeName]; if (isUnionType(schemaType)) { this._parsedSchemaMeta.types.union[schemaType.name] = { type: schemaType, unionMembers: {}, }; const unionMemberTypes = schemaType.getTypes(); for (const type of unionMemberTypes) { this._parsedSchemaMeta.types.union[schemaType.name].unionMembers[type.name] = type; this._parsedSchemaMeta.typesWithIsTypeOf[type.name] = true; } } if (isInterfaceType(schemaType)) { this._parsedSchemaMeta.types.interface[schemaType.name] = { type: schemaType, implementingTypes: {}, }; for (const graphqlType of Object.values(allSchemaTypes)) { if (graphqlType instanceof GraphQLObjectType) { const allInterfaces = graphqlType.getInterfaces(); if (allInterfaces.some(int => int.name === schemaType.name)) { this._parsedSchemaMeta.types.interface[schemaType.name].implementingTypes[graphqlType.name] = graphqlType; this._parsedSchemaMeta.typesWithIsTypeOf[graphqlType.name] = true; } } } } } } protected applyRequireFields(argsType: string, fields: InputValueDefinitionNode[]): string { this._globalDeclarations.add(REQUIRE_FIELDS_TYPE); return `RequireFields<${argsType}, ${fields.map(f => `'${f.name.value}'`).join(' | ')}>`; } protected applyOptionalFields(argsType: string, _fields: readonly InputValueDefinitionNode[]): string { return `Partial<${argsType}>`; } ObjectTypeDefinition(node: ObjectTypeDefinitionNode): string | null { const typeName = node.name.value; const fieldsToGenerate = this._federation.findFieldNodesToGenerate({ node }); if (fieldsToGenerate.length === 0) { return null; } const declarationKind = 'type'; const name = this.convertName(node, { suffix: this.config.resolverTypeSuffix, }); const parentType = this.getParentTypeToUse(typeName); const rootType = ((): false | 'query' | 'mutation' | 'subscription' => { if (this.schema.getQueryType()?.name === typeName) { return 'query'; } if (this.schema.getMutationType()?.name === typeName) { return 'mutation'; } if (this.schema.getSubscriptionType()?.name === typeName) { return 'subscription'; } return false; })(); const fieldsContent = (node.fields as unknown as FieldDefinitionResult[]) .map(({ printContent }) => { return printContent( node, (rootType === 'query' && this.config.avoidOptionals.query) || (rootType === 'mutation' && this.config.avoidOptionals.mutation) || (rootType === 'subscription' && this.config.avoidOptionals.subscription) || (rootType === false && this.config.avoidOptionals.resolvers) ).value; }) .filter(v => v); if (!rootType && this._parsedSchemaMeta.typesWithIsTypeOf[typeName]) { fieldsContent.push( indent( `${ this.config.internalResolversPrefix }isTypeOf?: IsTypeOfResolverFn${this.getPunctuation(declarationKind)}` ) ); } if (fieldsContent.length === 0) { return null; } const genericTypes: string[] = [ `ContextType = ${this.config.contextType.type}`, this.transformParentGenericType(parentType), ]; this._federation.addFederationTypeGenericIfApplicable({ genericTypes, federationTypesType: this.convertName('FederationReferenceTypes'), typeName, }); const block = new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(name, `<${genericTypes.join(', ')}>`) .withBlock(fieldsContent.join('\n')); this._collectedResolvers[node.name.value] = { typename: name + '', baseGeneratedTypename: name, }; return block.string; } UnionTypeDefinition(node: UnionTypeDefinitionNode, key: string | number, parent: any): string { const declarationKind = 'type'; const name = this.convertName(node, { suffix: this.config.resolverTypeSuffix, }); const originalNode = parent[key] as UnionTypeDefinitionNode; const possibleTypes = originalNode.types .map(node => node.name.value) .map(f => `'${f}'`) .join(' | '); this._collectedResolvers[node.name.value] = { typename: name + '', baseGeneratedTypename: name, }; const parentType = this.getParentTypeToUse(node.name.value); return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(name, ``) .withBlock( indent( `${this.config.internalResolversPrefix}resolveType${ this.config.optionalResolveType ? '?' : '' }: TypeResolveFn<${possibleTypes}, ParentType, ContextType>${this.getPunctuation(declarationKind)}` ) ).string; } ScalarTypeDefinition(node: ScalarTypeDefinitionNode): string { const nameAsString = node.name.value; const baseName = this.getTypeToUse(nameAsString); if (this._federation.skipScalar(nameAsString)) { return null; } this._hasScalars = true; this._collectedResolvers[node.name.value] = { typename: 'GraphQLScalarType', }; return new DeclarationBlock({ ...this._declarationBlockConfig, blockTransformer(block) { return block; }, }) .export() .asKind('interface') .withName( this.convertName(node, { suffix: 'ScalarConfig', }), ` extends GraphQLScalarTypeConfig<${baseName}, any>` ) .withBlock(indent(`name: '${node.name.value}'${this.getPunctuation('interface')}`)).string; } DirectiveDefinition(node: DirectiveDefinitionNode, key: string | number, parent: any): string { if (this._federation.skipDirective(node.name.value)) { return null; } const directiveName = this.convertName(node, { suffix: 'DirectiveResolver', }); const sourceNode = parent[key] as DirectiveDefinitionNode; const hasArguments = sourceNode.arguments && sourceNode.arguments.length > 0; this._collectedDirectiveResolvers[node.name.value] = directiveName + ''; const directiveArgsTypeName = this.convertName(node, { suffix: 'DirectiveArgs', }); return [ new DeclarationBlock({ ...this._declarationBlockConfig, blockTransformer(block) { return block; }, }) .export() .asKind('type') .withName(directiveArgsTypeName) .withContent( hasArguments ? `{\n${this._variablesTransformer.transform(sourceNode.arguments)}\n}` : '{ }' ).string, new DeclarationBlock({ ...this._declarationBlockConfig, blockTransformer(block) { return block; }, }) .export() .asKind('type') .withName( directiveName, `` ) .withContent(`DirectiveResolverFn`).string, ].join('\n'); } protected buildEnumResolverContentBlock(_node: EnumTypeDefinitionNode, _mappedEnumType: string): string { throw new Error(`buildEnumResolverContentBlock is not implemented!`); } protected buildEnumResolversExplicitMappedValues( _node: EnumTypeDefinitionNode, _valuesMapping: { [valueName: string]: string | number } ): string { throw new Error(`buildEnumResolversExplicitMappedValues is not implemented!`); } EnumTypeDefinition(node: EnumTypeDefinitionNode): string { const rawTypeName = node.name.value; // If we have enumValues set, and it's point to an external enum - we need to allow internal values resolvers // In case we have enumValues set but as explicit values, no need to to do mapping since it's already // have type validation (the original enum has been modified by base types plugin). // If we have mapper for that type - we can skip if (!this.config.mappers[rawTypeName] && !this.config.enumValues[rawTypeName]) { return null; } const name = this.convertName(node, { suffix: this.config.resolverTypeSuffix }); this._collectedResolvers[rawTypeName] = { typename: name, baseGeneratedTypename: name, }; const hasExplicitValues = this.config.enumValues[rawTypeName]?.mappedValues; return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind('type') .withName(name) .withContent( hasExplicitValues ? this.buildEnumResolversExplicitMappedValues(node, this.config.enumValues[rawTypeName].mappedValues) : this.buildEnumResolverContentBlock(node, this.getTypeToUse(rawTypeName)) ).string; } InterfaceTypeDefinition(node: InterfaceTypeDefinitionNode): string { const name = this.convertName(node, { suffix: this.config.resolverTypeSuffix, }); const declarationKind = 'type'; const typeName = node.name.value; const implementingTypes = Object.keys(this._parsedSchemaMeta.types.interface[typeName].implementingTypes); this._collectedResolvers[typeName] = { typename: name + '', baseGeneratedTypename: name, }; const parentType = this.getParentTypeToUse(typeName); const genericTypes: string[] = [ `ContextType = ${this.config.contextType.type}`, this.transformParentGenericType(parentType), ]; this._federation.addFederationTypeGenericIfApplicable({ genericTypes, federationTypesType: this.convertName('FederationReferenceTypes'), typeName, }); const possibleTypes = implementingTypes.map(name => `'${name}'`).join(' | ') || 'null'; // An Interface has __resolveType resolver, and no other fields. const blockFields: string[] = [ indent( `${this.config.internalResolversPrefix}resolveType${ this.config.optionalResolveType ? '?' : '' }: TypeResolveFn<${possibleTypes}, ParentType, ContextType>${this.getPunctuation(declarationKind)}` ), ]; // An Interface in Federation may have the additional __resolveReference resolver, if resolvable. // So, we filter out the normal fields declared on the Interface and add the __resolveReference resolver. const fields = (node.fields as unknown as FieldDefinitionResult[]).map(({ printContent }) => printContent(node, this.config.avoidOptionals.resolvers) ); for (const field of fields) { if (field.meta.federation?.isResolveReference || this.config.addInterfaceFieldResolverTypes) { blockFields.push(field.value); } } return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(name, `<${genericTypes.join(', ')}>`) .withBlock(blockFields.join('\n')).string; } SchemaDefinition() { return null; } SchemaExtension() { return null; } private getRelevantFieldsToOmit({ schemaType, shouldInclude, getTypeToUse, }: { schemaType: GraphQLObjectType; getTypeToUse: (name: string) => string; shouldInclude?: (type: GraphQLNamedType) => boolean; }): { addOptionalSign: boolean; fieldName: string; replaceWithType: string; }[] { const fields = schemaType.getFields(); return this._federation .filterFieldNames(Object.keys(fields)) .filter(fieldName => { const field = fields[fieldName]; const baseType = getBaseType(field.type); // Filter out fields of types that are not included if (shouldInclude && !shouldInclude(baseType)) { return false; } return true; }) .map(fieldName => { const field = fields[fieldName]; const baseType = getBaseType(field.type); const isUnion = isUnionType(baseType); const isInterface = isInterfaceType(baseType); const isObject = isObjectType(baseType); let isObjectWithAbstractType = false; if (isObject && !this.config.avoidCheckingAbstractTypesRecursively) { isObjectWithAbstractType = checkIfObjectTypeHasAbstractTypesRecursively(baseType, { isObjectWithAbstractType, checkedTypesWithNestedAbstractTypes: this._checkedTypesWithNestedAbstractTypes, }); } if ( !this.config.mappers[baseType.name] && !isUnion && !isInterface && !this._shouldMapType[baseType.name] && !isObjectWithAbstractType ) { return null; } const addOptionalSign = !this.config.avoidOptionals.resolvers && !isNonNullType(field.type); return { addOptionalSign, fieldName, replaceWithType: wrapTypeWithModifiers(getTypeToUse(baseType.name), field.type, { wrapOptional: this.applyMaybe, wrapArray: this.wrapWithArray, }), }; }) .filter(a => a); } } function replacePlaceholder(pattern: string, typename: string): string { return pattern.replace(/\{T\}/g, typename); } function hasPlaceholder(pattern: string): boolean { return pattern.includes('{T}'); } function normalizeResolversNonOptionalTypename( input?: boolean | ResolversNonOptionalTypenameConfig ): ResolversNonOptionalTypenameConfig { const defaultConfig: ResolversNonOptionalTypenameConfig = { unionMember: false, }; if (typeof input === 'boolean') { return { unionMember: input, interfaceImplementingType: input, }; } return { ...defaultConfig, ...input, }; } function checkIfObjectTypeHasAbstractTypesRecursively( baseType: GraphQLObjectType, result: { isObjectWithAbstractType: boolean; checkedTypesWithNestedAbstractTypes: Record; } ): boolean { if ( result.checkedTypesWithNestedAbstractTypes[baseType.name] && (result.checkedTypesWithNestedAbstractTypes[baseType.name].checkStatus === 'yes' || result.checkedTypesWithNestedAbstractTypes[baseType.name].checkStatus === 'no') ) { return result.checkedTypesWithNestedAbstractTypes[baseType.name].checkStatus === 'yes'; } result.checkedTypesWithNestedAbstractTypes[baseType.name] ||= { checkStatus: 'checking' }; let atLeastOneFieldWithAbstractType = false; const fields = baseType.getFields(); for (const field of Object.values(fields)) { const fieldBaseType = getBaseType(field.type); // If the field is self-referencing, skip it. Otherwise, it's an infinite loop if (baseType.name === fieldBaseType.name) { continue; } // If the current field has been checked, and it has nested abstract types, // mark the parent type as having nested abstract types if (result.checkedTypesWithNestedAbstractTypes[fieldBaseType.name]) { if (result.checkedTypesWithNestedAbstractTypes[fieldBaseType.name].checkStatus === 'yes') { atLeastOneFieldWithAbstractType = true; result.checkedTypesWithNestedAbstractTypes[baseType.name].checkStatus = 'yes'; } continue; } else { result.checkedTypesWithNestedAbstractTypes[fieldBaseType.name] = { checkStatus: 'checking' }; } // If the field is an abstract type, then both the field type and parent type are abstract types if (isInterfaceType(fieldBaseType) || isUnionType(fieldBaseType)) { atLeastOneFieldWithAbstractType = true; result.checkedTypesWithNestedAbstractTypes[fieldBaseType.name].checkStatus = 'yes'; result.checkedTypesWithNestedAbstractTypes[baseType.name].checkStatus = 'yes'; continue; } // If the field is an object, check it recursively to see if it has abstract types // If it does, both field type and parent type have abstract types if (isObjectType(fieldBaseType)) { // IMPORTANT: we are pointing the parent type to the field type here // to make sure when the field type is updated to either 'yes' or 'no', it becomes the parent's type as well if (result.checkedTypesWithNestedAbstractTypes[baseType.name].checkStatus === 'checking') { result.checkedTypesWithNestedAbstractTypes[baseType.name] = result.checkedTypesWithNestedAbstractTypes[fieldBaseType.name]; } const foundAbstractType = checkIfObjectTypeHasAbstractTypesRecursively(fieldBaseType, result); if (foundAbstractType) { atLeastOneFieldWithAbstractType = true; result.checkedTypesWithNestedAbstractTypes[fieldBaseType.name].checkStatus = 'yes'; result.checkedTypesWithNestedAbstractTypes[baseType.name].checkStatus = 'yes'; } continue; } // Otherwise, the current field type is not abstract type // This includes scalar types, enums, input types and objects without abstract types result.checkedTypesWithNestedAbstractTypes[fieldBaseType.name].checkStatus = 'no'; } if (atLeastOneFieldWithAbstractType) { result.isObjectWithAbstractType = true; } else { result.checkedTypesWithNestedAbstractTypes[baseType.name].checkStatus = 'no'; } return atLeastOneFieldWithAbstractType; } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts ================================================ import { DirectiveDefinitionNode, DirectiveNode, EnumTypeDefinitionNode, EnumValueDefinitionNode, FieldDefinitionNode, GraphQLEnumType, GraphQLSchema, InputObjectTypeDefinitionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, isEnumType, Kind, ListTypeNode, NamedTypeNode, NonNullTypeNode, ObjectTypeDefinitionNode, ScalarTypeDefinitionNode, UnionTypeDefinitionNode, } from 'graphql'; import { BaseVisitor, ParsedConfig, RawConfig } from './base-visitor.js'; import { normalizeDeclarationKind } from './declaration-kinds.js'; import { parseEnumValues } from './enum-values.js'; import { transformDirectiveArgumentAndInputFieldMappings } from './mappers.js'; import { DEFAULT_SCALARS } from './scalars.js'; import { DeclarationKind, DeclarationKindConfig, DirectiveArgumentAndInputFieldMappings, EnumValuesMap, NormalizedScalarsMap, ParsedDirectiveArgumentAndInputFieldMappings, ParsedEnumValuesMap, } from './types.js'; import { buildScalarsFromConfig, DeclarationBlock, DeclarationBlockConfig, getConfigValue, indent, isOneOfInputObjectType, transformComment, wrapWithSingleQuotes, } from './utils.js'; import { OperationVariablesToObject } from './variables-to-object.js'; export interface ParsedTypesConfig extends ParsedConfig { enumValues: ParsedEnumValuesMap; declarationKind: DeclarationKindConfig; addUnderscoreToArgsType: boolean; onlyEnums: boolean; onlyOperationTypes: boolean; enumPrefix: boolean; enumSuffix: boolean; fieldWrapperValue: string; wrapFieldDefinitions: boolean; entireFieldWrapperValue: string; wrapEntireDefinitions: boolean; ignoreEnumValuesFromSchema: boolean; directiveArgumentAndInputFieldMappings: ParsedDirectiveArgumentAndInputFieldMappings; } export interface RawTypesConfig extends RawConfig { /** * @description Adds `_` to generated `Args` types in order to avoid duplicate identifiers. * * @exampleMarkdown * ## With Custom Values * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * addUnderscoreToArgsType: true * }, * }, * }, * }; * export default config; * ``` */ addUnderscoreToArgsType?: boolean; /** * @description Overrides the default value of enum values declared in your GraphQL schema. * You can also map the entire enum to an external type by providing a string that of `module#type`. * * @exampleMarkdown * ## With Custom Values * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * enumValues: { * MyEnum: { * A: 'foo' * } * } * }, * }, * }, * }; * export default config; * ``` * * ## With External Enum * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * enumValues: { * MyEnum: './my-file#MyCustomEnum', * } * }, * }, * }, * }; * export default config; * ``` * * ## Import All Enums from a file * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * enumValues: { * MyEnum: './my-file', * } * }, * }, * }, * }; * export default config; * ``` */ enumValues?: EnumValuesMap; /** * @description Overrides the default output for various GraphQL elements. * * @exampleMarkdown * ## Override all declarations * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * declarationKind: 'interface' * }, * }, * }, * }; * export default config; * ``` * * ## Override only specific declarations * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * declarationKind: { * type: 'interface', * input: 'interface' * } * }, * }, * }, * }; * export default config; * ``` */ declarationKind?: DeclarationKind | DeclarationKindConfig; /** * @default true * @description Allow you to disable prefixing for generated enums, works in combination with `typesPrefix`. * * @exampleMarkdown * ## Disable enum prefixes * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * typesPrefix: 'I', * enumPrefix: false * }, * }, * }, * }; * export default config; * ``` */ enumPrefix?: boolean; /** * @default true * @description Allow you to disable suffixing for generated enums, works in combination with `typesSuffix`. * * @exampleMarkdown * ## Disable enum suffixes * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * typesSuffix: 'I', * enumSuffix: false * }, * }, * }, * }; * export default config; * ``` */ enumSuffix?: boolean; /** * @description Allow you to add wrapper for field type, use T as the generic value. Make sure to set `wrapFieldDefinitions` to `true` in order to make this flag work. * @default T * * @exampleMarkdown * ## Allow Promise * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * wrapFieldDefinitions: true, * fieldWrapperValue: 'T | Promise', * }, * }, * }, * }; * export default config; * ``` */ fieldWrapperValue?: string; /** * @description Set to `true` in order to wrap field definitions with `FieldWrapper`. * This is useful to allow return types such as Promises and functions. * @default false * * @exampleMarkdown * ## Enable wrapping fields * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * wrapFieldDefinitions: true, * }, * }, * }, * }; * export default config; * ``` */ wrapFieldDefinitions?: boolean; /** * @description This will cause the generator to emit types for enums only * @default false * * @exampleMarkdown * ## Override all definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * onlyEnums: true, * }, * }, * }, * }; * export default config; * ``` */ onlyEnums?: boolean; /** * @description This will cause the generator to emit types for operations only (basically only enums and scalars) * @default false * * @exampleMarkdown * ## Override all definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * onlyOperationTypes: true, * }, * }, * }, * }; * export default config; * ``` */ onlyOperationTypes?: boolean; /** * @description This will cause the generator to ignore enum values defined in GraphQLSchema * @default false * * @exampleMarkdown * ## Ignore enum values from schema * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * ignoreEnumValuesFromSchema: true, * }, * }, * }, * }; * export default config; * ``` */ ignoreEnumValuesFromSchema?: boolean; /** * @name wrapEntireFieldDefinitions * @type boolean * @description Set to `true` in order to wrap field definitions with `EntireFieldWrapper`. * This is useful to allow return types such as Promises and functions for fields. * Differs from `wrapFieldDefinitions` in that this wraps the entire field definition if i.e. the field is an Array, while * `wrapFieldDefinitions` will wrap every single value inside the array. * @default true * * @example Enable wrapping entire fields * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * wrapEntireFieldDefinitions: false, * }, * }, * }, * }; * export default config; * ``` */ wrapEntireFieldDefinitions?: boolean; /** * @name entireFieldWrapperValue * @type string * @description Allow to override the type value of `EntireFieldWrapper`. This wrapper applies outside of Array and Maybe * unlike `fieldWrapperValue`, that will wrap the inner type. * @default T | Promise | (() => T | Promise) * * @example Only allow values * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * entireFieldWrapperValue: 'T', * }, * }, * }, * }; * export default config; * ``` */ entireFieldWrapperValue?: string; /** * @description Replaces a GraphQL scalar with a custom type based on the applied directive on an argument or input field. * * You can use both `module#type` and `module#namespace#type` syntax. * Will NOT work with introspected schemas since directives are not exported. * Only works with directives on ARGUMENT_DEFINITION or INPUT_FIELD_DEFINITION. * * **WARNING:** Using this option does only change the type definitions. * * For actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://graphql-tools.com/docs/schema-directives)) that apply those rules! * Otherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors. * * Please use this configuration option with care! * * @exampleMarkdown * ## Custom Context Type\ * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * directiveArgumentAndInputFieldMappings: { * AsNumber: 'number', * AsComplex: './my-models#Complex', * } * }, * }, * }, * }; * export default config; * ``` */ directiveArgumentAndInputFieldMappings?: DirectiveArgumentAndInputFieldMappings; /** * @description Adds a suffix to the imported names to prevent name clashes. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * directiveArgumentAndInputFieldMappings: 'Model' * }, * }, * }, * }; * export default config; * ``` */ directiveArgumentAndInputFieldMappingTypeSuffix?: string; } const onlyUnderscoresPattern = /^_+$/; export class BaseTypesVisitor< TRawConfig extends RawTypesConfig = RawTypesConfig, TPluginConfig extends ParsedTypesConfig = ParsedTypesConfig > extends BaseVisitor { protected _argumentsTransformer: OperationVariablesToObject; constructor( protected _schema: GraphQLSchema, rawConfig: TRawConfig, additionalConfig: TPluginConfig, defaultScalars: NormalizedScalarsMap = DEFAULT_SCALARS ) { super(rawConfig, { enumPrefix: getConfigValue(rawConfig.enumPrefix, true), enumSuffix: getConfigValue(rawConfig.enumSuffix, true), onlyEnums: getConfigValue(rawConfig.onlyEnums, false), onlyOperationTypes: getConfigValue(rawConfig.onlyOperationTypes, false), addUnderscoreToArgsType: getConfigValue(rawConfig.addUnderscoreToArgsType, false), enumValues: parseEnumValues({ schema: _schema, mapOrStr: rawConfig.enumValues, ignoreEnumValuesFromSchema: rawConfig.ignoreEnumValuesFromSchema, }), declarationKind: normalizeDeclarationKind(rawConfig.declarationKind), scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars), fieldWrapperValue: getConfigValue(rawConfig.fieldWrapperValue, 'T'), wrapFieldDefinitions: getConfigValue(rawConfig.wrapFieldDefinitions, false), entireFieldWrapperValue: getConfigValue(rawConfig.entireFieldWrapperValue, 'T'), wrapEntireDefinitions: getConfigValue(rawConfig.wrapEntireFieldDefinitions, false), ignoreEnumValuesFromSchema: getConfigValue(rawConfig.ignoreEnumValuesFromSchema, false), directiveArgumentAndInputFieldMappings: transformDirectiveArgumentAndInputFieldMappings( rawConfig.directiveArgumentAndInputFieldMappings ?? {}, rawConfig.directiveArgumentAndInputFieldMappingTypeSuffix ), ...additionalConfig, }); // Note: Missing directive mappers but not a problem since always overriden by implementors this._argumentsTransformer = new OperationVariablesToObject(this.scalars, this.convertName); } protected getExportPrefix(): string { return 'export '; } public getFieldWrapperValue(): string { if (this.config.fieldWrapperValue) { return `${this.getExportPrefix()}type FieldWrapper = ${this.config.fieldWrapperValue};`; } return ''; } public getEntireFieldWrapperValue(): string { if (this.config.entireFieldWrapperValue) { return `${this.getExportPrefix()}type EntireFieldWrapper = ${this.config.entireFieldWrapperValue};`; } return ''; } public getScalarsImports(): string[] { return Object.keys(this.config.scalars).reduce((res, enumName) => { const mappedValue = this.config.scalars[enumName]; if (mappedValue.input.isExternal) { res.push(this._buildTypeImport(mappedValue.input.import, mappedValue.input.source, mappedValue.input.default)); } if (mappedValue.output.isExternal) { res.push( this._buildTypeImport(mappedValue.output.import, mappedValue.output.source, mappedValue.output.default) ); } return res; }, []); } public getDirectiveArgumentAndInputFieldMappingsImports(): string[] { return Object.keys(this.config.directiveArgumentAndInputFieldMappings) .map(directive => { const mappedValue = this.config.directiveArgumentAndInputFieldMappings[directive]; if (mappedValue.isExternal) { return this._buildTypeImport(mappedValue.import, mappedValue.source, mappedValue.default); } return null; }) .filter(a => a); } public get scalarsDefinition(): string { if (this.config.onlyEnums) return ''; const allScalars = Object.keys(this.config.scalars).map(scalarName => { const inputScalarValue = this.config.scalars[scalarName].input.type; const outputScalarValue = this.config.scalars[scalarName].output.type; const scalarType = this._schema.getType(scalarName); const comment = scalarType?.astNode && scalarType.description ? transformComment(scalarType.description, 1) : ''; const { scalar } = this._parsedConfig.declarationKind; return ( comment + indent( `${scalarName}: { input: ${inputScalarValue}${this.getPunctuation( scalar )} output: ${outputScalarValue}${this.getPunctuation(scalar)} }` ) ); }); return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(this._parsedConfig.declarationKind.scalar) .withName('Scalars') .withComment('All built-in and custom scalars, mapped to their actual values') .withBlock(allScalars.join('\n')).string; } public get directiveArgumentAndInputFieldMappingsDefinition(): string { const directiveEntries = Object.entries(this.config.directiveArgumentAndInputFieldMappings); if (directiveEntries.length === 0) { return ''; } const allDirectives: Array = []; for (const [directiveName, parsedMapper] of directiveEntries) { const directiveType = this._schema.getDirective(directiveName); const comment = directiveType?.astNode && directiveType.description ? transformComment(directiveType.description, 1) : ''; const { directive } = this._parsedConfig.declarationKind; allDirectives.push(comment + indent(`${directiveName}: ${parsedMapper.type}${this.getPunctuation(directive)}`)); } return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(this._parsedConfig.declarationKind.directive) .withName('DirectiveArgumentAndInputFieldMappings') .withComment('Type overrides using directives') .withBlock(allDirectives.join('\n')).string; } setDeclarationBlockConfig(config: DeclarationBlockConfig): void { this._declarationBlockConfig = config; } setArgumentsTransformer(argumentsTransfomer: OperationVariablesToObject): void { this._argumentsTransformer = argumentsTransfomer; } NonNullType(node: NonNullTypeNode): string { const asString = node.type as any as string; return asString; } getInputObjectDeclarationBlock(node: InputObjectTypeDefinitionNode): DeclarationBlock { return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(this._parsedConfig.declarationKind.input) .withName(this.convertName(node)) .withComment(node.description?.value) .withBlock(node.fields.join('\n')); } getInputObjectOneOfDeclarationBlock(node: InputObjectTypeDefinitionNode): DeclarationBlock { // As multiple fields always result in a union, we have // to force a declaration kind of `type` in this case const declarationKind = node.fields.length === 1 ? this._parsedConfig.declarationKind.input : 'type'; return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(declarationKind) .withName(this.convertName(node)) .withComment(node.description?.value) .withContent(`\n` + node.fields.join('\n |')); } InputObjectTypeDefinition(node: InputObjectTypeDefinitionNode): string { if (this.config.onlyEnums) return ''; if (isOneOfInputObjectType(this._schema.getType(node.name.value))) { return this.getInputObjectOneOfDeclarationBlock(node).string; } return this.getInputObjectDeclarationBlock(node).string; } InputValueDefinition(node: InputValueDefinitionNode): string { if (this.config.onlyEnums) return ''; const comment = transformComment(node.description.value, 1); const { input } = this._parsedConfig.declarationKind; let type: string = node.type as any as string; if (node.directives && this.config.directiveArgumentAndInputFieldMappings) { type = this._getDirectiveOverrideType(node.directives) || type; } return comment + indent(`${node.name.value}: ${type}${this.getPunctuation(input)}`); } FieldDefinition(node: FieldDefinitionNode): string { if (this.config.onlyEnums) return ''; const typeString = node.type as any as string; const { type } = this._parsedConfig.declarationKind; const comment = this.getNodeComment(node); return comment + indent(`${node.name.value}: ${typeString}${this.getPunctuation(type)}`); } UnionTypeDefinition(node: UnionTypeDefinitionNode, key: string | number | undefined, parent: any): string { if (this.config.onlyOperationTypes || this.config.onlyEnums) return ''; const originalNode = parent[key] as UnionTypeDefinitionNode; const possibleTypes = originalNode.types .map(t => (this.scalars[t.name.value] ? this._getScalar(t.name.value, 'output') : this.convertName(t))) .join(' | '); return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind('type') .withName(this.convertName(node)) .withComment(node.description.value) .withContent(possibleTypes).string; } protected mergeInterfaces(interfaces: string[], hasOtherFields: boolean): string { return interfaces.join(' & ') + (interfaces.length && hasOtherFields ? ' & ' : ''); } appendInterfacesAndFieldsToBlock(block: DeclarationBlock, interfaces: string[], fields: string[]): void { block.withContent(this.mergeInterfaces(interfaces, fields.length > 0)); block.withBlock(this.mergeAllFields(fields, interfaces.length > 0)); } getObjectTypeDeclarationBlock( node: ObjectTypeDefinitionNode, originalNode: ObjectTypeDefinitionNode ): DeclarationBlock { const optionalTypename = this.config.nonOptionalTypename ? '__typename' : '__typename?'; const { type, interface: interfacesType } = this._parsedConfig.declarationKind; const allFields = [ ...(this.config.addTypename ? [ indent( `${this.config.immutableTypes ? 'readonly ' : ''}${optionalTypename}: '${ node.name.value }'${this.getPunctuation(type)}` ), ] : []), ...node.fields, ] as string[]; const interfacesNames = originalNode.interfaces ? originalNode.interfaces.map(i => this.convertName(i)) : []; const declarationBlock = new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(type) .withName(this.convertName(node)) .withComment(node.description?.value); if (type === 'interface' || type === 'class') { if (interfacesNames.length > 0) { const keyword = interfacesType === 'interface' && type === 'class' ? 'implements' : 'extends'; declarationBlock.withContent(`${keyword} ` + interfacesNames.join(', ') + (allFields.length > 0 ? ' ' : ' {}')); } declarationBlock.withBlock(this.mergeAllFields(allFields, false)); } else { this.appendInterfacesAndFieldsToBlock(declarationBlock, interfacesNames, allFields); } return declarationBlock; } protected mergeAllFields(allFields: string[], _hasInterfaces: boolean): string { return allFields.join('\n'); } ObjectTypeDefinition(node: ObjectTypeDefinitionNode, key: number | string, parent: any): string { if (this.config.onlyOperationTypes || this.config.onlyEnums) return ''; const originalNode = parent[key] as ObjectTypeDefinitionNode; return [this.getObjectTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)] .filter(f => f) .join('\n\n'); } getInterfaceTypeDeclarationBlock( node: InterfaceTypeDefinitionNode, _originalNode: InterfaceTypeDefinitionNode ): DeclarationBlock { const declarationBlock = new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(this._parsedConfig.declarationKind.interface) .withName(this.convertName(node)) .withComment(node.description?.value); return declarationBlock.withBlock(node.fields.join('\n')); } InterfaceTypeDefinition(node: InterfaceTypeDefinitionNode, key: number | string, parent: any): string { if (this.config.onlyOperationTypes || this.config.onlyEnums) return ''; const originalNode = parent[key] as InterfaceTypeDefinitionNode; return [this.getInterfaceTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)] .filter(f => f) .join('\n\n'); } ScalarTypeDefinition(_node: ScalarTypeDefinitionNode): string { // We empty this because we handle scalars in a different way, see constructor. return ''; } protected _buildTypeImport(identifier: string, source: string, asDefault = false): string { const { useTypeImports } = this.config; if (asDefault) { if (useTypeImports) { return `import type { default as ${identifier} } from '${source}';`; } return `import ${identifier} from '${source}';`; } return `import${useTypeImports ? ' type' : ''} { ${identifier} } from '${source}';`; } protected handleEnumValueMapper( typeIdentifier: string, importIdentifier: string | null, sourceIdentifier: string | null, sourceFile: string | null ): string[] { if (importIdentifier !== sourceIdentifier) { // use namespace import to dereference nested enum // { enumValues: { MyEnum: './my-file#NS.NestedEnum' } } return [ this._buildTypeImport(importIdentifier || sourceIdentifier, sourceFile), `import ${typeIdentifier} = ${sourceIdentifier};`, ]; } if (sourceIdentifier !== typeIdentifier) { return [this._buildTypeImport(`${sourceIdentifier} as ${typeIdentifier}`, sourceFile)]; } return [this._buildTypeImport(importIdentifier || sourceIdentifier, sourceFile)]; } public getEnumsImports(): string[] { return Object.keys(this.config.enumValues) .flatMap(enumName => { const mappedValue = this.config.enumValues[enumName]; if (mappedValue.sourceFile) { if (mappedValue.isDefault) { return [this._buildTypeImport(mappedValue.typeIdentifier, mappedValue.sourceFile, true)]; } return this.handleEnumValueMapper( mappedValue.typeIdentifier, mappedValue.importIdentifier, mappedValue.sourceIdentifier, mappedValue.sourceFile ); } return []; }) .filter(Boolean); } EnumTypeDefinition(node: EnumTypeDefinitionNode): string { const enumName = node.name.value; // In case of mapped external enum string if (this.config.enumValues[enumName]?.sourceFile) { return null; } return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind('enum') .withName( this.convertName(node, { useTypesPrefix: this.config.enumPrefix, useTypesSuffix: this.config.enumSuffix, }) ) .withComment(node.description.value) .withBlock(this.buildEnumValuesBlock(enumName, node.values)).string; } protected makeValidEnumIdentifier(identifier: string): string { if (/^[0-9]/.exec(identifier)) { return wrapWithSingleQuotes(identifier, true); } return identifier; } protected buildEnumValuesBlock(typeName: string, values: ReadonlyArray): string { const schemaEnumType: GraphQLEnumType | undefined = this._schema ? (this._schema.getType(typeName) as GraphQLEnumType) : undefined; return values .map(enumOption => { const optionName = this.makeValidEnumIdentifier( this.convertName(enumOption, { useTypesPrefix: false, // We can only strip out the underscores if the value contains other // characters. Otherwise we'll generate syntactically invalid code. transformUnderscore: !onlyUnderscoresPattern.test(enumOption.name.value), }) ); const comment = this.getNodeComment(enumOption); const schemaEnumValue = schemaEnumType && !this.config.ignoreEnumValuesFromSchema ? schemaEnumType.getValue(enumOption.name.value).value : undefined; let enumValue: string | number = typeof schemaEnumValue === 'undefined' ? enumOption.name.value : schemaEnumValue; if (typeof this.config.enumValues[typeName]?.mappedValues?.[enumValue] !== 'undefined') { enumValue = this.config.enumValues[typeName].mappedValues[enumValue]; } return ( comment + indent( `${optionName}${this._declarationBlockConfig.enumNameValueSeparator} ${wrapWithSingleQuotes( enumValue, typeof schemaEnumValue !== 'undefined' )}` ) ); }) .join(',\n'); } DirectiveDefinition(_node: DirectiveDefinitionNode): string { return ''; } getArgumentsObjectDeclarationBlock( node: InterfaceTypeDefinitionNode | ObjectTypeDefinitionNode, name: string, field: FieldDefinitionNode ): DeclarationBlock { return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(this._parsedConfig.declarationKind.arguments) .withName(this.convertName(name)) .withComment(node.description?.value) .withBlock(this._argumentsTransformer.transform(field.arguments)); } getArgumentsObjectTypeDefinition( node: InterfaceTypeDefinitionNode | ObjectTypeDefinitionNode, name: string, field: FieldDefinitionNode ): string { if (this.config.onlyEnums) return ''; return this.getArgumentsObjectDeclarationBlock(node, name, field).string; } protected buildArgumentsBlock(node: InterfaceTypeDefinitionNode | ObjectTypeDefinitionNode) { const fieldsWithArguments = node.fields.filter(field => field.arguments && field.arguments.length > 0) || []; return fieldsWithArguments .map(field => { const name = node.name.value + (this.config.addUnderscoreToArgsType ? '_' : '') + this.convertName(field, { useTypesPrefix: false, useTypesSuffix: false, }) + 'Args'; return this.getArgumentsObjectTypeDefinition(node, name, field); }) .join('\n\n'); } protected _getScalar(name: string, type: 'input' | 'output'): string { return `Scalars['${name}']['${type}']`; } protected _getDirectiveArgumentNadInputFieldMapping(name: string): string { return `DirectiveArgumentAndInputFieldMappings['${name}']`; } protected _getDirectiveOverrideType(directives: ReadonlyArray): string | null { const type = directives .map(directive => { const directiveName = directive.name.value; if (this.config.directiveArgumentAndInputFieldMappings[directiveName]) { return this._getDirectiveArgumentNadInputFieldMapping(directiveName); } return null; }) .reverse() .find(a => !!a); return type || null; } protected _getTypeForNode(node: NamedTypeNode, isVisitingInputType: boolean): string { const typeAsString = node.name.value; if (this.scalars[typeAsString]) { return this._getScalar(typeAsString, isVisitingInputType ? 'input' : 'output'); } if (this.config.enumValues[typeAsString]) { return this.config.enumValues[typeAsString].typeIdentifier; } const schemaType = this._schema.getType(typeAsString); if (schemaType && isEnumType(schemaType)) { return this.convertName(node, { useTypesPrefix: this.config.enumPrefix, useTypesSuffix: this.config.enumSuffix, }); } return this.convertName(node); } NamedType(node: NamedTypeNode, key, parent, path, ancestors): string { const currentVisitContext = this.getVisitorKindContextFromAncestors(ancestors); const isVisitingInputType = currentVisitContext.includes(Kind.INPUT_OBJECT_TYPE_DEFINITION); const typeToUse = this._getTypeForNode(node, isVisitingInputType); if (!isVisitingInputType && this.config.fieldWrapperValue && this.config.wrapFieldDefinitions) { return `FieldWrapper<${typeToUse}>`; } return typeToUse; } ListType(node: ListTypeNode, _key, _parent, _path, _ancestors): string { const asString = node.type as any as string; return this.wrapWithListType(asString); } SchemaDefinition() { return null; } SchemaExtension() { return null; } getNodeComment(node: FieldDefinitionNode | EnumValueDefinitionNode | InputValueDefinitionNode): string { let commentText = node.description?.value; const deprecationDirective = node.directives.find(v => v.name.value === 'deprecated'); if (deprecationDirective) { const deprecationReason = this.getDeprecationReason(deprecationDirective); commentText = `${commentText ? `${commentText}\n` : ''}@deprecated ${deprecationReason}`; } const comment = transformComment(commentText, 1); return comment; } protected getDeprecationReason(directive: DirectiveNode): string | void { if (directive.name.value === 'deprecated') { let reason = 'Field no longer supported'; const deprecatedReason = directive.arguments[0]; if (deprecatedReason && deprecatedReason.value.kind === Kind.STRING) { reason = deprecatedReason.value.value; } return reason; } } protected wrapWithListType(str: string): string { return `Array<${str}>`; } } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/base-visitor.ts ================================================ import autoBind from 'auto-bind'; import { ASTNode, FragmentDefinitionNode, OperationDefinitionNode } from 'graphql'; import { FragmentImport, ImportDeclaration } from './imports.js'; import { convertFactory } from './naming.js'; import { ConvertFn, ConvertOptions, DeclarationKind, LoadedFragment, NamingConvention, NormalizedScalarsMap, ParsedScalarsMap, ScalarsMap, } from './types.js'; import { DeclarationBlockConfig } from './utils.js'; import { normalizeImportExtension } from '@graphql-codegen/plugin-helpers'; export interface BaseVisitorConvertOptions { useTypesPrefix?: boolean; useTypesSuffix?: boolean; } export type InlineFragmentTypeOptions = 'inline' | 'combine' | 'mask'; export interface ParsedConfig { scalars: ParsedScalarsMap; convert: ConvertFn; typesPrefix: string; typesSuffix: string; addTypename: boolean; nonOptionalTypename: boolean; extractAllFieldsToTypes: boolean; externalFragments: LoadedFragment[]; fragmentImports: ImportDeclaration[]; immutableTypes: boolean; useTypeImports: boolean; allowEnumStringTypes: boolean; inlineFragmentTypes: InlineFragmentTypeOptions; emitLegacyCommonJSImports?: boolean; importExtension: '' | `.${string}`; printFieldsOnNewLines: boolean; includeExternalFragments: boolean; } export interface RawConfig { /** * @description Makes scalars strict. * * If scalars are found in the schema that are not defined in `scalars` * an error will be thrown during codegen. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * strictScalars: true, * }, * }, * }, * }; * export default config; * ``` */ strictScalars?: boolean; /** * @description Allows you to override the type that unknown scalars will have. * @default any * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * defaultScalarType: 'unknown' * }, * }, * }, * }; * export default config; * ``` */ defaultScalarType?: string; /** * @description Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * scalars: { * ID: { * input: 'string', * output: 'string | number' * } * DateTime: 'Date', * JSON: '{ [key: string]: any }', * } * }, * }, * }, * }; * export default config; * ``` */ scalars?: ScalarsMap; /** * @default change-case-all#pascalCase * @description Allow you to override the naming convention of the output. * You can either override all namings, or specify an object with specific custom naming convention per output. * The format of the converter must be a valid `module#method`. * Allowed values for specific output are: `typeNames`, `enumValues`. * You can also use "keep" to keep all GraphQL names as-is. * Additionally, you can set `transformUnderscore` to `true` if you want to override the default behavior, * which is to preserve underscores. * * Available case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst` * [See more](https://github.com/btxtiger/change-case-all) * * @exampleMarkdown * ## Override All Names * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * namingConvention: 'change-case-all#lowerCase', * }, * }, * }, * }; * export default config; * ``` * * ## Upper-case enum values * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * namingConvention: { * typeNames: 'change-case-all#pascalCase', * enumValues: 'change-case-all#upperCase', * } * }, * }, * }, * }; * export default config; * ``` * * ## Keep names as is * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * namingConvention: 'keep', * }, * }, * }, * }; * export default config; * ``` * * ## Remove Underscores * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * namingConvention: { * typeNames: 'change-case-all#pascalCase', * transformUnderscore: true * } * }, * }, * }, * }; * export default config; * ``` */ namingConvention?: NamingConvention; /** * @default "" * @description Prefixes all the generated types. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * typesPrefix: 'I', * }, * }, * }, * }; * export default config; * ``` */ typesPrefix?: string; /** * @default "" * @description Suffixes all the generated types. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * typesSuffix: 'I', * }, * }, * }, * }; * export default config; * ``` */ typesSuffix?: string; /** * @default false * @description Does not add `__typename` to the generated types, unless it was specified in the selection set. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * skipTypename: true * }, * }, * }, * }; * export default config; * ``` */ skipTypename?: boolean; /** * @default false * @description Automatically adds `__typename` field to the generated types, even when they are not specified * in the selection set, and makes it non-optional * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * nonOptionalTypename: true * }, * }, * }, * }; * export default config; * ``` */ nonOptionalTypename?: boolean; /** * @name useTypeImports * @type boolean * @default false * @description Will use `import type {}` rather than `import {}` when importing only types. This gives * compatibility with TypeScript's "importsNotUsedAsValues": "error" option * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * useTypeImports: true * }, * }, * }, * }; * export default config; * ``` */ useTypeImports?: boolean; /* The following configuration are for preset configuration and should not be set manually (for most use cases...) */ /** * @ignore */ externalFragments?: LoadedFragment[]; /** * @ignore */ fragmentImports?: ImportDeclaration[]; /** * @ignore */ globalNamespace?: boolean; /** * @ignore */ allowEnumStringTypes?: boolean; /** * @description Whether fragment types should be inlined into other operations. * "inline" is the default behavior and will perform deep inlining fragment types within operation type definitions. * "combine" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types). * "mask" transforms the types for use with fragment masking. Useful when masked types are needed when not using the "client" preset e.g. such as combining it with Apollo Client's data masking feature. * * @type string * @default inline */ inlineFragmentTypes?: InlineFragmentTypeOptions; /** * @deprecated Please use `importExtension` instead. * @default true * @description Emit legacy common js imports. * Default it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065). */ emitLegacyCommonJSImports?: boolean; /** * @description Append this extension to all imports. * Useful for ESM environments that require file extensions in import statements. */ importExtension?: '' | `.${string}`; /** * @default false * @description Extract all field types to their own types, instead of inlining them. * This helps to reduce type duplication, and makes type errors more readable. * It can also significantly reduce the size of the generated code, the generation time, * and the typechecking time. */ extractAllFieldsToTypes?: boolean; /** * @default false * @description If you prefer to have each field in generated types printed on a new line, set this to true. * This can be useful for improving readability of the resulting types, * without resorting to running tools like Prettier on the output. */ printFieldsOnNewLines?: boolean; /** * @default false * @description Whether to include external fragments in the generated code. External fragments are not defined * in the same location as the operation definition. */ includeExternalFragments?: boolean; } export class BaseVisitor { protected _parsedConfig: TPluginConfig; protected _declarationBlockConfig: DeclarationBlockConfig = {}; public readonly scalars: NormalizedScalarsMap; constructor(rawConfig: TRawConfig, additionalConfig: Partial) { const importExtension = normalizeImportExtension({ emitLegacyCommonJSImports: rawConfig.emitLegacyCommonJSImports, importExtension: rawConfig.importExtension, }); this._parsedConfig = { convert: convertFactory(rawConfig), typesPrefix: rawConfig.typesPrefix || '', typesSuffix: rawConfig.typesSuffix || '', externalFragments: rawConfig.externalFragments || [], fragmentImports: rawConfig.fragmentImports || [], addTypename: !rawConfig.skipTypename, nonOptionalTypename: !!rawConfig.nonOptionalTypename, useTypeImports: !!rawConfig.useTypeImports, allowEnumStringTypes: !!rawConfig.allowEnumStringTypes, inlineFragmentTypes: rawConfig.inlineFragmentTypes ?? 'inline', emitLegacyCommonJSImports: rawConfig.emitLegacyCommonJSImports ?? true, importExtension, extractAllFieldsToTypes: rawConfig.extractAllFieldsToTypes ?? false, printFieldsOnNewLines: rawConfig.printFieldsOnNewLines ?? false, includeExternalFragments: rawConfig.includeExternalFragments ?? false, ...((additionalConfig || {}) as any), }; this.scalars = {}; for (const key of Object.keys(this.config.scalars || {})) { this.scalars[key] = { input: this.config.scalars[key]?.input?.type, output: this.config.scalars[key]?.output?.type, }; } autoBind(this); } protected getVisitorKindContextFromAncestors(ancestors: ASTNode[]): string[] { if (!ancestors) { return []; } return ancestors.map(t => t.kind).filter(Boolean); } get config(): TPluginConfig { return this._parsedConfig; } public convertName(node: ASTNode | string, options?: BaseVisitorConvertOptions & ConvertOptions): string { const useTypesPrefix = typeof options?.useTypesPrefix === 'boolean' ? options.useTypesPrefix : true; const useTypesSuffix = typeof options?.useTypesSuffix === 'boolean' ? options.useTypesSuffix : true; let convertedName = ''; if (useTypesPrefix) { convertedName += this.config.typesPrefix; } convertedName += this.config.convert(node, options); if (useTypesSuffix) { convertedName += this.config.typesSuffix; } return convertedName; } public getOperationSuffix( node: FragmentDefinitionNode | OperationDefinitionNode | string, operationType: string ): string { const { omitOperationSuffix = false, dedupeOperationSuffix = false } = this.config as { [key: string]: any }; const operationName = typeof node === 'string' ? node : node.name ? node.name.value : ''; return omitOperationSuffix ? '' : dedupeOperationSuffix && operationName.toLowerCase().endsWith(operationType.toLowerCase()) ? '' : operationType; } public getFragmentSuffix(node: FragmentDefinitionNode | string): string { return this.getOperationSuffix(node, 'Fragment'); } public getFragmentName(node: FragmentDefinitionNode | string): string { return this.convertName(node, { suffix: this.getFragmentSuffix(node), useTypesPrefix: false, }); } public getFragmentVariableName(node: FragmentDefinitionNode | string): string { const { omitOperationSuffix = false, dedupeOperationSuffix = false, fragmentVariableSuffix = 'FragmentDoc', fragmentVariablePrefix = '', } = this.config as { [key: string]: any }; const fragmentName = typeof node === 'string' ? node : node.name.value; const suffix = omitOperationSuffix ? '' : dedupeOperationSuffix && fragmentName.toLowerCase().endsWith('fragment') && fragmentVariableSuffix.toLowerCase().startsWith('fragment') ? fragmentVariableSuffix.substring('fragment'.length) : fragmentVariableSuffix; return this.convertName(node, { prefix: fragmentVariablePrefix, suffix, useTypesPrefix: false, }); } protected getPunctuation(_declarationKind: DeclarationKind): string { return ''; } } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts ================================================ import { basename, extname } from 'path'; import { normalizeImportExtension, oldVisit, Types } from '@graphql-codegen/plugin-helpers'; import { optimizeDocumentNode } from '@graphql-tools/optimize'; import autoBind from 'auto-bind'; import { pascalCase } from 'change-case-all'; import { DepGraph } from 'dependency-graph'; import { DefinitionNode, DirectiveNode, DocumentNode, FragmentDefinitionNode, FragmentSpreadNode, GraphQLSchema, Kind, OperationDefinitionNode, SelectionNode, print, } from 'graphql'; import gqlTag from 'graphql-tag'; import { BaseVisitor, ParsedConfig, RawConfig } from './base-visitor.js'; import { LoadedFragment, ParsedImport } from './types.js'; import { buildScalarsFromConfig, unique, flatten, getConfigValue, groupBy } from './utils.js'; import { FragmentImport, ImportDeclaration, generateFragmentImportStatement } from './imports.js'; gqlTag.enableExperimentalFragmentVariables(); export enum DocumentMode { graphQLTag = 'graphQLTag', documentNode = 'documentNode', documentNodeImportFragments = 'documentNodeImportFragments', external = 'external', string = 'string', } const EXTENSIONS_TO_REMOVE = ['.ts', '.tsx', '.js', '.jsx']; export interface RawClientSideBasePluginConfig extends RawConfig { /** * @default graphql-tag#gql * @description Customize from which module will `gql` be imported from. * This is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`. * * @exampleMarkdown * ## graphql.macro * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * gqlImport: 'graphql.macro#gql' * }, * }, * }, * }; * export default config; * ``` * * ## Gatsby * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * gqlImport: 'gatsby#graphql' * }, * }, * }, * }; * export default config; * ``` */ gqlImport?: string; /** * @default graphql#DocumentNode * @description Customize from which module will `DocumentNode` be imported from. * This is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`. */ documentNodeImport?: string; /** * @default false * @description Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier. */ noExport?: boolean; /** * @default false * @description Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix. */ dedupeOperationSuffix?: boolean; /** * @default false * @description Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`. */ omitOperationSuffix?: boolean; /** * @default "" * @description Adds a suffix to generated operation result type names */ operationResultSuffix?: string; /** * @default "" * @description Changes the GraphQL operations variables prefix. */ documentVariablePrefix?: string; /** * @default Document * @description Changes the GraphQL operations variables suffix. */ documentVariableSuffix?: string; /** * @default "" * @description Changes the GraphQL fragments variables prefix. */ fragmentVariablePrefix?: string; /** * @default FragmentDoc * @description Changes the GraphQL fragments variables suffix. */ fragmentVariableSuffix?: string; /** * @default graphQLTag * @description Declares how DocumentNode are created: * * - `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client * - `documentNode`: document nodes will be generated as objects when we generate the templates. * - `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them. * - `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom` * * Note that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter. * */ documentMode?: DocumentMode; /** * @default true * @description If you are using `documentMode: documentNode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document. * This will remove all "loc" and "description" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`). */ optimizeDocumentNode?: boolean; /** * @default "" * @description This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using. * This is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there. */ importOperationTypesFrom?: string; /** * @default "" * @description This config should be used if `documentMode` is `external`. This has 2 usage: * * - any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document * - 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * documentMode: 'external', * importDocumentNodeExternallyFrom: 'path/to/document-node-file', * }, * }, * }, * }; * export default config; * ``` * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * documentMode: 'external', * importDocumentNodeExternallyFrom: 'near-operation-file', * }, * }, * }, * }; * export default config; * ``` * */ importDocumentNodeExternallyFrom?: string; /** * @default false * @description This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler. */ pureMagicComment?: boolean; /** * @default false * @description If set to true, it will enable support for parsing variables on fragments. */ experimentalFragmentVariables?: boolean; } export interface ClientSideBasePluginConfig extends ParsedConfig { gqlImport: string; documentNodeImport: string; operationResultSuffix: string; dedupeOperationSuffix: boolean; omitOperationSuffix: boolean; noExport: boolean; documentVariablePrefix: string; documentVariableSuffix: string; fragmentVariablePrefix: string; fragmentVariableSuffix: string; documentMode?: DocumentMode; importDocumentNodeExternallyFrom?: 'near-operation-file' | string; importOperationTypesFrom?: string; globalNamespace?: boolean; pureMagicComment?: boolean; optimizeDocumentNode: boolean; experimentalFragmentVariables?: boolean; unstable_onExecutableDocumentNode?: Unstable_OnExecutableDocumentNode; unstable_omitDefinitions?: boolean; } type ExecutableDocumentNodeMeta = Record; type Unstable_OnExecutableDocumentNode = (documentNode: DocumentNode) => void | ExecutableDocumentNodeMeta; export class ClientSideBaseVisitor< TRawConfig extends RawClientSideBasePluginConfig = RawClientSideBasePluginConfig, TPluginConfig extends ClientSideBasePluginConfig = ClientSideBasePluginConfig > extends BaseVisitor { protected _collectedOperations: OperationDefinitionNode[] = []; protected _documents: Types.DocumentFile[] = []; protected _additionalImports: string[] = []; protected _imports = new Set(); private _onExecutableDocumentNode?: Unstable_OnExecutableDocumentNode; private _omitDefinitions?: boolean; private readonly _fragments: ReadonlyMap; private readonly fragmentsGraph: DepGraph; constructor( protected _schema: GraphQLSchema, fragments: LoadedFragment[], rawConfig: TRawConfig, additionalConfig: Partial, documents?: Types.DocumentFile[] ) { super(rawConfig, { scalars: buildScalarsFromConfig(_schema, rawConfig), dedupeOperationSuffix: getConfigValue(rawConfig.dedupeOperationSuffix, false), optimizeDocumentNode: getConfigValue(rawConfig.optimizeDocumentNode, true), omitOperationSuffix: getConfigValue(rawConfig.omitOperationSuffix, false), gqlImport: rawConfig.gqlImport || null, documentNodeImport: rawConfig.documentNodeImport || null, noExport: !!rawConfig.noExport, importOperationTypesFrom: getConfigValue(rawConfig.importOperationTypesFrom, null), operationResultSuffix: getConfigValue(rawConfig.operationResultSuffix, ''), documentVariablePrefix: getConfigValue(rawConfig.documentVariablePrefix, ''), documentVariableSuffix: getConfigValue(rawConfig.documentVariableSuffix, 'Document'), fragmentVariablePrefix: getConfigValue(rawConfig.fragmentVariablePrefix, ''), fragmentVariableSuffix: getConfigValue(rawConfig.fragmentVariableSuffix, 'FragmentDoc'), documentMode: getConfigValue(rawConfig.documentMode, DocumentMode.graphQLTag), importDocumentNodeExternallyFrom: getConfigValue(rawConfig.importDocumentNodeExternallyFrom, ''), pureMagicComment: getConfigValue(rawConfig.pureMagicComment, false), experimentalFragmentVariables: getConfigValue(rawConfig.experimentalFragmentVariables, false), ...additionalConfig, } as any); this._documents = documents; this._onExecutableDocumentNode = (rawConfig as any).unstable_onExecutableDocumentNode; this._omitDefinitions = (rawConfig as any).unstable_omitDefinitions; this._fragments = new Map(fragments.map(fragment => [fragment.name, fragment])); this.fragmentsGraph = this._getFragmentsGraph(); autoBind(this); } protected _extractFragments( document: FragmentDefinitionNode | OperationDefinitionNode, withNested = false ): string[] { if (!document) { return []; } const names: Set = new Set(); oldVisit(document, { enter: { FragmentSpread: (node: FragmentSpreadNode) => { names.add(node.name.value); if (withNested) { const foundFragment = this._fragments.get(node.name.value); if (foundFragment) { const childItems = this._extractFragments(foundFragment.node, true); if (childItems && childItems.length > 0) { for (const item of childItems) { names.add(item); } } } } }, }, }); return Array.from(names); } protected _transformFragments(fragmentNames: Array): string[] { return fragmentNames.map(document => this.getFragmentVariableName(document)); } protected _includeFragments(fragments: string[]): string { if (fragments && fragments.length > 0) { if (this.config.documentMode === DocumentMode.documentNode || this.config.documentMode === DocumentMode.string) { return Array.from(this._fragments.values()) .filter(f => fragments.includes(this.getFragmentVariableName(f.name))) .map(fragment => print(fragment.node)) .join('\n'); } if (this.config.documentMode === DocumentMode.documentNodeImportFragments) { return ''; } return String(fragments.map(name => '${' + name + '}').join('\n')); } return ''; } protected _prepareDocument(documentStr: string): string { return documentStr; } protected _gql(node: FragmentDefinitionNode | OperationDefinitionNode): string { const includeNestedFragments = this.config.documentMode === DocumentMode.documentNode || this.config.documentMode === DocumentMode.string; const fragmentNames = this._extractFragments(node, includeNestedFragments); const fragments = this._transformFragments(fragmentNames); const doc = this._prepareDocument(` ${print(node).split('\\').join('\\\\') /* Re-escape escaped values in GraphQL syntax */} ${this._includeFragments(fragments)}`); if (this.config.documentMode === DocumentMode.documentNode) { let gqlObj = gqlTag([doc]); if (this.config.optimizeDocumentNode) { gqlObj = optimizeDocumentNode(gqlObj); } return JSON.stringify(gqlObj); } if (this.config.documentMode === DocumentMode.documentNodeImportFragments) { const gqlObj = gqlTag([doc]); // We need to inline all fragments that are used in this document // Otherwise we might encounter the following issues: // 1. missing fragments // 2. duplicated fragments const fragmentDependencyNames = new Set( fragmentNames.map(name => this.fragmentsGraph.dependenciesOf(name)).flatMap(item => item) ); for (const fragmentName of fragmentNames) { fragmentDependencyNames.add(fragmentName); } const jsonStringify = (json: unknown) => JSON.stringify(json, (key, value) => (key === 'loc' ? undefined : value)); let definitions = [...gqlObj.definitions]; for (const fragmentName of fragmentDependencyNames) { definitions.push(this.fragmentsGraph.getNodeData(fragmentName).node); } if (this.config.optimizeDocumentNode) { definitions = [ ...optimizeDocumentNode({ kind: Kind.DOCUMENT, definitions, }).definitions, ]; } let metaString = ''; if (this._onExecutableDocumentNode) { const meta = this._getGraphQLCodegenMetadata(node, definitions); if (meta) { if (this._omitDefinitions === true) { return `{${`"__meta__":${JSON.stringify(meta)},`.slice(0, -1)}}`; } metaString = `"__meta__":${JSON.stringify(meta)},`; } } return `{${metaString}"kind":"${Kind.DOCUMENT}","definitions":${jsonStringify(definitions)}}`; } if (this.config.documentMode === DocumentMode.string) { if (node.kind === Kind.FRAGMENT_DEFINITION) { const meta = this._getGraphQLCodegenMetadata(node, gqlTag([doc]).definitions); return `new TypedDocumentString(\`${doc}\`, ${JSON.stringify({ fragmentName: node.name.value, ...meta })})`; } if (this._onExecutableDocumentNode && node.kind === Kind.OPERATION_DEFINITION) { const meta = this._getGraphQLCodegenMetadata(node, gqlTag([doc]).definitions); if (meta) { if (this._omitDefinitions === true) { return `{${`"__meta__":${JSON.stringify(meta)},`.slice(0, -1)}}`; } return `new TypedDocumentString(\`${doc}\`, ${JSON.stringify(meta)})`; } } return `new TypedDocumentString(\`${doc}\`)`; } const gqlImport = this._parseImport(this.config.gqlImport || 'graphql-tag'); return (gqlImport.propName || 'gql') + '`' + doc + '`'; } protected _getGraphQLCodegenMetadata( node: OperationDefinitionNode | FragmentDefinitionNode, definitions?: ReadonlyArray ): Record | void | undefined { let meta: Record | void | undefined; if (node.kind === Kind.OPERATION_DEFINITION) { meta = this._onExecutableDocumentNode({ kind: Kind.DOCUMENT, definitions, }); } const deferredFields = this._findDeferredFields(node); if (Object.keys(deferredFields).length) { meta = { ...meta, deferredFields, }; } return meta; } protected _findDeferredFields(node: OperationDefinitionNode | FragmentDefinitionNode): { [fargmentName: string]: string[]; } { const deferredFields: { [fargmentName: string]: string[] } = {}; const queue: SelectionNode[] = [...node.selectionSet.selections]; while (queue.length) { const selection = queue.shift(); if ( selection.kind === Kind.FRAGMENT_SPREAD && selection.directives.some((d: DirectiveNode) => d.name.value === 'defer') ) { const fragmentName = selection.name.value; const fragment = this.fragmentsGraph.getNodeData(fragmentName); if (fragment) { const fields = fragment.node.selectionSet.selections.reduce((acc, selection) => { if (selection.kind === Kind.FIELD) { acc.push(selection.name.value); } return acc; }, []); deferredFields[fragmentName] = fields; } } else if (selection.kind === Kind.FIELD && selection.selectionSet) { queue.push(...selection.selectionSet.selections); } } return deferredFields; } protected _generateFragment(fragmentDocument: FragmentDefinitionNode): string | void { const name = this.getFragmentVariableName(fragmentDocument); const fragmentTypeSuffix = this.getFragmentSuffix(fragmentDocument); return `export const ${name} =${this.config.pureMagicComment ? ' /*#__PURE__*/' : ''} ${this._gql( fragmentDocument )}${this.getDocumentNodeSignature( this.convertName(fragmentDocument.name.value, { useTypesPrefix: true, suffix: fragmentTypeSuffix, }), this.config.experimentalFragmentVariables ? this.convertName(fragmentDocument.name.value, { suffix: fragmentTypeSuffix + 'Variables', }) : 'unknown', fragmentDocument )};`; } private _getFragmentsGraph(): DepGraph { const graph = new DepGraph({ circular: true }); for (const fragment of this._fragments.values()) { if (graph.hasNode(fragment.name)) { const cachedAsString = print(graph.getNodeData(fragment.name).node); const asString = print(fragment.node); if (cachedAsString !== asString) { throw new Error(`Duplicated fragment called '${fragment.name}'!`); } } graph.addNode(fragment.name, fragment); } for (const fragment of this._fragments.values()) { const depends = this._extractFragments(fragment.node); if (depends && depends.length > 0) { for (const name of depends) { graph.addDependency(fragment.name, name); } } } return graph; } public get fragments(): string { if (this._fragments.size === 0 || this.config.documentMode === DocumentMode.external) { return ''; } const graph = this.fragmentsGraph; const orderedDeps = graph.overallOrder(); const localFragments = orderedDeps .filter(name => !graph.getNodeData(name).isExternal || this.config.includeExternalFragments) .map(name => this._generateFragment(graph.getNodeData(name).node)); return localFragments.join('\n'); } protected _parseImport(importStr: string): ParsedImport { // This is a special case when we want to ignore importing, and just use `gql` provided from somewhere else // Plugins that uses that will need to ensure to add import/declaration for the gql identifier if (importStr === 'gql') { return { moduleName: null, propName: 'gql', }; } // This is a special use case, when we don't want this plugin to manage the import statement // of the gql tag. In this case, we provide something like `Namespace.gql` and it will be used instead. if (importStr.includes('.gql')) { return { moduleName: null, propName: importStr, }; } const [moduleName, propName] = importStr.split('#'); return { moduleName, propName, }; } protected _generateImport( { moduleName, propName }: ParsedImport, varName: string, isTypeImport: boolean ): string | null { const typeImport = isTypeImport && this.config.useTypeImports ? 'import type' : 'import'; const propAlias = propName === varName ? '' : ` as ${varName}`; if (moduleName) { return `${typeImport} ${propName ? `{ ${propName}${propAlias} }` : varName} from '${moduleName}';`; } return null; } private clearExtension(path: string): string { const extension = extname(path); const importExtension = normalizeImportExtension({ emitLegacyCommonJSImports: this.config.emitLegacyCommonJSImports, importExtension: this.config.importExtension, }); if (extension === importExtension) { return path; } if (EXTENSIONS_TO_REMOVE.includes(extension)) { return path.replace(/\.[^/.]+$/, ''); } return path; } public getImports(options: { excludeFragments?: boolean } = {}): string[] { for (const i of this._additionalImports || []) { this._imports.add(i); } switch (this.config.documentMode) { case DocumentMode.documentNode: case DocumentMode.documentNodeImportFragments: { const documentNodeImport = this._parseImport(this.config.documentNodeImport || 'graphql#DocumentNode'); const tagImport = this._generateImport(documentNodeImport, 'DocumentNode', true); if (tagImport) { this._imports.add(tagImport); } break; } case DocumentMode.graphQLTag: { const gqlImport = this._parseImport(this.config.gqlImport || 'graphql-tag'); const tagImport = this._generateImport(gqlImport, 'gql', false); if (tagImport) { this._imports.add(tagImport); } break; } case DocumentMode.external: { if (this._collectedOperations.length > 0) { if (this.config.importDocumentNodeExternallyFrom === 'near-operation-file' && this._documents.length === 1) { let documentPath = `./${this.clearExtension(basename(this._documents[0].location))}`; documentPath += normalizeImportExtension({ emitLegacyCommonJSImports: this.config.emitLegacyCommonJSImports, importExtension: this.config.importExtension, }); this._imports.add(`import * as Operations from '${documentPath}';`); } else { if (!this.config.importDocumentNodeExternallyFrom) { // eslint-disable-next-line no-console console.warn('importDocumentNodeExternallyFrom must be provided if documentMode=external'); } this._imports.add( `import * as Operations from '${this.clearExtension(this.config.importDocumentNodeExternallyFrom)}';` ); } } break; } default: break; } const excludeFragments = options.excludeFragments || this.config.globalNamespace || this.config.documentMode !== DocumentMode.graphQLTag; if (!excludeFragments) { const importExtension = normalizeImportExtension({ emitLegacyCommonJSImports: this.config.emitLegacyCommonJSImports, importExtension: this.config.importExtension, }); const deduplicatedImports = Object.values(groupBy(this.config.fragmentImports, fi => fi.importSource.path)) .map( (fragmentImports): ImportDeclaration => ({ ...fragmentImports[0], importSource: { ...fragmentImports[0].importSource, identifiers: unique( flatten(fragmentImports.map(fi => fi.importSource.identifiers)), identifier => identifier.name ), }, emitLegacyCommonJSImports: this.config.emitLegacyCommonJSImports, importExtension, }) ) .filter(fragmentImport => fragmentImport.outputPath !== fragmentImport.importSource.path); for (const fragmentImport of deduplicatedImports) { this._imports.add(generateFragmentImportStatement(fragmentImport, 'document')); } } return Array.from(this._imports); } protected buildOperation( _node: OperationDefinitionNode, _documentVariableName: string, _operationType: string, _operationResultType: string, _operationVariablesTypes: string, _hasRequiredVariables: boolean ): string { return null; } protected getDocumentNodeSignature( _resultType: string, _variablesTypes: string, _node: FragmentDefinitionNode | OperationDefinitionNode ): string { if ( this.config.documentMode === DocumentMode.documentNode || this.config.documentMode === DocumentMode.documentNodeImportFragments ) { return ` as unknown as DocumentNode`; } return ''; } /** * Checks if the specific operation has variables that are non-null (required), and also doesn't have default. * This is useful for deciding of `variables` should be optional or not. * @param node */ protected checkVariablesRequirements(node: OperationDefinitionNode): boolean { const variables = node.variableDefinitions || []; if (variables.length === 0) { return false; } return variables.some(variableDef => variableDef.type.kind === Kind.NON_NULL_TYPE && !variableDef.defaultValue); } public getOperationVariableName(node: OperationDefinitionNode) { return this.convertName(node, { suffix: this.config.documentVariableSuffix, prefix: this.config.documentVariablePrefix, useTypesPrefix: false, }); } public OperationDefinition(node: OperationDefinitionNode): string { this._collectedOperations.push(node); const documentVariableName = this.getOperationVariableName(node); const operationType: string = pascalCase(node.operation); const operationTypeSuffix: string = this.getOperationSuffix(node, operationType); const operationResultType: string = this.convertName(node, { suffix: operationTypeSuffix + this._parsedConfig.operationResultSuffix, }); const operationVariablesTypes: string = this.convertName(node, { suffix: operationTypeSuffix + 'Variables', }); let documentString = ''; if ( this.config.documentMode !== DocumentMode.external && documentVariableName !== '' // only generate exports for named queries ) { documentString = `${this.config.noExport ? '' : 'export'} const ${documentVariableName} =${ this.config.pureMagicComment ? ' /*#__PURE__*/' : '' } ${this._gql(node)}${this.getDocumentNodeSignature(operationResultType, operationVariablesTypes, node)};`; } const hasRequiredVariables = this.checkVariablesRequirements(node); const additional = this.buildOperation( node, documentVariableName, operationType, operationResultType, operationVariablesTypes, hasRequiredVariables ); return [documentString, additional].filter(a => a).join('\n'); } } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/declaration-kinds.ts ================================================ import { DeclarationKind, DeclarationKindConfig } from './types.js'; export const DEFAULT_DECLARATION_KINDS: DeclarationKindConfig = { directive: 'type', scalar: 'type', input: 'type', type: 'type', interface: 'type', arguments: 'type', }; export function normalizeDeclarationKind( declarationKind?: DeclarationKind | DeclarationKindConfig ): DeclarationKindConfig { if (typeof declarationKind === 'string') { return { directive: declarationKind, scalar: declarationKind, input: declarationKind, type: declarationKind, interface: declarationKind, arguments: declarationKind, }; } return { ...DEFAULT_DECLARATION_KINDS, ...declarationKind, }; } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/enum-values.ts ================================================ import { GraphQLEnumType, GraphQLSchema, isEnumType } from 'graphql'; import { parseMapper } from './mappers.js'; import { EnumValuesMap, ParsedEnumValuesMap } from './types.js'; function escapeString(str: string) { return str.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/'/g, "\\'"); } export function parseEnumValues({ schema, mapOrStr = {}, ignoreEnumValuesFromSchema, }: { schema: GraphQLSchema; mapOrStr: EnumValuesMap; ignoreEnumValuesFromSchema?: boolean; }): ParsedEnumValuesMap { const allTypes = schema.getTypeMap(); const allEnums = Object.keys(allTypes).filter(t => isEnumType(allTypes[t])); if (typeof mapOrStr === 'object') { if (!ignoreEnumValuesFromSchema) { for (const enumTypeName of allEnums) { const enumType = schema.getType(enumTypeName) as GraphQLEnumType; for (const { name, value } of enumType.getValues()) { if (value !== name) { mapOrStr[enumTypeName] ||= {}; if (typeof mapOrStr[enumTypeName] !== 'string' && !mapOrStr[enumTypeName][name]) { mapOrStr[enumTypeName][name] = typeof value === 'string' ? escapeString(value) : value; } } } } } const invalidMappings = Object.keys(mapOrStr).filter(gqlName => !allEnums.includes(gqlName)); if (invalidMappings.length > 0) { throw new Error( `Invalid 'enumValues' mapping! \n The following types does not exist in your GraphQL schema: ${invalidMappings.join(', ')}` ); } return Object.keys(mapOrStr).reduce((prev, gqlIdentifier) => { const pointer = mapOrStr[gqlIdentifier]; if (typeof pointer === 'string') { const mapper = parseMapper(pointer, gqlIdentifier); return { ...prev, [gqlIdentifier]: { isDefault: mapper.isExternal && mapper.default, typeIdentifier: gqlIdentifier, sourceFile: mapper.isExternal ? mapper.source : null, sourceIdentifier: mapper.type, importIdentifier: mapper.isExternal ? mapper.import : null, mappedValues: null, }, }; } if (typeof pointer === 'object') { return { ...prev, [gqlIdentifier]: { isDefault: false, typeIdentifier: gqlIdentifier, sourceFile: null, sourceIdentifier: null, importIdentifier: null, mappedValues: pointer, }, }; } throw new Error( `Invalid "enumValues" configuration \n Enum "${gqlIdentifier}": expected string or object (with enum values mapping)` ); }, {} as ParsedEnumValuesMap); } if (typeof mapOrStr === 'string') { return allEnums .filter(enumName => !enumName.startsWith('__')) .reduce((prev, enumName) => { return { ...prev, [enumName]: { isDefault: false, typeIdentifier: enumName, sourceFile: mapOrStr, sourceIdentifier: enumName, importIdentifier: enumName, mappedValues: null, }, }; }, {} as ParsedEnumValuesMap); } return {}; } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/imports.ts ================================================ import { dirname, isAbsolute, join, relative, resolve } from 'path'; import parse from 'parse-filepath'; import { normalizeImportExtension } from '@graphql-codegen/plugin-helpers'; export type ImportDeclaration = { outputPath: string; importSource: ImportSource; baseOutputDir: string; baseDir: string; typesImport: boolean; emitLegacyCommonJSImports?: boolean; importExtension: '' | `.${string}`; }; export type ImportSource = { /** * Source path, relative to the `baseOutputDir` */ path: string; /** * Namespace to import source as */ namespace?: string; /** * Entity names to import */ identifiers?: T[]; }; export type FragmentImport = { name: string; kind: 'type' | 'document'; }; export function generateFragmentImportStatement( statement: ImportDeclaration, kind: 'type' | 'document' | 'both' ): string { const { importSource: fragmentImportSource, ...rest } = statement; const { identifiers, path, namespace } = fragmentImportSource; const importSource: ImportSource = { identifiers: identifiers .filter(fragmentImport => kind === 'both' || kind === fragmentImport.kind) .map(({ name }) => name), path, namespace, }; return generateImportStatement({ importSource, ...rest, typesImport: kind === 'type' ? statement.typesImport : false, }); } export function generateImportStatement(statement: ImportDeclaration): string { const { baseDir, importSource, outputPath, typesImport } = statement; const importPath = resolveImportPath(baseDir, outputPath, importSource.path); const importNames = importSource.identifiers?.length ? `{ ${Array.from(new Set(importSource.identifiers)).join(', ')} }` : '*'; const importExtension = importPath.startsWith('/') || importPath.startsWith('.') ? normalizeImportExtension({ emitLegacyCommonJSImports: statement.emitLegacyCommonJSImports, importExtension: statement.importExtension, }) : ''; const importAlias = importSource.namespace ? ` as ${importSource.namespace}` : ''; const importStatement = typesImport ? 'import type' : 'import'; return `${importStatement} ${importNames}${importAlias} from '${importPath}${importExtension}';${ importAlias ? '\n' : '' }`; // return `${importStatement} ${importNames}${importAlias} from '${importPath}';${importAlias ? '\n' : ''}`; } function resolveImportPath(baseDir: string, outputPath: string, sourcePath: string) { const shouldAbsolute = !sourcePath.startsWith('~'); if (shouldAbsolute) { const absGeneratedFilePath = resolve(baseDir, outputPath); const absImportFilePath = resolve(baseDir, sourcePath); return resolveRelativeImport(absGeneratedFilePath, absImportFilePath); } return sourcePath.replace(`~`, ''); } export function resolveRelativeImport(from: string, to: string): string { if (!isAbsolute(from)) { throw new Error(`Argument 'from' must be an absolute path, '${from}' given.`); } if (!isAbsolute(to)) { throw new Error(`Argument 'to' must be an absolute path, '${to}' given.`); } return fixLocalFilePath(clearExtension(relative(dirname(from), to))); } export function resolveImportSource(source: string | ImportSource): ImportSource { return typeof source === 'string' ? { path: source } : source; } export function clearExtension(path: string): string { const parsedPath = parse(path); return join(parsedPath.dir, parsedPath.name).replace(/\\/g, '/'); } export function fixLocalFilePath(path: string): string { return path.startsWith('..') ? path : `./${path}`; } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/index.ts ================================================ export * from './avoid-optionals.js'; export * from './base-documents-visitor.js'; export * from './base-resolvers-visitor.js'; export * from './base-types-visitor.js'; export * from './base-visitor.js'; export * from './client-side-base-visitor.js'; export * from './declaration-kinds.js'; export * from './enum-values.js'; export * from './imports.js'; export * from './mappers.js'; export * from './naming.js'; export * from './optimize-operations.js'; export * from './scalars.js'; export * from './selection-set-processor/base.js'; export * from './selection-set-processor/pre-resolve-types.js'; export * from './selection-set-to-object.js'; export * from './types.js'; export * from './utils.js'; export * from './variables-to-object.js'; ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/mappers.ts ================================================ import { ParsedResolversConfig, RawResolversConfig } from './base-resolvers-visitor.js'; import { DirectiveArgumentAndInputFieldMappings, ParsedDirectiveArgumentAndInputFieldMappings } from './types.js'; export type ParsedMapper = InternalParsedMapper | ExternalParsedMapper; export interface InternalParsedMapper { isExternal: false; type: string; } export interface ExternalParsedMapper { isExternal: true; type: string; import: string; source: string; default: boolean; } export function isExternalMapperType(m: ParsedMapper): m is ExternalParsedMapper { return !!(m as ExternalParsedMapper).import; } enum MapperKind { Namespace, Default, Regular, } interface Helpers { items: string[]; isNamespace: boolean; isDefault: boolean; hasAlias: boolean; } function prepareLegacy(mapper: string): Helpers { const isScoped = mapper.includes('\\#'); if (mapper.includes('\\#')) { mapper = mapper.replace('\\#', ''); } const items = mapper.split('#'); const isNamespace = items.length === 3; const isDefault = items[1].trim() === 'default' || items[1].startsWith('default '); const hasAlias = items[1].includes(' as '); const source = isScoped ? `#${items[0]}` : items[0]; items[0] = source; return { items, isDefault, isNamespace, hasAlias, }; } function prepare(mapper: string): Helpers { const isScoped = mapper.includes('\\#'); if (mapper.includes('\\#')) { mapper = mapper.replace('\\#', ''); } let [source, path] = mapper.split('#'); const isNamespace = path.includes('.'); const isDefault = path.trim() === 'default' || path.startsWith('default '); const hasAlias = path.includes(' as '); source = isScoped ? `#${source}` : source; return { items: isNamespace ? [source, ...path.split('.')] : [source, path], isDefault, isNamespace, hasAlias, }; } function isLegacyMode(mapper: string) { if (mapper.includes('\\#')) { mapper = mapper.replace('\\#', ''); } return mapper.split('#').length === 3; } export function parseMapper(mapper: string, gqlTypeName: string | null = null, suffix?: string): ParsedMapper { if (isExternalMapper(mapper)) { const { isNamespace, isDefault, hasAlias, items } = isLegacyMode(mapper) ? prepareLegacy(mapper) : prepare(mapper); const mapperKind: MapperKind = isNamespace ? MapperKind.Namespace : isDefault ? MapperKind.Default : MapperKind.Regular; function handleAlias(isDefault = false) { const [importedType, aliasType] = items[1].split(/\s+as\s+/); const type = maybeSuffix(aliasType); return { importElement: isDefault ? type : `${importedType} as ${type}`, type, }; } function maybeSuffix(type: string) { if (suffix) { return addSuffix(type, suffix); } return type; } function handle(): { importElement: string; type: string; } { switch (mapperKind) { // ./my/module#Namespace#Identifier case MapperKind.Namespace: { const [, ns, identifier] = items; return { type: `${ns}.${identifier}`, importElement: ns, }; } case MapperKind.Default: { // ./my/module#default as alias if (hasAlias) { return handleAlias(true); } const type = maybeSuffix(String(gqlTypeName)); // ./my/module#default return { importElement: type, type, }; } case MapperKind.Regular: { // ./my/module#Identifier as alias if (hasAlias) { return handleAlias(); } const identifier = items[1]; const type = maybeSuffix(identifier); // ./my/module#Identifier return { type, importElement: suffix ? `${identifier} as ${type}` : type, }; } } } const { type, importElement } = handle(); return { default: isDefault, isExternal: true, source: items[0], type, import: importElement.replace(/<(.*?)>/g, ''), }; } return { isExternal: false, type: mapper, }; } function addSuffix(element: string, suffix: string): string { const generic = element.indexOf('<'); if (generic === -1) { return `${element}${suffix}`; } return `${element.slice(0, generic)}${suffix}${element.slice(generic)}`; } export function isExternalMapper(value: string): boolean { return value.includes('#'); } export function transformMappers( rawMappers: RawResolversConfig['mappers'], mapperTypeSuffix?: string ): ParsedResolversConfig['mappers'] { const result: ParsedResolversConfig['mappers'] = {}; for (const gqlTypeName of Object.keys(rawMappers)) { const mapperDef = rawMappers[gqlTypeName]; const parsedMapper = parseMapper(mapperDef, gqlTypeName, mapperTypeSuffix); result[gqlTypeName] = parsedMapper; } return result; } export function transformDirectiveArgumentAndInputFieldMappings( rawDirectiveArgumentAndInputFieldMappings: DirectiveArgumentAndInputFieldMappings, directiveArgumentAndInputFieldMappingTypeSuffix?: string ): ParsedDirectiveArgumentAndInputFieldMappings { const result: ParsedDirectiveArgumentAndInputFieldMappings = {}; for (const directive of Object.keys(rawDirectiveArgumentAndInputFieldMappings)) { const mapperDef = rawDirectiveArgumentAndInputFieldMappings[directive]; const parsedMapper = parseMapper(mapperDef, directive, directiveArgumentAndInputFieldMappingTypeSuffix); result[directive] = parsedMapper; } return result; } export function buildMapperImport( source: string, types: { identifier: string; asDefault?: boolean }[], useTypeImports: boolean ): string | null { if (!types || types.length === 0) { return null; } const defaultType = types.find(t => t.asDefault === true); let namedTypes = types.filter(t => !t.asDefault); if (useTypeImports) { if (defaultType) { // default as Baz namedTypes = [{ identifier: `default as ${defaultType.identifier}` }, ...namedTypes]; } // { Foo, Bar as BarModel } const namedImports = namedTypes.length ? `{ ${namedTypes.map(t => t.identifier).join(', ')} }` : ''; // { default as Baz, Foo, Bar as BarModel } return `import type ${[namedImports].filter(Boolean).join(', ')} from '${source}';`; } // { Foo, Bar as BarModel } const namedImports = namedTypes.length ? `{ ${namedTypes.map(t => t.identifier).join(', ')} }` : ''; // Baz const defaultImport = defaultType ? defaultType.identifier : ''; // Baz, { Foo, Bar as BarModel } return `import ${[defaultImport, namedImports].filter(Boolean).join(', ')} from '${source}';`; } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/naming.ts ================================================ import { resolveExternalModuleAndFn } from '@graphql-codegen/plugin-helpers'; import { pascalCase } from 'change-case-all'; import { ASTNode } from 'graphql'; import { ConvertFn, ConvertOptions, NamingConvention, NamingConventionMap } from './types.js'; import { convertNameParts, getConfigValue } from './utils.js'; function getKind(node: ASTNode | string): keyof NamingConventionMap { if (typeof node === 'string') { return 'typeNames'; } if (['EnumValueDefinition', 'EnumValue'].includes(node.kind)) { return 'enumValues'; } return 'typeNames'; } function getName(node: ASTNode | string): string | undefined { if (node == null) { return undefined; } if (typeof node === 'string') { return node; } switch (node.kind) { case 'OperationDefinition': case 'Variable': case 'Argument': case 'FragmentSpread': case 'FragmentDefinition': case 'ObjectField': case 'Directive': case 'NamedType': case 'ScalarTypeDefinition': case 'ObjectTypeDefinition': case 'FieldDefinition': case 'InputValueDefinition': case 'InterfaceTypeDefinition': case 'UnionTypeDefinition': case 'EnumTypeDefinition': case 'EnumValueDefinition': case 'InputObjectTypeDefinition': case 'DirectiveDefinition': { return getName(node.name); } case 'Name': { return node.value; } case 'Field': { return getName(node.alias || node.name); } case 'VariableDefinition': { return getName(node.variable); } } return undefined; } export function convertFactory(config: { namingConvention?: NamingConvention }): ConvertFn { function resolveConventionName(type: keyof NamingConventionMap): (str: string, opts?: ConvertOptions) => string { if (!config.namingConvention) { return (str: string, opts: ConvertOptions = {}) => { return convertNameParts(str, pascalCase, getConfigValue(opts?.transformUnderscore, false)); }; } if (typeof config.namingConvention === 'string') { if (config.namingConvention === 'keep') { return str => str; } return (str: string, opts: ConvertOptions = {}) => { return convertNameParts( str, resolveExternalModuleAndFn(config.namingConvention), getConfigValue(opts?.transformUnderscore, false) ); }; } if (typeof config.namingConvention === 'function') { return (str: string, opts: ConvertOptions = {}) => { return convertNameParts( str, config.namingConvention as (str: string) => string, getConfigValue(opts?.transformUnderscore, false) ); }; } if (typeof config.namingConvention === 'object' && config.namingConvention[type] === 'keep') { return str => str; } if (typeof config.namingConvention === 'object') { if (!config.namingConvention[type]) { return (str: string, opts: ConvertOptions = {}) => { const transformUnderscore = (config.namingConvention as NamingConventionMap).transformUnderscore || opts?.transformUnderscore; return convertNameParts(str, pascalCase, getConfigValue(transformUnderscore, false)); }; } return (str: string, opts: ConvertOptions = {}) => { return convertNameParts( str, resolveExternalModuleAndFn(config.namingConvention[type]), getConfigValue(opts?.transformUnderscore, true) ); }; } return config.namingConvention[type] as any; } return (node, opts) => { const prefix = opts?.prefix; const suffix = opts?.suffix; const kind = getKind(node); const str = [prefix || '', getName(node), suffix || ''].join(''); return resolveConventionName(kind)(str, opts); }; } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/optimize-operations.ts ================================================ import { Types } from '@graphql-codegen/plugin-helpers'; import { optimizeDocuments } from '@graphql-tools/relay-operation-optimizer'; import { GraphQLSchema } from 'graphql'; export function optimizeOperations( schema: GraphQLSchema, documents: Types.DocumentFile[], options?: { includeFragments: boolean } ): Types.DocumentFile[] { const newDocuments = optimizeDocuments( schema, documents.map(s => s.document), options ); return newDocuments.map((document, index) => ({ location: documents[index]?.location || 'optimized by relay', document, })); } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/scalars.ts ================================================ import { NormalizedScalarsMap } from './types.js'; export const DEFAULT_SCALARS: NormalizedScalarsMap = { ID: { input: 'string', output: 'string', }, String: { input: 'string', output: 'string', }, Boolean: { input: 'boolean', output: 'boolean', }, Int: { input: 'number', output: 'number', }, Float: { input: 'number', output: 'number', }, }; ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/selection-set-processor/base.ts ================================================ import { GraphQLInterfaceType, GraphQLNamedType, GraphQLObjectType, GraphQLOutputType, Location } from 'graphql'; import { AvoidOptionalsConfig, ConvertNameFn, NormalizedScalarsMap } from '../types.js'; export type PrimitiveField = { isConditional: boolean; fieldName: string }; export type PrimitiveAliasedFields = { isConditional: boolean; alias: string; fieldName: string }; export type LinkField = { alias: string; name: string; type: string; selectionSet: string }; export type NameAndType = { name: string; type: string }; export type ProcessResult = null | Array; export type SelectionSetProcessorConfig = { namespacedImportName: string | null; convertName: ConvertNameFn; enumPrefix: boolean | null; enumSuffix: boolean | null; scalars: NormalizedScalarsMap; formatNamedField( name: string, type?: GraphQLOutputType | GraphQLNamedType | null, isConditional?: boolean, isOptional?: boolean ): string; wrapTypeWithModifiers(baseType: string, type: GraphQLOutputType | GraphQLNamedType): string; avoidOptionals?: AvoidOptionalsConfig | boolean; printFieldsOnNewLines?: boolean; }; export class BaseSelectionSetProcessor { typeCache = new Map>(); constructor(public config: Config) {} buildFieldsIntoObject(allObjectsMerged: string[]): string { if (this.config.printFieldsOnNewLines) { return `{\n ${allObjectsMerged.join(',\n ')}\n}`; } return `{ ${allObjectsMerged.join(', ')} }`; } buildSelectionSetFromStrings(pieces: string[]): string { if (pieces.length === 0) { return null; } if (pieces.length === 1) { return pieces[0]; } return `(\n ${pieces.join(`\n & `)}\n)`; } transformPrimitiveFields( _schemaType: GraphQLObjectType | GraphQLInterfaceType, _fields: PrimitiveField[], _unsetTypes?: boolean ): ProcessResult { throw new Error( `Please override "transformPrimitiveFields" as part of your BaseSelectionSetProcessor implementation!` ); } transformAliasesPrimitiveFields( _schemaType: GraphQLObjectType | GraphQLInterfaceType, _fields: PrimitiveAliasedFields[], _unsetTypes?: boolean ): ProcessResult { throw new Error( `Please override "transformAliasesPrimitiveFields" as part of your BaseSelectionSetProcessor implementation!` ); } transformLinkFields(_fields: LinkField[], _unsetTypes?: boolean): ProcessResult { throw new Error(`Please override "transformLinkFields" as part of your BaseSelectionSetProcessor implementation!`); } transformTypenameField(_type: string, _name: string): ProcessResult { throw new Error( `Please override "transformTypenameField" as part of your BaseSelectionSetProcessor implementation!` ); } } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/selection-set-processor/pre-resolve-types.ts ================================================ import { getBaseType, removeNonNullWrapper } from '@graphql-codegen/plugin-helpers'; import { GraphQLInterfaceType, GraphQLObjectType, isEnumType, isNonNullType } from 'graphql'; import { BaseSelectionSetProcessor, LinkField, PrimitiveAliasedFields, PrimitiveField, ProcessResult, SelectionSetProcessorConfig, } from './base.js'; export class PreResolveTypesProcessor extends BaseSelectionSetProcessor { transformTypenameField(type: string, name: string): ProcessResult { return [ { type, name, }, ]; } transformPrimitiveFields( schemaType: GraphQLObjectType | GraphQLInterfaceType, fields: PrimitiveField[], unsetTypes?: boolean ): ProcessResult { if (fields.length === 0) { return []; } return fields.map(field => { const fieldObj = schemaType.getFields()[field.fieldName]; const baseType = getBaseType(fieldObj.type); let typeToUse = baseType.name; const useInnerType = field.isConditional && isNonNullType(fieldObj.type); const innerType = useInnerType ? removeNonNullWrapper(fieldObj.type) : undefined; const name = this.config.formatNamedField( field.fieldName, useInnerType ? innerType : fieldObj.type, field.isConditional, unsetTypes ); if (unsetTypes) { return { name, type: 'never', }; } if (isEnumType(baseType)) { typeToUse = (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') + this.config.convertName(baseType.name, { useTypesPrefix: this.config.enumPrefix, useTypesSuffix: this.config.enumSuffix, }); } else if (this.config.scalars[baseType.name]) { typeToUse = this.config.scalars[baseType.name].output; } const wrappedType = this.config.wrapTypeWithModifiers(typeToUse, fieldObj.type); return { name, type: wrappedType, }; }); } transformAliasesPrimitiveFields( schemaType: GraphQLObjectType | GraphQLInterfaceType, fields: PrimitiveAliasedFields[], unsetTypes?: boolean ): ProcessResult { if (fields.length === 0) { return []; } return fields.map(aliasedField => { if (aliasedField.fieldName === '__typename') { const name = this.config.formatNamedField(aliasedField.alias, null); return { name, type: `'${schemaType.name}'`, }; } const fieldObj = schemaType.getFields()[aliasedField.fieldName]; const baseType = getBaseType(fieldObj.type); let typeToUse = this.config.scalars[baseType.name]?.output || baseType.name; if (isEnumType(baseType)) { typeToUse = (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') + this.config.convertName(baseType.name, { useTypesPrefix: this.config.enumPrefix, useTypesSuffix: this.config.enumSuffix, }); } const name = this.config.formatNamedField( aliasedField.alias, fieldObj.type, aliasedField.isConditional, unsetTypes ); if (unsetTypes) { return { type: 'never', name, }; } const wrappedType = this.config.wrapTypeWithModifiers(typeToUse, fieldObj.type); return { name, type: wrappedType, }; }); } transformLinkFields(fields: LinkField[], unsetTypes?: boolean): ProcessResult { if (fields.length === 0) { return []; } return fields.map(field => ({ name: field.alias || field.name, type: unsetTypes ? 'never' : field.selectionSet, })); } } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/selection-set-to-object.ts ================================================ import { createHash } from 'crypto'; import { getBaseType } from '@graphql-codegen/plugin-helpers'; import { getRootTypes } from '@graphql-tools/utils'; import autoBind from 'auto-bind'; import { DirectiveNode, FieldNode, FragmentSpreadNode, GraphQLField, GraphQLNamedType, GraphQLObjectType, GraphQLOutputType, GraphQLSchema, InlineFragmentNode, isInterfaceType, isListType, isNonNullType, isObjectType, isTypeSubTypeOf, isUnionType, Kind, SchemaMetaFieldDef, SelectionNode, SelectionSetNode, TypeMetaFieldDef, } from 'graphql'; import { ParsedDocumentsConfig } from './base-documents-visitor.js'; import { BaseVisitorConvertOptions } from './base-visitor.js'; import { BaseSelectionSetProcessor, LinkField, NameAndType, PrimitiveAliasedFields, PrimitiveField, ProcessResult, } from './selection-set-processor/base.js'; import { ConvertNameFn, FragmentDirectives, GetFragmentSuffixFn, LoadedFragment, NormalizedScalarsMap, } from './types.js'; import { DeclarationBlock, DeclarationBlockConfig, getFieldNames, getFieldNodeNameValue, getPossibleTypes, hasConditionalDirectives, hasIncrementalDeliveryDirectives, mergeSelectionSets, separateSelectionSet, } from './utils.js'; type FragmentSpreadUsage = { fragmentName: string; typeName: string; onType: string; selectionNodes: Array; fragmentDirectives?: DirectiveNode[]; }; interface DependentType { name: string; content: string; isUnionType?: boolean; } type CollectedFragmentNode = (SelectionNode | FragmentSpreadUsage | DirectiveNode) & FragmentDirectives; type GroupedStringifiedTypes = Record>; const operationTypes: string[] = ['Query', 'Mutation', 'Subscription']; function isMetadataFieldName(name: string) { return ['__schema', '__type'].includes(name); } const metadataFieldMap: Record> = { __schema: SchemaMetaFieldDef, __type: TypeMetaFieldDef, }; export class SelectionSetToObject { protected _primitiveFields: PrimitiveField[] = []; protected _primitiveAliasedFields: PrimitiveAliasedFields[] = []; protected _linksFields: LinkField[] = []; protected _queriedForTypename = false; constructor( protected _processor: BaseSelectionSetProcessor, protected _scalars: NormalizedScalarsMap, protected _schema: GraphQLSchema, protected _convertName: ConvertNameFn, protected _getFragmentSuffix: GetFragmentSuffixFn, protected _loadedFragments: LoadedFragment[], protected _config: Config, protected _parentSchemaType?: GraphQLNamedType, protected _selectionSet?: SelectionSetNode ) { autoBind(this); } public createNext(parentSchemaType: GraphQLNamedType, selectionSet: SelectionSetNode): SelectionSetToObject { return new SelectionSetToObject( this._processor, this._scalars, this._schema, this._convertName.bind(this), this._getFragmentSuffix.bind(this), this._loadedFragments, this._config, parentSchemaType, selectionSet ); } /** * traverse the inline fragment nodes recursively for collecting the selectionSets on each type */ _collectInlineFragments( parentType: GraphQLNamedType, nodes: Array, types: Map> ) { if (isListType(parentType) || isNonNullType(parentType)) { return this._collectInlineFragments(parentType.ofType as GraphQLNamedType, nodes, types); } if (isObjectType(parentType)) { for (const node of nodes) { const typeOnSchema = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType; const { fields, inlines, spreads } = separateSelectionSet(node.selectionSet.selections); const spreadsUsage = this.buildFragmentSpreadsUsage(spreads); const directives = (node.directives as DirectiveNode[]) || undefined; // When we collect the selection sets of inline fragments we need to // make sure directives on the inline fragments are stored in a way // that can be associated back to the fields in the fragment, to // support things like making those fields optional when deferring a // fragment (using @defer). const fieldsWithFragmentDirectives: CollectedFragmentNode[] = fields.map(field => ({ ...field, fragmentDirectives: field.fragmentDirectives || directives, })); if (isObjectType(typeOnSchema)) { this._appendToTypeMap(types, typeOnSchema.name, fieldsWithFragmentDirectives); this._appendToTypeMap(types, typeOnSchema.name, spreadsUsage[typeOnSchema.name]); this._appendToTypeMap(types, typeOnSchema.name, directives); this._collectInlineFragments(typeOnSchema, inlines, types); } else if (isInterfaceType(typeOnSchema) && parentType.getInterfaces().includes(typeOnSchema)) { this._appendToTypeMap(types, parentType.name, fields); this._appendToTypeMap(types, parentType.name, spreadsUsage[parentType.name]); this._collectInlineFragments(typeOnSchema, inlines, types); } } } else if (isInterfaceType(parentType)) { const possibleTypes = getPossibleTypes(this._schema, parentType); for (const node of nodes) { const schemaType = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType; const { fields, inlines, spreads } = separateSelectionSet(node.selectionSet.selections); const spreadsUsage = this.buildFragmentSpreadsUsage(spreads); if (isObjectType(schemaType) && possibleTypes.find(possibleType => possibleType.name === schemaType.name)) { this._appendToTypeMap(types, schemaType.name, fields); this._appendToTypeMap(types, schemaType.name, spreadsUsage[schemaType.name]); this._collectInlineFragments(schemaType, inlines, types); } else if (isInterfaceType(schemaType) && schemaType.name === parentType.name) { for (const possibleType of possibleTypes) { this._appendToTypeMap(types, possibleType.name, fields); this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]); this._collectInlineFragments(schemaType, inlines, types); } } else { // it must be an interface type that is spread on an interface field for (const possibleType of possibleTypes) { if (!node.typeCondition) { throw new Error('Invalid state. Expected type condition for interface spread on a interface field.'); } const fragmentSpreadType = this._schema.getType(node.typeCondition.name.value); // the field should only be added to the valid selections // in case the possible type actually implements the given interface if (isTypeSubTypeOf(this._schema, possibleType, fragmentSpreadType)) { this._appendToTypeMap(types, possibleType.name, fields); this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]); } } } } } else if (isUnionType(parentType)) { const possibleTypes = parentType.getTypes(); for (const node of nodes) { const schemaType = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType; const { fields, inlines, spreads } = separateSelectionSet(node.selectionSet.selections); const spreadsUsage = this.buildFragmentSpreadsUsage(spreads); if (isObjectType(schemaType) && possibleTypes.find(possibleType => possibleType.name === schemaType.name)) { this._appendToTypeMap(types, schemaType.name, fields); this._appendToTypeMap(types, schemaType.name, spreadsUsage[schemaType.name]); this._collectInlineFragments(schemaType, inlines, types); } else if (isInterfaceType(schemaType)) { const possibleInterfaceTypes = getPossibleTypes(this._schema, schemaType); for (const possibleType of possibleTypes) { if ( possibleInterfaceTypes.find(possibleInterfaceType => possibleInterfaceType.name === possibleType.name) ) { this._appendToTypeMap(types, possibleType.name, fields); this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]); this._collectInlineFragments(schemaType, inlines, types); } } } else { for (const possibleType of possibleTypes) { this._appendToTypeMap(types, possibleType.name, fields); this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]); } } } } } protected _createInlineFragmentForFieldNodes( parentType: GraphQLNamedType, fieldNodes: FieldNode[] ): InlineFragmentNode { return { kind: Kind.INLINE_FRAGMENT, typeCondition: { kind: Kind.NAMED_TYPE, name: { kind: Kind.NAME, value: parentType.name, }, }, directives: [], selectionSet: { kind: Kind.SELECTION_SET, selections: fieldNodes, }, }; } /** * The `buildFragmentSpreadsUsage` method is used to collect fields from fragment spreads in the selection set. * It creates a record of fragment spread usages, which includes the fragment name, type name, and the selection nodes * inside the fragment. */ protected buildFragmentSpreadsUsage(spreads: FragmentSpreadNode[]): Record { const selectionNodesByTypeName: Record = {}; for (const spread of spreads) { const fragmentSpreadObject = this._loadedFragments.find(lf => lf.name === spread.name.value); if (fragmentSpreadObject) { const schemaType = this._schema.getType(fragmentSpreadObject.onType); const possibleTypesForFragment = getPossibleTypes(this._schema, schemaType); for (const possibleType of possibleTypesForFragment) { const fragmentSuffix = this._getFragmentSuffix(spread.name.value); const usage = this.buildFragmentTypeName( spread.name.value, fragmentSuffix, possibleTypesForFragment.length === 1 ? null : possibleType.name ); selectionNodesByTypeName[possibleType.name] ||= []; selectionNodesByTypeName[possibleType.name].push({ fragmentName: spread.name.value, typeName: usage, onType: fragmentSpreadObject.onType, selectionNodes: [...fragmentSpreadObject.node.selectionSet.selections], fragmentDirectives: [...spread.directives], }); } } } return selectionNodesByTypeName; } protected flattenSelectionSet( selections: ReadonlyArray, parentSchemaType?: GraphQLObjectType ): Map> { const selectionNodesByTypeName = new Map>(); const inlineFragmentSelections: InlineFragmentNode[] = []; const fieldNodes: FieldNode[] = []; const fragmentSpreads: FragmentSpreadNode[] = []; for (const selection of selections) { switch (selection.kind) { case Kind.FIELD: fieldNodes.push(selection); break; case Kind.INLINE_FRAGMENT: inlineFragmentSelections.push(selection); break; case Kind.FRAGMENT_SPREAD: fragmentSpreads.push(selection); break; } } if (fieldNodes.length) { inlineFragmentSelections.push( this._createInlineFragmentForFieldNodes(parentSchemaType ?? this._parentSchemaType, fieldNodes) ); } this._collectInlineFragments( parentSchemaType ?? this._parentSchemaType, inlineFragmentSelections, selectionNodesByTypeName ); const fragmentsUsage = this.buildFragmentSpreadsUsage(fragmentSpreads); for (const [typeName, records] of Object.entries(fragmentsUsage)) { this._appendToTypeMap(selectionNodesByTypeName, typeName, records); } return selectionNodesByTypeName; } private _appendToTypeMap( types: Map>, typeName: string, nodes: Array ): void { if (!types.has(typeName)) { types.set(typeName, []); } if (nodes && nodes.length > 0) { types.get(typeName).push(...nodes); } } protected _buildGroupedSelections(parentName: string): { grouped: GroupedStringifiedTypes; dependentTypes: DependentType[]; mustAddEmptyObject: boolean; } { if (!this._selectionSet?.selections || this._selectionSet.selections.length === 0) { return { grouped: {}, mustAddEmptyObject: true, dependentTypes: [] }; } const selectionNodesByTypeName = this.flattenSelectionSet(this._selectionSet.selections); // in case there is not a selection for each type, we need to add a empty type. let mustAddEmptyObject = false; const possibleTypes = getPossibleTypes(this._schema, this._parentSchemaType); const dependentTypes: DependentType[] = []; if (!this._config.mergeFragmentTypes || this._config.inlineFragmentTypes === 'mask') { const grouped = possibleTypes.reduce((prev, type) => { const typeName = type.name; const schemaType = this._schema.getType(typeName); if (!isObjectType(schemaType)) { throw new TypeError(`Invalid state! Schema type ${typeName} is not a valid GraphQL object!`); } const allNodes = selectionNodesByTypeName.get(typeName) || []; prev[typeName] ||= []; // incrementalNodes are the ones flagged with @defer, meaning they become nullable const { incrementalNodes, selectionNodes, fragmentSpreads } = allNodes.reduce<{ selectionNodes: (SelectionNode | FragmentSpreadUsage)[]; incrementalNodes: FragmentSpreadUsage[]; fragmentSpreads: string[]; }>( (acc, node) => { if ('fragmentDirectives' in node && hasIncrementalDeliveryDirectives(node.fragmentDirectives)) { acc.incrementalNodes.push(node); } else { acc.selectionNodes.push(node); } return acc; }, { selectionNodes: [], incrementalNodes: [], fragmentSpreads: [] } ); const { fields, dependentTypes: subDependentTypes } = this.buildSelectionSet(schemaType, selectionNodes, { parentFieldName: this.buildParentFieldName(typeName, parentName), }); const transformedSet = this.selectionSetStringFromFields(fields); if (transformedSet) { prev[typeName].push(transformedSet); } dependentTypes.push(...subDependentTypes); if (!transformedSet && !fragmentSpreads.length) { mustAddEmptyObject = true; } for (const incrementalNode of incrementalNodes) { if (this._config.inlineFragmentTypes === 'mask' && 'fragmentName' in incrementalNode) { const { fields: incrementalFields, dependentTypes: incrementalDependentTypes } = this.buildSelectionSet( schemaType, [incrementalNode], { unsetTypes: true, parentFieldName: parentName } ); const incrementalSet = this.selectionSetStringFromFields(incrementalFields); prev[typeName].push(incrementalSet); dependentTypes.push(...incrementalDependentTypes); continue; } const { fields: initialFields, dependentTypes: initialDependentTypes } = this.buildSelectionSet( schemaType, [incrementalNode], { parentFieldName: parentName } ); const { fields: subsequentFields, dependentTypes: subsequentDependentTypes } = this.buildSelectionSet( schemaType, [incrementalNode], { unsetTypes: true, parentFieldName: parentName } ); const initialSet = this.selectionSetStringFromFields(initialFields); const subsequentSet = this.selectionSetStringFromFields(subsequentFields); dependentTypes.push(...initialDependentTypes, ...subsequentDependentTypes); prev[typeName].push({ union: [initialSet, subsequentSet] }); } return prev; }, {}); return { grouped, mustAddEmptyObject, dependentTypes }; } // Accumulate a map of selected fields to the typenames that // share the exact same selected fields. When we find multiple // typenames with the same set of fields, we can collapse the // generated type to the selected fields and a string literal // union of the typenames. // // E.g. { // __typename: "foo" | "bar"; // shared: string; // } const grouped = possibleTypes.reduce< Record >((prev, type) => { const typeName = type.name; const schemaType = this._schema.getType(typeName); if (!isObjectType(schemaType)) { throw new TypeError(`Invalid state! Schema type ${typeName} is not a valid GraphQL object!`); } const selectionNodes = selectionNodesByTypeName.get(typeName) || []; const { typeInfo, fields, dependentTypes: subDependentTypes, } = this.buildSelectionSet(schemaType, selectionNodes, { parentFieldName: this.buildParentFieldName(typeName, parentName), }); dependentTypes.push(...subDependentTypes); const key = this.selectionSetStringFromFields(fields); prev[key] = { fields, types: [...(prev[key]?.types ?? []), typeInfo || { name: '', type: type.name }].filter(Boolean), }; return prev; }, {}); // For every distinct set of fields, create the corresponding // string literal union of typenames. const compacted = Object.keys(grouped).reduce>((acc, key) => { const typeNames = grouped[key].types.map(t => t.type); // Don't create very large string literal unions. TypeScript // will stop comparing some nested union types types when // they contain props with more than some number of string // literal union members (testing with TS 4.5 stops working // at 25 for a naive test case: // https://www.typescriptlang.org/play?ts=4.5.4&ssl=29&ssc=10&pln=29&pc=1#code/C4TwDgpgBAKg9nAMgQwE4HNoF4BQV9QA+UA3ngRQJYB21EqAXDsQEQCMLzULATJ6wGZ+3ACzCWAVnEA2cQHZxADnEBOcWwAM6jl3Z9dbIQbEGpB2QYUHlBtbp5b7O1j30ujLky7Os4wABb0nAC+ODigkFAAQlBYUOT4xGQUVLT0TKzO3G7cHqLiPtwWrFasNqx2mY6ZWXrqeexe3GyF7MXNpc3lzZXZ1dm1ruI8DTxNvGahFEkJKTR0jLMpRNx+gaicy6E4APQ7AALAAM4AtJTo1HCoEDgANhDAUMgMsAgoGNikwQDcdw9QACMXjE4shfmEItAAGI0bCzGbLfDzdIGYbiBrjVrtFidFjdFi9dj9di1Ng5dgNNjjFrqbFsXFsfFsQkOYaDckjYbjNZBHDbPaHU7nS7XP6PZBsF4wuixL6-e6PAGS6KyiXfIA const max_types = 20; for (let i = 0; i < typeNames.length; i += max_types) { const selectedTypes = typeNames.slice(i, i + max_types); const typenameUnion = grouped[key].types[0].name ? this._processor.transformTypenameField(selectedTypes.join(' | '), grouped[key].types[0].name) : []; const transformedSet = this.selectionSetStringFromFields([...typenameUnion, ...grouped[key].fields]); // The keys here will be used to generate intermediary // fragment names. To avoid blowing up the type name on large // unions, calculate a stable hash here instead. // // Also use fragment hashing if skipTypename is true, since we // then don't have a typename for naming the fragment. acc[ selectedTypes.length <= 3 ? // Remove quote marks to produce a valid type name selectedTypes.map(t => t.replace(/'/g, '')).join('_') : createHash('sha256') .update(selectedTypes.join() || transformedSet || '') // Remove invalid characters to produce a valid type name .digest('base64') .replace(/[=+/]/g, '') ] = [transformedSet]; } return acc; }, {}); return { grouped: compacted, mustAddEmptyObject, dependentTypes }; } protected selectionSetStringFromFields(fields: (string | NameAndType)[]): string | null { const allStrings = fields.filter((f: string | NameAndType): f is string => typeof f === 'string'); const allObjects = fields .filter((f: string | NameAndType): f is NameAndType => typeof f !== 'string') .map(t => `${t.name}: ${t.type}`); const mergedObjects = allObjects.length ? this._processor.buildFieldsIntoObject(allObjects) : null; const transformedSet = this._processor.buildSelectionSetFromStrings([...allStrings, mergedObjects].filter(Boolean)); return transformedSet; } protected buildSelectionSet( parentSchemaType: GraphQLObjectType, selectionNodes: Array, options: { unsetTypes?: boolean; parentFieldName?: string } ) { const primitiveFields = new Map(); const primitiveAliasFields = new Map(); const linkFieldSelectionSets = new Map< string, { selectedFieldType: GraphQLOutputType; field: FieldNode; } >(); let requireTypename = false; // usages via fragment typescript type const fragmentsSpreadUsages: string[] = []; // ensure we mutate no function params selectionNodes = [...selectionNodes]; let inlineFragmentConditional = false; for (const selectionNode of selectionNodes) { // 1. Handle Field or Directtives selection nodes if ('kind' in selectionNode) { if (selectionNode.kind === 'Field') { if (selectionNode.selectionSet) { let selectedField: GraphQLField = null; const fields = parentSchemaType.getFields(); selectedField = fields[selectionNode.name.value]; if (isMetadataFieldName(selectionNode.name.value)) { selectedField = metadataFieldMap[selectionNode.name.value]; } if (!selectedField) { continue; } const fieldName = getFieldNodeNameValue(selectionNode); let linkFieldNode = linkFieldSelectionSets.get(fieldName); if (linkFieldNode) { linkFieldNode = { ...linkFieldNode, field: { ...linkFieldNode.field, selectionSet: mergeSelectionSets(linkFieldNode.field.selectionSet, selectionNode.selectionSet), }, }; } else { linkFieldNode = { selectedFieldType: selectedField.type, field: selectionNode, }; } linkFieldSelectionSets.set(fieldName, linkFieldNode); } else if (selectionNode.alias) { primitiveAliasFields.set(selectionNode.alias.value, selectionNode); } else if (selectionNode.name.value === '__typename') { requireTypename = true; } else { primitiveFields.set(selectionNode.name.value, selectionNode); } } else if (selectionNode.kind === 'Directive') { if (['skip', 'include'].includes(selectionNode?.name?.value)) { inlineFragmentConditional = true; } } else { throw new TypeError('Unexpected type.'); } continue; } // 2. Handle Fragment Spread nodes // A Fragment Spread can be: // - masked: the fields declared in the Fragment do not appear in the operation types // - inline: the fields declared in the Fragment appear in the operation types // 2a. If `inlineFragmentTypes` is 'combine' or 'mask', the Fragment Spread is masked by default // In some cases, a masked node could be unmasked (i.e. treated as inline): // - Fragment spread node is marked with Apollo `@unmask`, e.g. `...User @unmask` if (this._config.inlineFragmentTypes === 'combine' || this._config.inlineFragmentTypes === 'mask') { let isMasked = true; if ( this._config.customDirectives.apolloUnmask && selectionNode.fragmentDirectives.some(d => d.name.value === 'unmask') ) { isMasked = false; } if (isMasked) { fragmentsSpreadUsages.push(selectionNode.typeName); continue; } } // 2b. If the Fragment Spread is not masked, generate inline types. const fragmentType = this._schema.getType(selectionNode.onType); if (fragmentType == null) { throw new TypeError(`Unexpected error: Type ${selectionNode.onType} does not exist within schema.`); } if ( parentSchemaType.name === selectionNode.onType || parentSchemaType.getInterfaces().find(iinterface => iinterface.name === selectionNode.onType) != null || (isUnionType(fragmentType) && fragmentType.getTypes().find(objectType => objectType.name === parentSchemaType.name)) ) { // also process fields from fragment that apply for this parentType const flatten = this.flattenSelectionSet(selectionNode.selectionNodes, parentSchemaType); const typeNodes = flatten.get(parentSchemaType.name) ?? []; selectionNodes.push(...typeNodes); for (const iinterface of parentSchemaType.getInterfaces()) { const typeNodes = flatten.get(iinterface.name) ?? []; selectionNodes.push(...typeNodes); } } } const linkFields: LinkField[] = []; const linkFieldsInterfaces: DependentType[] = []; for (const { field, selectedFieldType } of linkFieldSelectionSets.values()) { const realSelectedFieldType = getBaseType(selectedFieldType as any); const selectionSet = this.createNext(realSelectedFieldType, field.selectionSet); const fieldName = field.alias?.value ?? field.name.value; const selectionSetObjects = selectionSet.transformSelectionSet( options.parentFieldName ? `${options.parentFieldName}_${fieldName}` : fieldName ); linkFieldsInterfaces.push(...selectionSetObjects.dependentTypes); const isConditional = hasConditionalDirectives(field) || inlineFragmentConditional; const isOptional = options.unsetTypes; linkFields.push({ alias: field.alias ? this._processor.config.formatNamedField(field.alias.value, selectedFieldType, isConditional, isOptional) : undefined, name: this._processor.config.formatNamedField(field.name.value, selectedFieldType, isConditional, isOptional), type: realSelectedFieldType.name, selectionSet: this._processor.config.wrapTypeWithModifiers( selectionSetObjects.mergedTypeString.split(`\n`).join(`\n `), selectedFieldType ), }); } const typeInfoField = this.buildTypeNameField( parentSchemaType, this._config.nonOptionalTypename, this._config.addTypename, requireTypename, this._config.skipTypeNameForRoot ); const transformed: ProcessResult = [ // Only add the typename field if we're not merging fragment // types. If we are merging, we need to wait until we know all // the involved typenames. ...(typeInfoField && (!this._config.mergeFragmentTypes || this._config.inlineFragmentTypes === 'mask') ? this._processor.transformTypenameField(typeInfoField.type, typeInfoField.name) : []), ...this._processor.transformPrimitiveFields( parentSchemaType, Array.from(primitiveFields.values()).map(field => ({ isConditional: hasConditionalDirectives(field), fieldName: field.name.value, })), options.unsetTypes ), ...this._processor.transformAliasesPrimitiveFields( parentSchemaType, Array.from(primitiveAliasFields.values()).map(field => ({ alias: field.alias.value, fieldName: field.name.value, isConditional: hasConditionalDirectives(field), })), options.unsetTypes ), ...this._processor.transformLinkFields(linkFields, options.unsetTypes), ].filter(Boolean); const allStrings: string[] = transformed.filter(t => typeof t === 'string') as string[]; const allObjectsMerged: string[] = transformed .filter(t => typeof t !== 'string') .map((t: NameAndType) => `${t.name}: ${t.type}`); let mergedObjectsAsString: string = null; if (allObjectsMerged.length > 0) { mergedObjectsAsString = this._processor.buildFieldsIntoObject(allObjectsMerged); } const fields = [...allStrings, mergedObjectsAsString].filter(Boolean); if (fragmentsSpreadUsages.length) { if (this._config.inlineFragmentTypes === 'combine') { fields.push(...fragmentsSpreadUsages); } else if (this._config.inlineFragmentTypes === 'mask') { fields.push( `{ ' $fragmentRefs'?: { ${fragmentsSpreadUsages .map(name => `'${name}': ${options.unsetTypes ? `Incremental<${name}>` : name}`) .join(`;`)} } }` ); } } return { typeInfo: typeInfoField, fields, dependentTypes: linkFieldsInterfaces }; } protected buildTypeNameField( type: GraphQLObjectType, nonOptionalTypename: boolean = this._config.nonOptionalTypename, addTypename: boolean = this._config.addTypename, queriedForTypename: boolean = this._queriedForTypename, skipTypeNameForRoot: boolean = this._config.skipTypeNameForRoot ): { name: string; type: string } { const rootTypes = getRootTypes(this._schema); if (rootTypes.has(type) && skipTypeNameForRoot && !queriedForTypename) { return null; } if (nonOptionalTypename || addTypename || queriedForTypename) { const optionalTypename = !queriedForTypename && !nonOptionalTypename; return { name: `${this._processor.config.formatNamedField('__typename')}${optionalTypename ? '?' : ''}`, type: `'${type.name}'`, }; } return null; } protected getUnknownType(): string { return 'never'; } protected getEmptyObjectType(): string { return 'Record'; } private getEmptyObjectTypeString(mustAddEmptyObject: boolean): string { return mustAddEmptyObject ? this.getEmptyObjectType() : ``; } public transformSelectionSet(fieldName: string) { const possibleTypesList = getPossibleTypes(this._schema, this._parentSchemaType); const possibleTypes = possibleTypesList.map(v => v.name).sort(); const fieldSelections = [ ...getFieldNames({ selections: this._selectionSet.selections, loadedFragments: this._loadedFragments }), ].sort(); // Optimization: Do not create new dependentTypes if fragment typename exists in cache // 2-layer cache: LOC => Field Selection Type Combination => cachedTypeString const objMap = this._processor.typeCache.get(this._selectionSet.loc) ?? new Map(); this._processor.typeCache.set(this._selectionSet.loc, objMap); const cacheHashKey = `${fieldSelections.join(',')} @ ${possibleTypes.join('|')}`; const [cachedTypeString] = objMap.get(cacheHashKey) ?? []; if (cachedTypeString) { // reuse previously generated type, as it is identical return { mergedTypeString: cachedTypeString, // there are no new dependent types, as this is a nth use of the same type dependentTypes: [], }; } const result = this.transformSelectionSetUncached(fieldName); objMap.set(cacheHashKey, [result.mergedTypeString, fieldName]); if (this._selectionSet.loc) { this._processor.typeCache.set(this._selectionSet.loc, objMap); } return result; } private transformSelectionSetUncached(fieldName: string): { mergedTypeString: string; dependentTypes: DependentType[]; isUnionType?: boolean; } { const { grouped, mustAddEmptyObject, dependentTypes: subDependentTypes } = this._buildGroupedSelections(fieldName); // This might happen in case we have an interface, that is being queries, without any GraphQL // "type" that implements it. It will lead to a runtime error, but we aim to try to reflect that in // build time as well. if (Object.keys(grouped).length === 0) { return { mergedTypeString: this.getUnknownType(), dependentTypes: subDependentTypes, }; } const dependentTypes = Object.keys(grouped) .map(typeName => { const relevant = grouped[typeName].filter(Boolean); return relevant.map(objDefinition => { const name = fieldName ? `${fieldName}_${typeName}` : typeName; return { name, content: typeof objDefinition === 'string' ? objDefinition : objDefinition.union.join(' | '), isUnionType: !!(typeof objDefinition !== 'string' && objDefinition.union.length > 1), }; }); }) .filter(pairs => pairs.length > 0); const typeParts = [ ...dependentTypes.map(pair => pair .map(({ name, content, isUnionType }) => // unions need to be wrapped, as intersections have higher precedence this._config.extractAllFieldsToTypes ? name : isUnionType ? `(${content})` : content ) .join(' & ') ), this.getEmptyObjectTypeString(mustAddEmptyObject), ].filter(Boolean); const content = formatUnion(typeParts); if (typeParts.length > 1 && this._config.extractAllFieldsToTypes) { return { mergedTypeString: fieldName, dependentTypes: [ ...subDependentTypes, ...dependentTypes.flat(1), { name: fieldName, content, isUnionType: true }, ], }; } return { mergedTypeString: content, dependentTypes: [...subDependentTypes, ...dependentTypes.flat(1)], isUnionType: typeParts.length > 1, }; } public transformFragmentSelectionSetToTypes( fragmentName: string, fragmentSuffix: string, declarationBlockConfig: DeclarationBlockConfig ): string { const mergedTypeString = this.buildFragmentTypeName(fragmentName, fragmentSuffix); const { grouped, dependentTypes } = this._buildGroupedSelections(mergedTypeString); const subTypes: DependentType[] = Object.keys(grouped).flatMap(typeName => { const possibleFields = grouped[typeName].filter(Boolean); const declarationName = this.buildFragmentTypeName(fragmentName, fragmentSuffix, typeName); if (possibleFields.length === 0) { if (!this._config.addTypename) { return [{ name: declarationName, content: this.getEmptyObjectType() }]; } return []; } const flatFields = possibleFields.map(selectionObject => { if (typeof selectionObject === 'string') return { value: selectionObject }; return { value: selectionObject.union.join(' | '), isUnionType: true }; }); const content = flatFields.length > 1 ? flatFields.map(({ value, isUnionType }) => (isUnionType ? `(${value})` : value)).join(' & ') : flatFields.map(({ value }) => value).join(' & '); return { name: declarationName, content, isUnionType: false, }; }); const fragmentMaskPartial = this._config.inlineFragmentTypes === 'mask' ? ` & { ' $fragmentName'?: '${mergedTypeString}' }` : ''; // TODO: unify with line 308 from base-documents-visitor const dependentTypesContent = this._config.extractAllFieldsToTypes ? dependentTypes.map( i => new DeclarationBlock(declarationBlockConfig) .export(true) .asKind('type') .withName(i.name) .withContent(i.content).string ) : []; if (subTypes.length === 1) { return [ ...dependentTypesContent, new DeclarationBlock(declarationBlockConfig) .export() .asKind('type') .withName(mergedTypeString) .withContent(subTypes[0].content + fragmentMaskPartial).string, ].join('\n'); } return [ ...dependentTypesContent, ...subTypes.map( t => new DeclarationBlock(declarationBlockConfig) .export(this._config.exportFragmentSpreadSubTypes) .asKind('type') .withName(t.name) .withContent( `${t.content}${ this._config.inlineFragmentTypes === 'mask' ? ` & { ' $fragmentName'?: '${t.name}' }` : '' }` ).string ), new DeclarationBlock(declarationBlockConfig) .export() .asKind('type') .withName(mergedTypeString) .withContent(formatUnion(subTypes.map(t => t.name))).string, ].join('\n'); } protected buildFragmentTypeName(name: string, suffix: string, typeName = ''): string { return this._convertName(name, { useTypesPrefix: true, suffix: typeName && suffix ? `_${typeName}_${suffix}` : typeName ? `_${typeName}` : suffix, }); } protected buildParentFieldName(typeName: string, parentName: string): string { // queries/mutations/fragments are guaranteed to be unique type names, // so we can skip affixing the field names with typeName if (operationTypes.includes(typeName)) { return parentName; } const schemaType = this._schema.getType(typeName); // Check if current selection set has type-narrowing fragments. // - Inline fragments are always type-narrowing // - Fragment spreads are only type-narrowing if they are on a different type than the current parent schema type // (e.g. spreading `fragment Foo on Pet` while processing `Pet` is not type-narrowing). const hasTypeNarrowingFragments = this._selectionSet?.selections?.some(selection => { if (selection.kind === Kind.INLINE_FRAGMENT) { return true; } if (selection.kind === Kind.FRAGMENT_SPREAD) { const spreadFragment = this._loadedFragments.find(lf => lf.name === selection.name.value); // If we can't resolve fragment metadata (or the current parent type), treat it as type-narrowing. // This avoids incorrectly using interface-rooted names in cases that are actually concrete-targeting. return !spreadFragment || !this._parentSchemaType || spreadFragment.onType !== this._parentSchemaType.name; } return false; }) ?? false; // When the parent schema type is an interface: // - If we're processing inline fragments, use the concrete type name // - If we're processing the interface directly, use the interface name // - If we're in a named fragment, always use the concrete type name if ( isObjectType(schemaType) && this._parentSchemaType && isInterfaceType(this._parentSchemaType) && !hasTypeNarrowingFragments ) { return `${parentName}_${this._parentSchemaType.name}`; } return `${parentName}_${typeName}`; } } function formatUnion(members: string[]): string { if (members.length > 1) { return `\n | ${members.map(m => m.replace(/\n/g, '\n ')).join('\n | ')}\n`; } return members.join(' | '); } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/types.ts ================================================ /* eslint-disable @typescript-eslint/no-empty-object-type */ import { ASTNode, FragmentDefinitionNode, DirectiveNode } from 'graphql'; import { ParsedMapper } from './mappers.js'; /** * A map between the GraphQL directive name and the identifier that should be used */ export type DirectiveArgumentAndInputFieldMappings = { [name: string]: string }; /** * Parsed directives map - a mapping between GraphQL directive name and the parsed mapper object, * including all required information for generating code for that mapping. */ export type ParsedDirectiveArgumentAndInputFieldMappings = { [name: string]: ParsedMapper }; /** * Scalars map or a string, a map between the GraphQL scalar name and the identifier that should be used */ export type ScalarsMap = string | { [name: string]: string | { input: string; output: string } }; /** * A normalized map between GraphQL scalar name and the identifier name */ export type NormalizedScalarsMap = { [name: string]: { input: string; output: string; }; }; /** * Parsed scalars map - a mapping between GraphQL scalar name and the parsed mapper object, * including all required information for generting code for that mapping. */ export type ParsedScalarsMap = { [name: string]: { input: ParsedMapper; output: ParsedMapper; }; }; /** * A raw configuration for enumValues map - can be represented with a single string value for a file path, * a map between enum name and a file path, or a map between enum name and an object with explicit enum values. */ export type EnumValuesMap = | string | { [enumName: string]: string | ({ [key: string]: string | number } & AdditionalProps) }; export type ParsedEnumValuesMap = { [enumName: string]: { // If values are explictly set, this will include the mapped values mappedValues?: { [valueName: string]: string | number }; // The GraphQL enum name typeIdentifier: string; // The actual identifier that you should use in the code (original or aliased) sourceIdentifier?: string; // In case of external enum, this will contain the source file path sourceFile?: string; // If the identifier is external (imported) - this will contain the imported expression (including alias), otherwise null importIdentifier?: string; // Is defualt import is used to import the enum isDefault?: boolean; }; }; export type ConvertNameFn = ConvertFn; export type GetFragmentSuffixFn = (node: FragmentDefinitionNode | string) => string; export interface ConvertOptions { prefix?: string; suffix?: string; transformUnderscore?: boolean; } export type ConvertFn = (node: ASTNode | string, options?: ConvertOptions & T) => string; export type NamingConventionFn = (str: string) => string; export type NamingConventionResolvePath = string; export type NamingConvention = string | NamingConventionFn | NamingConventionMap; /** * @additionalProperties false */ export interface NamingConventionMap { enumValues?: 'keep' | NamingConventionResolvePath | NamingConventionFn; typeNames?: 'keep' | NamingConventionResolvePath | NamingConventionFn; transformUnderscore?: boolean; } export type LoadedFragment = { name: string; onType: string; node: FragmentDefinitionNode; isExternal: boolean; importFrom?: string | null; } & AdditionalFields; export type DeclarationKind = 'type' | 'interface' | 'class' | 'abstract class'; export interface DeclarationKindConfig { directive?: DeclarationKind; scalar?: DeclarationKind; input?: DeclarationKind; type?: DeclarationKind; interface?: DeclarationKind; arguments?: DeclarationKind; } export interface AvoidOptionalsConfig { field?: boolean; object?: boolean; inputValue?: boolean; defaultValue?: boolean; resolvers?: boolean; query?: boolean; mutation?: boolean; subscription?: boolean; } export type NormalizedAvoidOptionalsConfig = Required; export interface ParsedImport { moduleName: string | null; propName: string; } export type FragmentDirectives = { fragmentDirectives?: Array; }; export interface ResolversNonOptionalTypenameConfig { unionMember?: boolean; interfaceImplementingType?: boolean; excludeTypes?: string[]; } export interface CustomDirectivesConfig { /** * @description Adds integration with Apollo Client's `@unmask` directive * when using Apollo Client's data masking feature. `@unmask` ensures fields * marked by `@unmask` are available in the type definition. * @default false */ apolloUnmask?: boolean; } ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/utils.ts ================================================ import { FieldNode, FragmentSpreadNode, GraphQLInputObjectType, GraphQLNamedType, GraphQLObjectType, GraphQLOutputType, GraphQLScalarType, GraphQLSchema, InlineFragmentNode, isAbstractType, isInputObjectType, isListType, isNonNullType, isObjectType, isScalarType, Kind, NamedTypeNode, NameNode, SelectionNode, SelectionSetNode, StringValueNode, TypeNode, DirectiveNode, } from 'graphql'; import { RawConfig } from './base-visitor.js'; import { parseMapper } from './mappers.js'; import { DEFAULT_SCALARS } from './scalars.js'; import { NormalizedScalarsMap, ParsedScalarsMap, ScalarsMap, FragmentDirectives, LoadedFragment } from './types.js'; export const getConfigValue = (value: T, defaultValue: T): T => { if (value === null || value === undefined) { return defaultValue; } return value; }; export function quoteIfNeeded(array: string[], joinWith = ' & '): string { if (array.length === 0) { return ''; } if (array.length === 1) { return array[0]; } return `(${array.join(joinWith)})`; } export function block(array) { return array && array.length !== 0 ? '{\n' + array.join('\n') + '\n}' : ''; } export function wrapWithSingleQuotes(value: string | number | NameNode, skipNumericCheck = false): string { if (skipNumericCheck) { if (typeof value === 'number') { return String(value); } return `'${value}'`; } if ( typeof value === 'number' || (typeof value === 'string' && !Number.isNaN(parseInt(value)) && parseFloat(value).toString() === value) ) { return String(value); } return `'${value}'`; } export function breakLine(str: string): string { return str + '\n'; } export function indent(str: string, count = 1): string { return new Array(count).fill(' ').join('') + str; } export function indentMultiline(str: string, count = 1): string { const indentation = new Array(count).fill(' ').join(''); const replaceWith = '\n' + indentation; return indentation + str.replace(/\n/g, replaceWith); } export interface DeclarationBlockConfig { blockWrapper?: string; blockTransformer?: (block: string) => string; enumNameValueSeparator?: string; ignoreExport?: boolean; } export function transformComment(comment: string | StringValueNode, indentLevel = 0, disabled = false): string { if (!comment || comment === '' || disabled) { return ''; } if (isStringValueNode(comment)) { comment = comment.value; } comment = comment.split('*/').join('*\\/'); let lines = comment.split('\n'); if (lines.length === 1) { return indent(`/** ${lines[0]} */\n`, indentLevel); } lines = ['/**', ...lines.map(line => ` * ${line}`), ' */\n']; return stripTrailingSpaces(lines.map(line => indent(line, indentLevel)).join('\n')); } export class DeclarationBlock { _decorator = null; _export = false; _name = null; _kind = null; _methodName = null; _content = null; _block = null; _nameGenerics = null; _comment = null; _ignoreBlockWrapper = false; constructor(private _config: DeclarationBlockConfig) { this._config = { blockWrapper: '', blockTransformer: block => block, enumNameValueSeparator: ':', ...this._config, }; } withDecorator(decorator: string): DeclarationBlock { this._decorator = decorator; return this; } export(exp = true): DeclarationBlock { if (!this._config.ignoreExport) { this._export = exp; } return this; } asKind(kind: string): DeclarationBlock { this._kind = kind; return this; } withComment(comment: string | StringValueNode | null, disabled = false): DeclarationBlock { const nonEmptyComment = !!(isStringValueNode(comment) ? comment.value : comment); if (nonEmptyComment && !disabled) { this._comment = transformComment(comment, 0); } return this; } withMethodCall(methodName: string, ignoreBlockWrapper = false): DeclarationBlock { this._methodName = methodName; this._ignoreBlockWrapper = ignoreBlockWrapper; return this; } withBlock(block: string): DeclarationBlock { this._block = block; return this; } withContent(content: string): DeclarationBlock { this._content = content; return this; } withName(name: string | NameNode, generics: string | null = null): DeclarationBlock { this._name = name; this._nameGenerics = generics; return this; } public get string(): string { let result = ''; if (this._decorator) { result += this._decorator + '\n'; } if (this._export) { result += 'export '; } if (this._kind) { let extra = ''; let name = ''; if (['type', 'const', 'var', 'let'].includes(this._kind)) { extra = '= '; } if (this._name) { name = this._name + (this._nameGenerics || '') + ' '; } result += this._kind + ' ' + name + extra; } if (this._block) { if (this._content) { result += this._content; } const blockWrapper = this._ignoreBlockWrapper ? '' : this._config.blockWrapper; const before = '{' + blockWrapper; const after = blockWrapper + '}'; const block = [before, this._block, after].filter(val => !!val).join('\n'); if (this._methodName) { result += `${this._methodName}(${this._config.blockTransformer(block)})`; } else { result += this._config.blockTransformer(block); } } else if (this._content) { result += this._content; } else if (this._kind) { result += this._config.blockTransformer('{}'); } return stripTrailingSpaces( (this._comment || '') + result + (this._kind === 'interface' || this._kind === 'enum' || this._kind === 'namespace' || this._kind === 'function' ? '' : ';') + '\n' ); } } export function getBaseTypeNode(typeNode: TypeNode): NamedTypeNode { if (typeNode.kind === Kind.LIST_TYPE || typeNode.kind === Kind.NON_NULL_TYPE) { return getBaseTypeNode(typeNode.type); } return typeNode; } export function convertNameParts(str: string, func: (str: string) => string, removeUnderscore = false): string { if (removeUnderscore) { return func(str); } return str .split('_') .map(s => func(s)) .join('_'); } export function buildScalarsFromConfig( schema: GraphQLSchema | undefined, config: RawConfig, defaultScalarsMapping: NormalizedScalarsMap = DEFAULT_SCALARS, defaultScalarType = 'any' ): ParsedScalarsMap { return buildScalars( schema, config.scalars, defaultScalarsMapping, config.strictScalars ? null : config.defaultScalarType || defaultScalarType ); } export function buildScalars( schema: GraphQLSchema | undefined, scalarsMapping: ScalarsMap, defaultScalarsMapping: NormalizedScalarsMap = DEFAULT_SCALARS, defaultScalarType: string | null = 'any' ): ParsedScalarsMap { const result: ParsedScalarsMap = {}; function normalizeScalarType(type: string | { input: string; output: string }): { input: string; output: string } { if (typeof type === 'string') { return { input: type, output: type, }; } return { input: type.input, output: type.output, }; } for (const name of Object.keys(defaultScalarsMapping)) { result[name] = { input: parseMapper(defaultScalarsMapping[name].input), output: parseMapper(defaultScalarsMapping[name].output), }; } if (schema) { const typeMap = schema.getTypeMap(); Object.keys(typeMap) .map(typeName => typeMap[typeName]) .filter(type => isScalarType(type)) .map((scalarType: GraphQLScalarType) => { const { name } = scalarType; if (typeof scalarsMapping === 'string') { const inputMapper = parseMapper(scalarsMapping + '#' + name, name); if (inputMapper.isExternal) { inputMapper.type += "['input']"; } const outputMapper = parseMapper(scalarsMapping + '#' + name, name); if (outputMapper.isExternal) { outputMapper.type += "['output']"; } result[name] = { input: inputMapper, output: outputMapper, }; } else if (scalarsMapping?.[name]) { const mappedScalar = scalarsMapping[name]; if (typeof mappedScalar === 'string') { const normalizedScalar = normalizeScalarType(scalarsMapping[name]); result[name] = { input: parseMapper(normalizedScalar.input, name), output: parseMapper(normalizedScalar.output, name), }; } else if (typeof mappedScalar === 'object' && mappedScalar.input && mappedScalar.output) { result[name] = { input: parseMapper(mappedScalar.input, name), output: parseMapper(mappedScalar.output, name), }; } else { result[name] = { input: { isExternal: false, type: JSON.stringify(mappedScalar), }, output: { isExternal: false, type: JSON.stringify(mappedScalar), }, }; } } else if (scalarType.extensions?.codegenScalarType) { result[name] = { input: { isExternal: false, type: scalarType.extensions.codegenScalarType as string, }, output: { isExternal: false, type: scalarType.extensions.codegenScalarType as string, }, }; } else if (!defaultScalarsMapping[name]) { if (defaultScalarType === null) { throw new Error(`Unknown scalar type ${name}. Please override it using the "scalars" configuration field!`); } result[name] = { input: { isExternal: false, type: defaultScalarType, }, output: { isExternal: false, type: defaultScalarType, }, }; } }); } else if (scalarsMapping) { if (typeof scalarsMapping === 'string') { throw new Error('Cannot use string scalars mapping when building without a schema'); } for (const name of Object.keys(scalarsMapping)) { if (typeof scalarsMapping[name] === 'string') { const normalizedScalar = normalizeScalarType(scalarsMapping[name]); result[name] = { input: parseMapper(normalizedScalar.input, name), output: parseMapper(normalizedScalar.output, name), }; } else { const normalizedScalar = normalizeScalarType(scalarsMapping[name]); result[name] = { input: { isExternal: false, type: JSON.stringify(normalizedScalar.input), }, output: { isExternal: false, type: JSON.stringify(normalizedScalar.output), }, }; } } } return result; } function isStringValueNode(node: any): node is StringValueNode { return node && typeof node === 'object' && node.kind === Kind.STRING; } // will be removed on next release because tools already has it export function getRootTypeNames(schema: GraphQLSchema): string[] { return [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()] .filter(t => t) .map(t => t.name); } export function stripMapperTypeInterpolation(identifier: string): string { return identifier.trim().replace(/<{.*}>/, ''); } export const OMIT_TYPE = 'export type Omit = Pick>;'; export const REQUIRE_FIELDS_TYPE = `export type RequireFields = Omit & { [P in K]-?: NonNullable };`; /** * merge selection sets into a new selection set without mutating the inputs. */ export function mergeSelectionSets(selectionSet1: SelectionSetNode, selectionSet2: SelectionSetNode): SelectionSetNode { const newSelections = [...selectionSet1.selections]; for (let selection2 of selectionSet2.selections) { if (selection2.kind === 'FragmentSpread' || selection2.kind === 'InlineFragment') { newSelections.push(selection2); continue; } if (selection2.kind !== 'Field') { throw new TypeError('Invalid state.'); } const match = newSelections.find( selection1 => selection1.kind === 'Field' && getFieldNodeNameValue(selection1) === getFieldNodeNameValue(selection2 as FieldNode) ); if ( match && // recursively merge all selection sets match.kind === 'Field' && match.selectionSet && selection2.selectionSet ) { selection2 = { ...selection2, selectionSet: mergeSelectionSets(match.selectionSet, selection2.selectionSet), }; } newSelections.push(selection2); } return { kind: Kind.SELECTION_SET, selections: newSelections, }; } export const getFieldNodeNameValue = (node: FieldNode): string => { return (node.alias || node.name).value; }; export function separateSelectionSet(selections: ReadonlyArray): { fields: (FieldNode & FragmentDirectives)[]; spreads: FragmentSpreadNode[]; inlines: InlineFragmentNode[]; } { return { fields: selections.filter(s => s.kind === Kind.FIELD) as FieldNode[], inlines: selections.filter(s => s.kind === Kind.INLINE_FRAGMENT) as InlineFragmentNode[], spreads: selections.filter(s => s.kind === Kind.FRAGMENT_SPREAD) as FragmentSpreadNode[], }; } export function getPossibleTypes(schema: GraphQLSchema, type: GraphQLNamedType): GraphQLObjectType[] { if (isListType(type) || isNonNullType(type)) { return getPossibleTypes(schema, type.ofType as GraphQLNamedType); } if (isObjectType(type)) { return [type]; } if (isAbstractType(type)) { return schema.getPossibleTypes(type) as Array; } return []; } export function hasConditionalDirectives(field: FieldNode): boolean { const CONDITIONAL_DIRECTIVES = ['skip', 'include']; return field.directives?.some(directive => CONDITIONAL_DIRECTIVES.includes(directive.name.value)); } export function hasIncrementalDeliveryDirectives(directives: DirectiveNode[]): boolean { const INCREMENTAL_DELIVERY_DIRECTIVES = ['defer']; return directives?.some(directive => INCREMENTAL_DELIVERY_DIRECTIVES.includes(directive.name.value)); } type WrapModifiersOptions = { wrapOptional(type: string): string; wrapArray(type: string): string; }; export function wrapTypeWithModifiers( baseType: string, type: GraphQLOutputType | GraphQLNamedType, options: WrapModifiersOptions ): string { let currentType = type; const modifiers: Array<(type: string) => string> = []; while (currentType) { if (isNonNullType(currentType)) { currentType = currentType.ofType; } else { modifiers.push(options.wrapOptional); } if (isListType(currentType)) { modifiers.push(options.wrapArray); currentType = currentType.ofType; } else { break; } } return modifiers.reduceRight((result, modifier) => modifier(result), baseType); } export function removeDescription(nodes: readonly T[]) { return nodes.map(node => ({ ...node, description: undefined })); } export function wrapTypeNodeWithModifiers(baseType: string, typeNode: TypeNode): string { switch (typeNode.kind) { case Kind.NAMED_TYPE: { return `Maybe<${baseType}>`; } case Kind.NON_NULL_TYPE: { const innerType = wrapTypeNodeWithModifiers(baseType, typeNode.type); return clearOptional(innerType); } case Kind.LIST_TYPE: { const innerType = wrapTypeNodeWithModifiers(baseType, typeNode.type); return `Maybe>`; } } } function clearOptional(str: string): string { const rgx = new RegExp(`^Maybe<(.*?)>$`, 'i'); if (str.startsWith(`Maybe`)) { return str.replace(rgx, '$1'); } return str; } function stripTrailingSpaces(str: string): string { return str.replace(/ +\n/g, '\n'); } const isOneOfTypeCache = new WeakMap(); export function isOneOfInputObjectType( namedType: GraphQLNamedType | null | undefined ): namedType is GraphQLInputObjectType { if (!namedType) { return false; } let isOneOfType = isOneOfTypeCache.get(namedType); if (isOneOfType !== undefined) { return isOneOfType; } isOneOfType = isInputObjectType(namedType) && ((namedType as unknown as Record<'isOneOf', boolean | undefined>).isOneOf || namedType.astNode?.directives?.some(d => d.name.value === 'oneOf')); isOneOfTypeCache.set(namedType, isOneOfType); return isOneOfType; } export function groupBy(array: Array, key: (item: T) => string | number): { [key: string]: Array } { return array.reduce<{ [key: string]: Array }>((acc, item) => { const group = (acc[key(item)] ??= []); group.push(item); return acc; }, {}); } export function flatten(array: Array>): Array { return ([] as Array).concat(...array); } export function unique(array: Array, key: (item: T) => string | number = item => item.toString()): Array { return Object.values(array.reduce((acc, item) => ({ [key(item)]: item, ...acc }), {})); } function getFullPathFieldName(selection: FieldNode, parentName: string) { const fullName = 'alias' in selection && selection.alias ? `${selection.alias.value}@${selection.name.value}` : selection.name.value; return parentName ? `${parentName}.${fullName}` : fullName; } export const getFieldNames = ({ selections, fieldNames = new Set(), parentName = '', loadedFragments, }: { selections: readonly SelectionNode[]; fieldNames?: Set; parentName?: string; loadedFragments: LoadedFragment[]; }) => { for (const selection of selections) { switch (selection.kind) { case Kind.FIELD: { const fieldName = getFullPathFieldName(selection, parentName); fieldNames.add(fieldName); if (selection.selectionSet) { getFieldNames({ selections: selection.selectionSet.selections, fieldNames, parentName: fieldName, loadedFragments, }); } break; } case Kind.FRAGMENT_SPREAD: { getFieldNames({ selections: loadedFragments .filter(def => def.name === selection.name.value) .flatMap(s => s.node.selectionSet.selections), fieldNames, parentName, loadedFragments, }); break; } case Kind.INLINE_FRAGMENT: { getFieldNames({ selections: selection.selectionSet.selections, fieldNames, parentName, loadedFragments }); break; } } } return fieldNames; }; ================================================ FILE: packages/plugins/other/visitor-plugin-common/src/variables-to-object.ts ================================================ import autoBind from 'auto-bind'; import { DirectiveNode, Kind, NameNode, TypeNode, ValueNode, VariableNode } from 'graphql'; import { BaseVisitorConvertOptions } from './base-visitor.js'; import { ConvertNameFn, NormalizedScalarsMap, ParsedDirectiveArgumentAndInputFieldMappings, ParsedEnumValuesMap, } from './types.js'; import { getBaseTypeNode, indent } from './utils.js'; export interface InterfaceOrVariable { name?: NameNode; variable?: VariableNode; type: TypeNode; defaultValue?: ValueNode; directives?: ReadonlyArray; } export class OperationVariablesToObject { constructor( protected _scalars: NormalizedScalarsMap, protected _convertName: ConvertNameFn, protected _namespacedImportName: string | null = null, protected _enumNames: string[] = [], protected _enumPrefix = true, protected _enumSuffix = true, protected _enumValues: ParsedEnumValuesMap = {}, protected _applyCoercion: boolean = false, protected _directiveArgumentAndInputFieldMappings: ParsedDirectiveArgumentAndInputFieldMappings = {} ) { autoBind(this); } getName(node: TDefinitionType): string { if (node.name) { if (typeof node.name === 'string') { return node.name; } return node.name.value; } if (node.variable) { return node.variable.name.value; } return null; } transform(variablesNode: ReadonlyArray): string { if (!variablesNode || variablesNode.length === 0) { return null; } return ( variablesNode.map(variable => indent(this.transformVariable(variable))).join(`${this.getPunctuation()}\n`) + this.getPunctuation() ); } protected getScalar(name: string): string { const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : ''; return `${prefix}Scalars['${name}']['input']`; } protected getDirectiveMapping(name: string): string { return `DirectiveArgumentAndInputFieldMappings['${name}']`; } protected getDirectiveOverrideType(directives: ReadonlyArray): string | null { if (!this._directiveArgumentAndInputFieldMappings) return null; const type = directives .map(directive => { const directiveName = directive.name.value; if (this._directiveArgumentAndInputFieldMappings[directiveName]) { return this.getDirectiveMapping(directiveName); } return null; }) .reverse() .find(a => !!a); return type || null; } protected transformVariable(variable: TDefinitionType): string { let typeValue = null; const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : ''; if (typeof variable.type === 'string') { typeValue = variable.type; } else { const baseType = getBaseTypeNode(variable.type); const overrideType = variable.directives ? this.getDirectiveOverrideType(variable.directives) : null; const typeName = baseType.name.value; if (overrideType) { typeValue = overrideType; } else if (this._scalars[typeName]) { typeValue = this.getScalar(typeName); } else if (this._enumValues[typeName]?.sourceFile) { typeValue = this._enumValues[typeName].typeIdentifier || this._enumValues[typeName].sourceIdentifier; } else { typeValue = `${prefix}${this._convertName(baseType, { useTypesPrefix: this._enumNames.includes(typeName) ? this._enumPrefix : true, useTypesSuffix: this._enumNames.includes(typeName) ? this._enumSuffix : true, })}`; } } const fieldName = this.getName(variable); const fieldType = this.wrapAstTypeWithModifiers(typeValue, variable.type, this._applyCoercion); const hasDefaultValue = variable.defaultValue != null && typeof variable.defaultValue !== 'undefined'; const isNonNullType = variable.type.kind === Kind.NON_NULL_TYPE; const formattedFieldString = this.formatFieldString(fieldName, isNonNullType, hasDefaultValue); const formattedTypeString = this.formatTypeString(fieldType, isNonNullType, hasDefaultValue); return `${formattedFieldString}: ${formattedTypeString}`; } public wrapAstTypeWithModifiers(_baseType: string, _typeNode: TypeNode, _applyCoercion?: boolean): string { throw new Error(`You must override "wrapAstTypeWithModifiers" of OperationVariablesToObject!`); } protected formatFieldString(fieldName: string, _isNonNullType: boolean, _hasDefaultValue: boolean): string { return fieldName; } protected formatTypeString(fieldType: string, isNonNullType: boolean, hasDefaultValue: boolean): string { const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : ''; if (hasDefaultValue) { return `${prefix}Maybe<${fieldType}>`; } return fieldType; } protected getPunctuation(): string { return ','; } } ================================================ FILE: packages/plugins/other/visitor-plugin-common/tests/client-side-base-visitor.spec.ts ================================================ import { buildSchema, FragmentDefinitionNode, OperationDefinitionNode, parse, Kind } from 'graphql'; import { ClientSideBaseVisitor, DocumentMode } from '../src/client-side-base-visitor.js'; describe('getImports', () => { describe('when documentMode "external", importDocumentNodeExternallyFrom is "near-operation-file"', () => { const schema = buildSchema(/* GraphQL */ ` type Query { a: A } type A { foo: String bar: String } `); describe('when emitLegacyCommonJSImports is true', () => { it('does not append `.js` to Operations import path', () => { const fileName = 'fooBarQuery'; const importPath = `src/queries/${fileName}`; const document = parse( `query fooBarQuery { a { foo bar } } ` ); const visitor = new ClientSideBaseVisitor( schema, [], { emitLegacyCommonJSImports: true, importDocumentNodeExternallyFrom: 'near-operation-file', documentMode: DocumentMode.external, }, {}, [{ document, location: importPath }] ); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); const imports = visitor.getImports(); expect(imports[0]).toBe(`import * as Operations from './${fileName}';`); }); }); describe('when emitLegacyCommonJSImports is false', () => { it('appends `.js` to Operations import path', () => { const fileName = 'fooBarQuery'; const importPath = `src/queries/${fileName}`; const document = parse( `query fooBarQuery { a { foo bar } } ` ); const visitor = new ClientSideBaseVisitor( schema, [], { emitLegacyCommonJSImports: false, importDocumentNodeExternallyFrom: 'near-operation-file', documentMode: DocumentMode.external, }, {}, [{ document, location: importPath }] ); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); const imports = visitor.getImports(); expect(imports[0]).toBe(`import * as Operations from './${fileName}.js';`); }); }); describe('when importExtension is set to .mjs', () => { it('appends `.mjs` to Operations import path', () => { const fileName = 'fooBarQuery'; const importPath = `src/queries/${fileName}`; const document = parse( `query fooBarQuery { a { foo bar } } ` ); const visitor = new ClientSideBaseVisitor( schema, [], { importExtension: '.mjs', importDocumentNodeExternallyFrom: 'near-operation-file', documentMode: DocumentMode.external, }, {}, [{ document, location: importPath }] ); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); const imports = visitor.getImports(); expect(imports[0]).toBe(`import * as Operations from './${fileName}.mjs';`); }); }); describe('when importExtension is set to empty string', () => { it('does not append extension to Operations import path', () => { const fileName = 'fooBarQuery'; const importPath = `src/queries/${fileName}`; const document = parse( `query fooBarQuery { a { foo bar } } ` ); const visitor = new ClientSideBaseVisitor( schema, [], { importExtension: '', importDocumentNodeExternallyFrom: 'near-operation-file', documentMode: DocumentMode.external, }, {}, [{ document, location: importPath }] ); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); const imports = visitor.getImports(); expect(imports[0]).toBe(`import * as Operations from './${fileName}';`); }); }); describe('when both importExtension and emitLegacyCommonJSImports are set', () => { it('uses importExtension over emitLegacyCommonJSImports', () => { const fileName = 'fooBarQuery'; const importPath = `src/queries/${fileName}`; const document = parse( `query fooBarQuery { a { foo bar } } ` ); const visitor = new ClientSideBaseVisitor( schema, [], { importExtension: '.mjs', emitLegacyCommonJSImports: false, importDocumentNodeExternallyFrom: 'near-operation-file', documentMode: DocumentMode.external, }, {}, [{ document, location: importPath }] ); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); const imports = visitor.getImports(); expect(imports[0]).toBe(`import * as Operations from './${fileName}.mjs';`); }); it('uses importExtension set to empty string even when emitLegacyCommonJSImports is false', () => { const fileName = 'fooBarQuery'; const importPath = `src/queries/${fileName}`; const document = parse( `query fooBarQuery { a { foo bar } } ` ); const visitor = new ClientSideBaseVisitor( schema, [], { importExtension: '', emitLegacyCommonJSImports: false, importDocumentNodeExternallyFrom: 'near-operation-file', documentMode: DocumentMode.external, }, {}, [{ document, location: importPath }] ); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); const imports = visitor.getImports(); expect(imports[0]).toBe(`import * as Operations from './${fileName}';`); }); }); }); describe('when documentMode "external", importDocumentNodeExternallyFrom is relative path', () => { const schema = buildSchema(/* GraphQL */ ` type Query { a: A } type A { foo: String bar: String } `); describe('when emitLegacyCommonJSImports is false', () => { it('preserves `.js` on Operations import path', () => { const fileName = 'fooBarQuery'; const importPath = `./src/queries/${fileName}.js`; const document = parse( `query fooBarQuery { a { foo bar } } ` ); const visitor = new ClientSideBaseVisitor( schema, [], { emitLegacyCommonJSImports: false, importDocumentNodeExternallyFrom: importPath, documentMode: DocumentMode.external, }, {}, [{ document, location: importPath }] ); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); const imports = visitor.getImports(); expect(imports[0]).toBe(`import * as Operations from '${importPath}';`); }); }); }); describe('when documentMode "documentNodeImportFragments"', () => { const schema = buildSchema(/* GraphQL */ ` type Query { a: A } type A { foo: String bar: String } `); it('does not import FragmentDocs', () => { const fileName = 'fooBarQuery'; const importPath = `src/queries/${fileName}`; const document = parse( `query fooBarQuery { a { ...fields } } fragment fields on A { foo bar } ` ); const visitor = new ClientSideBaseVisitor( schema, (document.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION) as FragmentDefinitionNode[]).map( fragmentDef => ({ node: fragmentDef, name: fragmentDef.name.value, onType: fragmentDef.typeCondition.name.value, isExternal: false, }) ), { emitLegacyCommonJSImports: true, importDocumentNodeExternallyFrom: 'near-operation-file', documentMode: DocumentMode.documentNodeImportFragments, fragmentImports: [ { baseDir: '/', baseOutputDir: '', outputPath: '', importSource: { path: '~types', identifiers: [ { name: 'FieldsFragmentDoc', kind: 'document' }, { name: 'FieldsFragment', kind: 'type' }, ], }, importExtension: '', typesImport: false, }, ], }, {}, [{ document, location: importPath }] ); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); const imports = visitor.getImports(); for (const i of imports) { expect(i).not.toContain('FragmentDoc'); } }); }); describe('when documentMode "graphQLTag"', () => { const schema = buildSchema(/* GraphQL */ ` type Query { a: A } type A { foo: String bar: String } `); it('imports FragmentDocs', () => { const fileName = 'fooBarQuery'; const importPath = `src/queries/${fileName}`; const document = parse( `query fooBarQuery { a { ...fields } } fragment fields on A { foo bar } ` ); const visitor = new ClientSideBaseVisitor( schema, (document.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION) as FragmentDefinitionNode[]).map( fragmentDef => ({ node: fragmentDef, name: fragmentDef.name.value, onType: fragmentDef.typeCondition.name.value, isExternal: false, }) ), { emitLegacyCommonJSImports: true, importDocumentNodeExternallyFrom: 'near-operation-file', documentMode: DocumentMode.graphQLTag, fragmentImports: [ { baseDir: '/', baseOutputDir: '', outputPath: '', importSource: { path: '~types', identifiers: [ { name: 'FieldsFragmentDoc', kind: 'document' }, { name: 'FieldsFragment', kind: 'type' }, ], }, importExtension: '', typesImport: false, }, ], }, {}, [{ document, location: importPath }] ); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); const imports = visitor.getImports(); expect(imports.some(i => i.includes('FragmentDoc'))).toBeTruthy(); }); }); }); describe('includeExternalFragments', () => { const schema = buildSchema(/* GraphQL */ ` type Query { a: A } type A { foo: String bar: String } `); const document = parse(` query fooBarQuery { a { ...ExternalA } } `); const externalFragments = parse(` fragment ExternalA on A { foo bar } `) .definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION) .map(fragmentDef => ({ node: fragmentDef, name: fragmentDef.name.value, onType: fragmentDef.typeCondition.name.value, isExternal: true, })); it('should not include external fragments', () => { const visitor = new ClientSideBaseVisitor(schema, externalFragments, {}, {}); visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode); expect(visitor.fragments).toBe(''); }); it('should include external fragments', () => { const visitor = new ClientSideBaseVisitor( schema, externalFragments, { includeExternalFragments: true, }, {} ); expect(visitor.fragments).toContain('ExternalAFragment'); }); }); ================================================ FILE: packages/plugins/other/visitor-plugin-common/tests/create-resolvers-fields.spec.ts ================================================ import { BaseResolversVisitor, ParsedResolversConfig } from '@graphql-codegen/visitor-plugin-common'; import { buildSchema } from 'graphql'; describe('BaseResolversVisitor.createResolversFields', () => { const schema = buildSchema(/* GraphQL */ ` type Query { a: A } type A { b: B } enum B { C } `); it('checks if types are actually included when Omit is applied', () => { /** * This makes sure that https://github.com/dotansimha/graphql-code-generator/issues/6709 doesn't occur again. * The result looked like this without the fix: * export type ResolversParentTypes = { * Query: {} * A: Omit & { b?: Maybe } * Boolean: Scalars['Boolean']['output'] * String: Scalars['String']['output'] * }; */ const visitor = new BaseResolversVisitor( { mappers: { B: './some-file#B', }, }, {} as ParsedResolversConfig, schema ); expect(visitor.buildResolversParentTypes()).toEqual( `/** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Query: Record A: A Boolean: Scalars['Boolean']['output'] String: Scalars['String']['output'] }; ` ); }); it('generates proper types when typesPrefix is used along with `enumPrefix: false`', () => { /** * This makes sure that https://github.com/dotansimha/graphql-code-generator/issues/6709 doesn't occur again. * The result looked like this without the fix: * export type ResolversParentTypes = { * Query: {} * A: Omit & { b?: Maybe } * Boolean: Scalars['Boolean']['output'] * String: Scalars['String']['output'] * }; */ const visitor = new BaseResolversVisitor( { mappers: { B: './some-file#B', }, typesPrefix: 'I', enumPrefix: false, }, {} as ParsedResolversConfig, schema ); expect(visitor.buildResolversParentTypes()).toEqual( `/** Mapping between all available schema types and the resolvers parents */ export type IResolversParentTypes = { Query: Record A: IA Boolean: Scalars['Boolean']['output'] String: Scalars['String']['output'] }; ` ); }); it('generates proper types when typesSuffix is used along with `enumSuffix: false`', () => { const visitor = new BaseResolversVisitor( { mappers: { B: './some-file#B', }, typesSuffix: 'I', enumSuffix: false, }, {} as ParsedResolversConfig, schema ); expect(visitor.buildResolversParentTypes()).toEqual( `/** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypesI = { Query: Record A: AI Boolean: Scalars['Boolean']['output'] String: Scalars['String']['output'] }; ` ); }); }); ================================================ FILE: packages/plugins/other/visitor-plugin-common/tests/enum-values.spec.ts ================================================ import { buildSchema, GraphQLEnumType, GraphQLObjectType, GraphQLSchema } from 'graphql'; import { parseEnumValues } from '../src/enum-values.js'; describe('enumValues', () => { const schema = buildSchema(/* GraphQL */ ` enum Test { A B C } type Query { test: Test } `); it('should work with namespaces', () => { const result = parseEnumValues({ schema, mapOrStr: { Test: `my-file#SomeNamespace.ETest`, }, }); expect(result).toEqual({ Test: { isDefault: false, typeIdentifier: 'Test', sourceFile: 'my-file', sourceIdentifier: 'SomeNamespace.ETest', importIdentifier: 'SomeNamespace', mappedValues: null, }, }); }); it('should work with regular type', () => { const result = parseEnumValues({ schema, mapOrStr: { Test: `my-file#ETest`, }, }); expect(result).toEqual({ Test: { isDefault: false, typeIdentifier: 'Test', sourceFile: 'my-file', sourceIdentifier: 'ETest', importIdentifier: 'ETest', mappedValues: null, }, }); }); it('should work with aliased type', () => { const result = parseEnumValues({ schema, mapOrStr: { Test: `my-file#ETest as Something`, }, }); expect(result).toEqual({ Test: { isDefault: false, typeIdentifier: 'Test', sourceFile: 'my-file', sourceIdentifier: 'Something', importIdentifier: 'ETest as Something', mappedValues: null, }, }); }); const schemaWithEnumValues = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { test: { type: new GraphQLEnumType({ name: 'Test', values: { A: { value: 'a', }, B: { value: 'b', }, C: { value: 'c', }, D: { value: `escape me '`, }, }, }), }, }, }), }); it('should respect enum values from schema and escape it if needed', () => { const result = parseEnumValues({ schema: schemaWithEnumValues, mapOrStr: {}, ignoreEnumValuesFromSchema: false, }); expect(result).toEqual({ Test: { isDefault: false, typeIdentifier: 'Test', sourceFile: null, importIdentifier: null, sourceIdentifier: null, mappedValues: { A: 'a', B: 'b', C: 'c', D: `escape me \\'`, }, }, }); }); it('should ignore enum values from schema', () => { const result = parseEnumValues({ schema: schemaWithEnumValues, mapOrStr: {}, ignoreEnumValuesFromSchema: true, }); expect(result).not.toEqual({ Test: { isDefault: false, typeIdentifier: 'Test', sourceFile: null, importIdentifier: null, sourceIdentifier: null, mappedValues: { A: 'a', B: 'b', C: 'c', }, }, }); }); const schemaWithNonStringEnumValues = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { test: { type: new GraphQLEnumType({ name: 'Test', values: { A: { value: 1, }, B: { value: true, }, C: { value: null, }, D: { value: undefined, }, }, }), }, }, }), }); it('should respect non-string enum values', () => { const result = parseEnumValues({ schema: schemaWithNonStringEnumValues, mapOrStr: {}, ignoreEnumValuesFromSchema: false, }); expect(result).not.toEqual({ Test: { isDefault: false, typeIdentifier: 'Test', sourceFile: null, importIdentifier: null, sourceIdentifier: null, mappedValues: { A: '1', B: 'true', C: 'null', D: 'undefined', }, }, }); }); }); ================================================ FILE: packages/plugins/other/visitor-plugin-common/tests/parse-mapper.spec.ts ================================================ import { parseMapper, transformMappers } from '../src/mappers.js'; describe('parseMapper', () => { it('Should return the correct values for a simple named mapper', () => { const result = parseMapper('MyType'); expect(result).toEqual({ isExternal: false, type: 'MyType', }); }); it('Should support a custom mapper with no imports', () => { const result = parseMapper('CustomMergeTypeMapper', 'SomeType'); expect(result).toEqual({ isExternal: false, type: 'CustomMergeTypeMapper', }); }); it('Should return the correct values for a external named mapper', () => { const result = parseMapper('file#MyType'); expect(result).toEqual({ default: false, isExternal: true, import: 'MyType', type: 'MyType', source: 'file', }); }); it('Should return the correct values for a external default mapper', () => { const result = parseMapper('file#default', 'MyGqlType'); expect(result).toEqual({ default: true, isExternal: true, import: 'MyGqlType', type: 'MyGqlType', source: 'file', }); }); it('Should support namespaces', () => { const result = parseMapper('file#Namespace.Type', 'MyGqlType'); expect(result).toEqual({ default: false, isExternal: true, import: 'Namespace', type: 'Namespace.Type', source: 'file', }); // legacy const legacyResult = parseMapper('file#Namespace#Type', 'MyGqlType'); expect(legacyResult).toEqual({ default: false, isExternal: true, import: 'Namespace', type: 'Namespace.Type', source: 'file', }); }); it('Should support aliases', () => { const result = parseMapper('file#Type as SomeOtherType', 'SomeType'); expect(result).toEqual({ default: false, isExternal: true, import: 'Type as SomeOtherType', type: 'SomeOtherType', source: 'file', }); }); it('Should support aliases (default)', () => { const result = parseMapper('file#default as SomeOtherType', 'SomeType'); expect(result).toEqual({ default: true, isExternal: true, import: 'SomeOtherType', type: 'SomeOtherType', source: 'file', }); }); it('should support generic with complex setup', () => { const result = parseMapper(`@common-types#Edge`, 'SomeType'); expect(result).toEqual({ default: false, isExternal: true, import: 'Edge', type: `Edge`, source: '@common-types', }); }); it('Should support generics', () => { const result = parseMapper('file#Type', 'SomeType'); expect(result).toEqual({ default: false, isExternal: true, import: 'Type', type: 'Type', source: 'file', }); }); describe('suffix', () => { it('Should not add a suffix to a simple named mapper', () => { const result = parseMapper('MyType', null, 'Model'); expect(result).toEqual({ isExternal: false, type: 'MyType', }); }); it('Should add a suffix to an external named mapper', () => { const result = parseMapper('file#Type', null, 'Model'); expect(result).toEqual({ default: false, isExternal: true, import: 'Type as TypeModel', type: 'TypeModel', source: 'file', }); }); it('Should add a suffix to an external default mapper', () => { const result = parseMapper('file#default', 'MyGqlType', 'Model'); expect(result).toEqual({ default: true, isExternal: true, import: 'MyGqlTypeModel', type: 'MyGqlTypeModel', source: 'file', }); }); it('Should add a suffix and support generics', () => { const result = parseMapper('file#Type', 'SomeType', 'Model'); expect(result).toEqual({ default: false, isExternal: true, import: 'Type as TypeModel', type: 'TypeModel', source: 'file', }); }); it('Should not add a suffix to a namespace', () => { const result = parseMapper('file#Namespace.Type', 'MyGqlType', 'Model'); expect(result).toEqual({ default: false, isExternal: true, import: 'Namespace', type: 'Namespace.Type', source: 'file', }); // legacy const legacyResult = parseMapper('file#Namespace#Type', 'MyGqlType', 'Model'); expect(legacyResult).toEqual({ default: false, isExternal: true, import: 'Namespace', type: 'Namespace.Type', source: 'file', }); }); it('Should add a suffix next to an alias', () => { const result = parseMapper('file#Type as SomeOtherType', 'SomeType', 'Model'); expect(result).toEqual({ default: false, isExternal: true, import: 'Type as SomeOtherTypeModel', type: 'SomeOtherTypeModel', source: 'file', }); }); it('transformMappers should apply a suffix to parseMapper', () => { const mappers = transformMappers( { Type: 'file#Type as SomeOtherType', }, 'Suffix' ); const result = mappers.Type; expect(result).toEqual({ default: false, isExternal: true, import: 'Type as SomeOtherTypeSuffix', type: 'SomeOtherTypeSuffix', source: 'file', }); }); }); }); ================================================ FILE: packages/plugins/other/visitor-plugin-common/tests/plugins-common.spec.ts ================================================ import { convertFactory } from '../src/naming.js'; describe('convertFactory', () => { it('Should use pascal case by default', () => { const factory = convertFactory({ namingConvention: null, }); expect(factory('MyName')).toBe('MyName'); expect(factory('myName')).toBe('MyName'); expect(factory('myname')).toBe('Myname'); expect(factory('MyNAME')).toBe('MyName'); }); it('Should allow to override underscore behaviour directly from configuration.', () => { const factory = convertFactory({ namingConvention: { transformUnderscore: true, }, }); expect(factory('My_Name')).toBe('MyName'); expect(factory('_Myname')).toBe('Myname'); expect(factory('My_name')).toBe('MyName'); }); it('Should allow to use "keep" as root', () => { const factory = convertFactory({ namingConvention: 'keep', }); expect(factory('MyName')).toBe('MyName'); expect(factory('myName')).toBe('myName'); expect(factory('myname')).toBe('myname'); expect(factory('MyNAME')).toBe('MyNAME'); }); it('Should allow to use Function as root', () => { const factory = convertFactory({ namingConvention: str => { return 'something' + str; }, }); expect(factory('MyName')).toBe('somethingMyName'); }); it('Should allow to use object of naming conventions', () => { const factory = convertFactory({ namingConvention: { typeNames: 'keep', enumValues: 'keep', }, }); expect(factory('MyName')).toBe('MyName'); expect(factory('Myname')).toBe('Myname'); expect(factory('NYNAME')).toBe('NYNAME'); }); it('Should allow to use function of naming conventions', () => { const factory = convertFactory({ namingConvention: { typeNames: str => 'a_' + str, enumValues: 'keep', }, }); expect(factory('MyName')).toBe('a_MyName'); expect(factory('Myname')).toBe('a_Myname'); expect(factory('NYNAME')).toBe('a_NYNAME'); }); it('Should allow to use function of naming conventions', () => { const factory = convertFactory({ namingConvention: { typeNames: str => 'a_' + str, enumValues: 'keep', }, }); expect(factory('MyName')).toBe('a_MyName'); expect(factory('Myname')).toBe('a_Myname'); expect(factory('NYNAME')).toBe('a_NYNAME'); }); it('Should keep underscore by default', () => { const factory = convertFactory({ namingConvention: null, }); expect(factory('My_Name')).toBe('My_Name'); expect(factory('_Myname')).toBe('_Myname'); expect(factory('My_name')).toBe('My_Name'); }); it('Should allow to override underscore behaviour', () => { const factory = convertFactory({ namingConvention: null, }); expect(factory('My_Name', { transformUnderscore: true })).toBe('MyName'); expect(factory('_Myname', { transformUnderscore: true })).toBe('Myname'); expect(factory('My_name', { transformUnderscore: true })).toBe('MyName'); }); it('Should allow to override transformUnderscore in config', () => { const factory = convertFactory({ namingConvention: { typeNames: str => str.replace('_', ''), enumValues: 'keep', transformUnderscore: true, }, }); expect(factory('My_Name')).toBe('MyName'); expect(factory('_Myname')).toBe('Myname'); expect(factory('My_name')).toBe('Myname'); }); }); ================================================ FILE: packages/plugins/other/visitor-plugin-common/tests/utils.spec.ts ================================================ import { flatten, groupBy, unique } from '../src/utils'; describe('utils', () => { describe('flatten', () => { it('should flatten a nested array', () => { const array = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]; const actual = flatten(array); const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9]; expect(actual).toEqual(expected); }); }); describe('groupBy', () => { it('should group by a property', () => { const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const actual = groupBy(array, i => i % 2); const expected = { 0: [2, 4, 6, 8, 10], 1: [1, 3, 5, 7, 9] }; expect(actual).toEqual(expected); }); }); describe('unique', () => { it('should return unique items when no key selector is passed', () => { const array = [1, 2, 3, 1, 2, 4]; const actual = unique(array); const expected = [1, 2, 3, 4]; expect(actual).toEqual(expected); }); it('should return unique items based on key selector', () => { const array = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 1, name: 'Alice #2' }, { id: 3, name: 'Charlie' }, ]; const actual = unique(array, item => item.id); const expected = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }, ]; expect(actual).toEqual(expected); }); }); }); ================================================ FILE: packages/plugins/other/visitor-plugin-common/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'visitor-plugin-common', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/typescript/document-nodes/CHANGELOG.md ================================================ # @graphql-codegen/typescript-document-nodes ## 5.0.9 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-codegen/visitor-plugin-common@^6.2.3` ↗︎](https://www.npmjs.com/package/@graphql-codegen/visitor-plugin-common/v/6.2.3) (from `6.2.3`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 - @graphql-codegen/visitor-plugin-common@6.2.4 ## 5.0.8 ### Patch Changes - Updated dependencies [[`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf)]: - @graphql-codegen/visitor-plugin-common@6.2.3 ## 5.0.7 ### Patch Changes - Updated dependencies [[`f588d91`](https://github.com/dotansimha/graphql-code-generator/commit/f588d91ac43ea0aa5931915ce980d2e6876bb59c)]: - @graphql-codegen/visitor-plugin-common@6.2.2 ## 5.0.6 ### Patch Changes - Updated dependencies [[`b995ed1`](https://github.com/dotansimha/graphql-code-generator/commit/b995ed13a49379ea05e0e313fac68b557527523a)]: - @graphql-codegen/visitor-plugin-common@6.2.1 ## 5.0.5 ### Patch Changes - Updated dependencies [[`f821e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f821e8ab9351f23a9f7e5d5e6fc69c8e8868cad8), [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/visitor-plugin-common@6.2.0 - @graphql-codegen/plugin-helpers@6.1.0 ## 5.0.4 ### Patch Changes - Updated dependencies [[`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d)]: - @graphql-codegen/visitor-plugin-common@6.1.2 ## 5.0.3 ### Patch Changes - Updated dependencies [[`6715330`](https://github.com/dotansimha/graphql-code-generator/commit/67153304646694d75aee24afd70c3fce12e9f1f2)]: - @graphql-codegen/visitor-plugin-common@6.1.1 ## 5.0.2 ### Patch Changes - Updated dependencies [[`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26)]: - @graphql-codegen/visitor-plugin-common@6.1.0 ## 5.0.1 ### Patch Changes - Updated dependencies [[`accdab6`](https://github.com/dotansimha/graphql-code-generator/commit/accdab69106605241933e9d66d64dc7077656f30)]: - @graphql-codegen/visitor-plugin-common@6.0.1 ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/visitor-plugin-common@6.0.0 - @graphql-codegen/plugin-helpers@6.0.0 ## 4.0.16 ### Patch Changes - Updated dependencies [[`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc)]: - @graphql-codegen/visitor-plugin-common@5.8.0 ## 4.0.15 ### Patch Changes - Updated dependencies [[`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a)]: - @graphql-codegen/visitor-plugin-common@5.7.1 ## 4.0.14 ### Patch Changes - Updated dependencies [[`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c)]: - @graphql-codegen/visitor-plugin-common@5.7.0 ## 4.0.13 ### Patch Changes - Updated dependencies [[`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517)]: - @graphql-codegen/visitor-plugin-common@5.6.1 ## 4.0.12 ### Patch Changes - Updated dependencies [[`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a), [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba)]: - @graphql-codegen/visitor-plugin-common@5.6.0 ## 4.0.11 ### Patch Changes - Updated dependencies [[`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc), [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03)]: - @graphql-codegen/visitor-plugin-common@5.5.0 - @graphql-codegen/plugin-helpers@5.1.0 ## 4.0.10 ### Patch Changes - Updated dependencies [[`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4)]: - @graphql-codegen/visitor-plugin-common@5.4.0 ## 4.0.9 ### Patch Changes - Updated dependencies [[`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2)]: - @graphql-codegen/visitor-plugin-common@5.3.1 ## 4.0.8 ### Patch Changes - Updated dependencies [[`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3), [`14ce39e`](https://github.com/dotansimha/graphql-code-generator/commit/14ce39e41dfee38c652be736664177fa2b1df421)]: - @graphql-codegen/visitor-plugin-common@5.3.0 ## 4.0.7 ### Patch Changes - Updated dependencies [[`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431), [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e)]: - @graphql-codegen/plugin-helpers@5.0.4 - @graphql-codegen/visitor-plugin-common@5.2.0 ## 4.0.6 ### Patch Changes - Updated dependencies [[`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53), [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d)]: - @graphql-codegen/visitor-plugin-common@5.1.0 ## 4.0.5 ### Patch Changes - Updated dependencies [[`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5)]: - @graphql-codegen/visitor-plugin-common@5.0.0 ## 4.0.4 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/visitor-plugin-common@4.1.2 - @graphql-codegen/plugin-helpers@5.0.3 ## 4.0.3 ### Patch Changes - Updated dependencies [[`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f)]: - @graphql-codegen/visitor-plugin-common@4.1.1 ## 4.0.2 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 - @graphql-codegen/visitor-plugin-common@4.1.0 ## 4.0.1 ### Patch Changes - Updated dependencies [[`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a)]: - @graphql-codegen/visitor-plugin-common@4.0.1 ## 4.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96), [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c), [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d), [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0), [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c)]: - @graphql-codegen/plugin-helpers@5.0.0 - @graphql-codegen/visitor-plugin-common@4.0.0 ## 3.0.4 ### Patch Changes - Updated dependencies [[`386cf9044`](https://github.com/dotansimha/graphql-code-generator/commit/386cf9044a41d87ed45069b22d26b30f4b262a85), [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00)]: - @graphql-codegen/visitor-plugin-common@3.1.1 ## 3.0.3 ### Patch Changes - Updated dependencies [[`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835), [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087), [`acb647e4e`](https://github.com/dotansimha/graphql-code-generator/commit/acb647e4efbddecf732b6e55dc47ac40c9bdaf08), [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd)]: - @graphql-codegen/visitor-plugin-common@3.1.0 - @graphql-codegen/plugin-helpers@4.2.0 ## 3.0.2 ### Patch Changes - Updated dependencies [[`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a), [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc), [`b343626c9`](https://github.com/dotansimha/graphql-code-generator/commit/b343626c978b9ee0f14e314cea6c01ae3dad057c)]: - @graphql-codegen/visitor-plugin-common@3.0.2 ## 3.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 - @graphql-codegen/visitor-plugin-common@3.0.1 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/visitor-plugin-common@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 ## 2.3.13 ### Patch Changes - Updated dependencies [[`a98198524`](https://github.com/dotansimha/graphql-code-generator/commit/a9819852443884b43de7c15040ccffc205f9177a)]: - @graphql-codegen/visitor-plugin-common@2.13.8 ## 2.3.12 ### Patch Changes - Updated dependencies [[`eb454d06c`](https://github.com/dotansimha/graphql-code-generator/commit/eb454d06c977f11f7d4a7b0b07eb80f8fd590560)]: - @graphql-codegen/visitor-plugin-common@2.13.7 ## 2.3.11 ### Patch Changes - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 - @graphql-codegen/visitor-plugin-common@2.13.6 ## 2.3.10 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/visitor-plugin-common@2.13.5 ## 2.3.9 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/visitor-plugin-common@2.13.4 ## 2.3.8 ### Patch Changes - Updated dependencies [[`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe)]: - @graphql-codegen/visitor-plugin-common@2.13.3 ## 2.3.7 ### Patch Changes - Updated dependencies [[`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122)]: - @graphql-codegen/visitor-plugin-common@2.13.2 ## 2.3.6 ### Patch Changes - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/visitor-plugin-common@2.13.1 - @graphql-codegen/plugin-helpers@2.7.2 ## 2.3.5 ### Patch Changes - Updated dependencies [[`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b)]: - @graphql-codegen/visitor-plugin-common@2.13.0 ## 2.3.4 ### Patch Changes - Updated dependencies [[`1bd7f771c`](https://github.com/dotansimha/graphql-code-generator/commit/1bd7f771ccb949a5a37395c7c57cb41c19340714)]: - @graphql-codegen/visitor-plugin-common@2.12.2 ## 2.3.3 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f), [`47d0a57e2`](https://github.com/dotansimha/graphql-code-generator/commit/47d0a57e27dd0d2334670bfc6c81c45e00ff4e74)]: - @graphql-codegen/visitor-plugin-common@2.12.1 - @graphql-codegen/plugin-helpers@2.6.2 ## 2.3.2 ### Patch Changes - Updated dependencies [2cbcbb371] - @graphql-codegen/visitor-plugin-common@2.12.0 - @graphql-codegen/plugin-helpers@2.6.0 ## 2.3.1 ### Patch Changes - Updated dependencies [525ad580b] - @graphql-codegen/visitor-plugin-common@2.11.1 ## 2.3.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [68bb30e19] - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/visitor-plugin-common@2.11.0 - @graphql-codegen/plugin-helpers@2.5.0 ## 2.2.14 ### Patch Changes - Updated dependencies [aa1e6eafd] - Updated dependencies [a42fcbfe4] - Updated dependencies [8b10f22be] - @graphql-codegen/visitor-plugin-common@2.10.0 ## 2.2.13 ### Patch Changes - Updated dependencies [d16bebacb] - @graphql-codegen/visitor-plugin-common@2.9.1 ## 2.2.12 ### Patch Changes - Updated dependencies [c3d7b7226] - @graphql-codegen/visitor-plugin-common@2.9.0 ## 2.2.11 ### Patch Changes - Updated dependencies [f1fb77bd4] - @graphql-codegen/visitor-plugin-common@2.8.0 ## 2.2.10 ### Patch Changes - Updated dependencies [9a5f31cb6] - @graphql-codegen/visitor-plugin-common@2.7.6 ## 2.2.9 ### Patch Changes - Updated dependencies [2966686e9] - @graphql-codegen/visitor-plugin-common@2.7.5 ## 2.2.8 ### Patch Changes - Updated dependencies [337fd4f77] - @graphql-codegen/visitor-plugin-common@2.7.4 ## 2.2.7 ### Patch Changes - Updated dependencies [54718c039] - @graphql-codegen/visitor-plugin-common@2.7.3 ## 2.2.6 ### Patch Changes - Updated dependencies [11d05e361] - @graphql-codegen/visitor-plugin-common@2.7.2 ## 2.2.5 ### Patch Changes - Updated dependencies [fd55e2039] - @graphql-codegen/visitor-plugin-common@2.7.1 ## 2.2.4 ### Patch Changes - Updated dependencies [1479233df] - @graphql-codegen/visitor-plugin-common@2.7.0 ## 2.2.3 ### Patch Changes - Updated dependencies [c8ef37ae0] - Updated dependencies [754a33715] - Updated dependencies [bef4376d5] - Updated dependencies [be7cb3a82] - @graphql-codegen/visitor-plugin-common@2.6.0 - @graphql-codegen/plugin-helpers@2.4.0 ## 2.2.2 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/visitor-plugin-common@2.5.2 - @graphql-codegen/plugin-helpers@2.3.2 ## 2.2.1 ### Patch Changes - Updated dependencies [a9f1f1594] - Updated dependencies [9ea6621ec] - @graphql-codegen/visitor-plugin-common@2.5.1 ## 2.2.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/visitor-plugin-common@2.5.0 - @graphql-codegen/plugin-helpers@2.3.0 ## 2.1.6 ### Patch Changes - Updated dependencies [ad02cb9b8] - @graphql-codegen/visitor-plugin-common@2.4.0 ## 2.1.5 ### Patch Changes - Updated dependencies [b9e85adae] - Updated dependencies [7c60e5acc] - Updated dependencies [3c2c847be] - @graphql-codegen/visitor-plugin-common@2.3.0 - @graphql-codegen/plugin-helpers@2.2.0 ## 2.1.4 ### Patch Changes - Updated dependencies [0b090e31a] - @graphql-codegen/visitor-plugin-common@2.2.1 ## 2.1.3 ### Patch Changes - Updated dependencies [d6c2d4c09] - Updated dependencies [feeae1c66] - Updated dependencies [5086791ac] - @graphql-codegen/visitor-plugin-common@2.2.0 ## 2.1.2 ### Patch Changes - Updated dependencies [6470e6cc9] - Updated dependencies [263570e50] - Updated dependencies [35199dedf] - @graphql-codegen/visitor-plugin-common@2.1.2 - @graphql-codegen/plugin-helpers@2.1.1 ## 2.1.1 ### Patch Changes - Updated dependencies [aabeff181] - @graphql-codegen/visitor-plugin-common@2.1.1 ## 2.1.0 ### Minor Changes - 440172cfe: support ESM ### Patch Changes - Updated dependencies [290170262] - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/visitor-plugin-common@2.1.0 - @graphql-codegen/plugin-helpers@2.1.0 ## 2.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [d80efdec4] - Updated dependencies [d80efdec4] - Updated dependencies [b0cb13df4] - @graphql-codegen/visitor-plugin-common@2.0.0 - @graphql-codegen/plugin-helpers@2.0.0 ## 1.17.16 ### Patch Changes - Updated dependencies [df19a4ed] - Updated dependencies [470336a1] - Updated dependencies [9005cc17] - @graphql-codegen/visitor-plugin-common@1.22.0 - @graphql-codegen/plugin-helpers@1.18.8 ## 1.17.15 ### Patch Changes - Updated dependencies [6762aff5] - @graphql-codegen/visitor-plugin-common@1.21.3 ## 1.17.14 ### Patch Changes - Updated dependencies [6aaecf1c] - @graphql-codegen/visitor-plugin-common@1.21.2 ## 1.17.13 ### Patch Changes - Updated dependencies [cf1e5abc] - @graphql-codegen/visitor-plugin-common@1.21.1 ## 1.17.12 ### Patch Changes - Updated dependencies [dfd25caf] - Updated dependencies [8da7dff6] - @graphql-codegen/visitor-plugin-common@1.21.0 - @graphql-codegen/plugin-helpers@1.18.7 ## 1.17.11 ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - Updated dependencies [f0b5ea53] - Updated dependencies [097bea2f] - @graphql-codegen/visitor-plugin-common@1.20.0 - @graphql-codegen/plugin-helpers@1.18.5 ## 1.17.10 ### Patch Changes - 29b75b1e: enhance(docs): improve docs for naming convention - 29b75b1e: enhance(namingConvention): use change-case-all instead of individual packages for naming convention - Updated dependencies [e947f8e3] - Updated dependencies [29b75b1e] - Updated dependencies [d4942d04] - Updated dependencies [1f6f3db6] - Updated dependencies [29b75b1e] - @graphql-codegen/visitor-plugin-common@1.19.0 - @graphql-codegen/plugin-helpers@1.18.3 ## 1.17.9 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/visitor-plugin-common@1.17.20 - @graphql-codegen/plugin-helpers@1.18.2 ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/visitor-plugin-common@1.17.13 - @graphql-codegen/plugin-helpers@1.17.8 ================================================ FILE: packages/plugins/typescript/document-nodes/package.json ================================================ { "name": "@graphql-codegen/typescript-document-nodes", "version": "5.0.9", "description": "GraphQL Code Generator plugin for generating TypeScript modules with embedded GraphQL document nodes", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/typescript/document-nodes" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-codegen/visitor-plugin-common": "^6.2.4", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/typescript/document-nodes/src/index.ts ================================================ import { oldVisit, PluginFunction, PluginValidateFn, Types } from '@graphql-codegen/plugin-helpers'; import { LoadedFragment, NamingConvention, RawClientSideBasePluginConfig, } from '@graphql-codegen/visitor-plugin-common'; import { concatAST, FragmentDefinitionNode, GraphQLSchema, Kind } from 'graphql'; import { TypeScriptDocumentNodesVisitor } from './visitor.js'; /** * @description This plugin generates TypeScript source `.ts` file from GraphQL files `.graphql`. */ export interface TypeScriptDocumentNodesRawPluginConfig extends RawClientSideBasePluginConfig { /** * @default change-case-all#pascalCase * @description Allow you to override the naming convention of the output. * You can either override all namings, or specify an object with specific custom naming convention per output. * The format of the converter must be a valid `module#method`. * Allowed values for specific output are: `typeNames`, `enumValues`. * You can also use "keep" to keep all GraphQL names as-is. * Additionally, you can set `transformUnderscore` to `true` if you want to override the default behavior, * which is to preserve underscores. * * Available case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst` * [See more](https://github.com/btxtiger/change-case-all) * * @exampleMarkdown * ## Override All Names * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * namingConvention: 'change-case-all#lowerCase', * }, * }, * }, * }; * export default config; * ``` * * ## Upper-case enum values * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * namingConvention: { * typeNames: 'change-case-all#pascalCase', * enumValues: 'change-case-all#upperCase', * } * }, * }, * }, * }; * export default config; * ``` * * ## Keep names as is * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * namingConvention: 'keep', * }, * }, * }, * }; * export default config; * ``` * * ## Remove Underscores * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file': { * // plugins... * config: { * namingConvention: { * typeNames: 'change-case-all#pascalCase', * transformUnderscore: true * } * }, * }, * }, * }; * export default config; * ``` */ namingConvention?: NamingConvention; /** * @default "" * @description Adds prefix to the name * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'src/api/user-service/queries.ts': { * plugins: ['typescript-document-nodes'], * config: { * namePrefix: 'gql', * }, * }, * }, * }; * export default config; * ``` */ namePrefix?: string; /** * @default "" * @description Adds suffix to the name * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'src/api/user-service/queries.ts': { * plugins: ['typescript-document-nodes'], * config: { * nameSuffix: 'Query' * }, * }, * }, * }; * export default config; * ``` */ nameSuffix?: string; /** * @default "" * @description Adds prefix to the fragment variable */ fragmentPrefix?: string; /** * @default "" * @description Adds suffix to the fragment variable */ fragmentSuffix?: string; } export const plugin: PluginFunction = ( schema: GraphQLSchema, documents: Types.DocumentFile[], config: TypeScriptDocumentNodesRawPluginConfig ) => { const allAst = concatAST(documents.map(v => v.document)); const allFragments: LoadedFragment[] = [ ...(allAst.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION) as FragmentDefinitionNode[]).map( fragmentDef => ({ node: fragmentDef, name: fragmentDef.name.value, onType: fragmentDef.typeCondition.name.value, isExternal: false, }) ), ...(config.externalFragments || []), ]; const visitor = new TypeScriptDocumentNodesVisitor(schema, allFragments, config, documents); const visitorResult = oldVisit(allAst, { leave: visitor }); return { prepend: visitor.getImports(), content: [visitor.fragments, ...visitorResult.definitions.filter(t => typeof t === 'string')].join('\n'), }; }; export const validate: PluginValidateFn = async ( schema: GraphQLSchema, documents: Types.DocumentFile[], config: any, outputFile: string ) => { if (!outputFile.endsWith('.ts')) { throw new Error(`Plugin "typescript-document-nodes" requires extension to be ".ts"!`); } }; ================================================ FILE: packages/plugins/typescript/document-nodes/src/visitor.ts ================================================ import { Types } from '@graphql-codegen/plugin-helpers'; import { ClientSideBasePluginConfig, ClientSideBaseVisitor, getConfigValue, LoadedFragment, NamingConvention, } from '@graphql-codegen/visitor-plugin-common'; import autoBind from 'auto-bind'; import { GraphQLSchema } from 'graphql'; import { TypeScriptDocumentNodesRawPluginConfig } from './index.js'; export interface TypeScriptDocumentNodesPluginConfig extends ClientSideBasePluginConfig { namingConvention: NamingConvention; transformUnderscore: boolean; } export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor< TypeScriptDocumentNodesRawPluginConfig, TypeScriptDocumentNodesPluginConfig > { constructor( schema: GraphQLSchema, fragments: LoadedFragment[], rawConfig: TypeScriptDocumentNodesRawPluginConfig, documents: Types.DocumentFile[] ) { const additionalConfig = { documentVariablePrefix: getConfigValue(rawConfig.namePrefix, ''), documentVariableSuffix: getConfigValue(rawConfig.nameSuffix, ''), fragmentVariablePrefix: getConfigValue(rawConfig.fragmentPrefix, ''), fragmentVariableSuffix: getConfigValue(rawConfig.fragmentSuffix, ''), }; super(schema, fragments, rawConfig, additionalConfig, documents); autoBind(this); } } ================================================ FILE: packages/plugins/typescript/document-nodes/tests/graphql-document-nodes.spec.ts ================================================ import { mergeOutputs, Types } from '@graphql-codegen/plugin-helpers'; import { validateTs } from '@graphql-codegen/testing'; import { parse } from 'graphql'; import { plugin } from '../src/index.js'; describe('graphql-codegen typescript-graphql-document-nodes', () => { it('Should generate simple module with one file', async () => { const result = plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query MyQuery { field } `), }, ], {}, { outputFile: '' } ) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const MyQuery = gql\` query MyQuery { field } \`; `); validateTs(mergeOutputs([result])); }); it('Should generate correctly for mutiple files', async () => { const result = (await plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query MyQuery { field } `), }, { location: 'some/file/my-other-query.graphql', document: parse(/* GraphQL */ ` query OtherQuery { field } `), }, ], {}, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const MyQuery = gql\` query MyQuery { field } \`; export const OtherQuery = gql\` query OtherQuery { field } \`; `); validateTs(mergeOutputs([result])); }); it('Should ignore unnamed documents', async () => { const result = (await plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query { field } `), }, ], {}, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(''); validateTs(mergeOutputs([result])); }); it('Should generate simple module with two documents in one file', async () => { const result = (await plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query MyQuery { field } query OtherQuery { field } `), }, ], {}, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const MyQuery = gql\` query MyQuery { field } \`; export const OtherQuery = gql\` query OtherQuery { field } \`; `); validateTs(mergeOutputs([result])); }); it('Should generate module with a name as a camel case', async () => { const result = plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query MyQuery { field } `), }, ], { namingConvention: 'change-case-all#camelCase' }, { outputFile: '' } ) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const myQuery = gql\` query MyQuery { field } \`; `); validateTs(mergeOutputs([result])); }); it('Should generate module with a name as a pascal case with underscores', async () => { const result = plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query My_Query { field } `), }, ], { namingConvention: 'change-case-all#pascalCase', transformUnderscore: false } as any, { outputFile: '' } ) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const My_Query = gql\` query My_Query { field } \`; `); validateTs(mergeOutputs([result])); }); it('Should generate module with a name as a pascal case without underscores', async () => { const result = plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query My_Query { field } `), }, ], { namingConvention: { typeNames: 'change-case-all#pascalCase', transformUnderscore: true, }, }, { outputFile: '' } ) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const MyQuery = gql\` query My_Query { field } \`; `); validateTs(mergeOutputs([result])); }); it('Should generate module with a name as a contant case', async () => { const result = plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query MyQuery { field } `), }, ], { namingConvention: 'change-case-all#constantCase' }, { outputFile: '' } ) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const MY_QUERY = gql\` query MyQuery { field } \`; `); validateTs(mergeOutputs([result])); }); it('Should generate module with prefix for a name', async () => { const result = plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query MyQuery { field } `), }, ], { namePrefix: 'Graphql' }, { outputFile: '' } ) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const GraphqlMyQuery = gql\` query MyQuery { field } \`; `); validateTs(mergeOutputs([result])); }); it('Should generate module with suffix for a name', async () => { const result = plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` query MyQuery { field } `), }, ], { nameSuffix: 'Query' }, { outputFile: '' } ) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const MyQueryQuery = gql\` query MyQuery { field } \`; `); validateTs(mergeOutputs([result])); }); it('should contain fragment definitions', async () => { const result = plugin( null, [ { location: 'some/file/my-query.graphql', document: parse(/* GraphQL */ ` # Put your operations here fragment fragment1 on User { id username } query user { user(id: 1) { ...fragment1 } } query user2 { user2: user(id: 1) { ...fragment1 email } } `), }, ], {}, { outputFile: '' } ) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const Fragment1 = gql\` fragment fragment1 on User { id username } \`; export const User = gql\` query user { user(id: 1) { ...fragment1 } } \${Fragment1}\`; export const User2 = gql\` query user2 { user2: user(id: 1) { ...fragment1 email } } \${Fragment1}\`; `); validateTs(mergeOutputs([result])); }); }); ================================================ FILE: packages/plugins/typescript/document-nodes/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'typescript-document-nodes', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/typescript/gql-tag-operations/CHANGELOG.md ================================================ # @graphql-codegen/gql-tag-operations ## 5.1.4 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^11.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/11.0.0) (from `^10.0.0`, in `dependencies`) - Updated dependency [`@graphql-codegen/visitor-plugin-common@^6.2.3` ↗︎](https://www.npmjs.com/package/@graphql-codegen/visitor-plugin-common/v/6.2.3) (from `6.2.3`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 - @graphql-codegen/visitor-plugin-common@6.2.4 ## 5.1.3 ### Patch Changes - Updated dependencies [[`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf)]: - @graphql-codegen/visitor-plugin-common@6.2.3 ## 5.1.2 ### Patch Changes - Updated dependencies [[`f588d91`](https://github.com/dotansimha/graphql-code-generator/commit/f588d91ac43ea0aa5931915ce980d2e6876bb59c)]: - @graphql-codegen/visitor-plugin-common@6.2.2 ## 5.1.1 ### Patch Changes - Updated dependencies [[`b995ed1`](https://github.com/dotansimha/graphql-code-generator/commit/b995ed13a49379ea05e0e313fac68b557527523a)]: - @graphql-codegen/visitor-plugin-common@6.2.1 ## 5.1.0 ### Minor Changes - [#10510](https://github.com/dotansimha/graphql-code-generator/pull/10510) [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670) Thanks [@nickmessing](https://github.com/nickmessing)! - add importExtension configuration option ### Patch Changes - Updated dependencies [[`f821e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f821e8ab9351f23a9f7e5d5e6fc69c8e8868cad8), [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/visitor-plugin-common@6.2.0 - @graphql-codegen/plugin-helpers@6.1.0 ## 5.0.5 ### Patch Changes - Updated dependencies [[`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d)]: - @graphql-codegen/visitor-plugin-common@6.1.2 ## 5.0.4 ### Patch Changes - Updated dependencies [[`6715330`](https://github.com/dotansimha/graphql-code-generator/commit/67153304646694d75aee24afd70c3fce12e9f1f2)]: - @graphql-codegen/visitor-plugin-common@6.1.1 ## 5.0.3 ### Patch Changes - [#10032](https://github.com/dotansimha/graphql-code-generator/pull/10032) [`1debf51`](https://github.com/dotansimha/graphql-code-generator/commit/1debf51aa714e2a53256419c549f6770b6c894a6) Thanks [@shota-tech](https://github.com/shota-tech)! - Change map of operations from an empty array to an empty object when no operations are found ## 5.0.2 ### Patch Changes - Updated dependencies [[`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26)]: - @graphql-codegen/visitor-plugin-common@6.1.0 ## 5.0.1 ### Patch Changes - Updated dependencies [[`accdab6`](https://github.com/dotansimha/graphql-code-generator/commit/accdab69106605241933e9d66d64dc7077656f30)]: - @graphql-codegen/visitor-plugin-common@6.0.1 ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/visitor-plugin-common@6.0.0 - @graphql-codegen/plugin-helpers@6.0.0 ## 4.0.17 ### Patch Changes - Updated dependencies [[`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc)]: - @graphql-codegen/visitor-plugin-common@5.8.0 ## 4.0.16 ### Patch Changes - Updated dependencies [[`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a)]: - @graphql-codegen/visitor-plugin-common@5.7.1 ## 4.0.15 ### Patch Changes - Updated dependencies [[`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c)]: - @graphql-codegen/visitor-plugin-common@5.7.0 ## 4.0.14 ### Patch Changes - [#10192](https://github.com/dotansimha/graphql-code-generator/pull/10192) [`ec07018`](https://github.com/dotansimha/graphql-code-generator/commit/ec070189a1a3c4d41f2457b56a68b506c81f28ba) Thanks [@brianhuang822](https://github.com/brianhuang822)! - Have gql-tag-operations generate the type for document registry ## 4.0.13 ### Patch Changes - Updated dependencies [[`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517)]: - @graphql-codegen/visitor-plugin-common@5.6.1 ## 4.0.12 ### Patch Changes - Updated dependencies [[`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a), [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba)]: - @graphql-codegen/visitor-plugin-common@5.6.0 ## 4.0.11 ### Patch Changes - Updated dependencies [[`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc), [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03)]: - @graphql-codegen/visitor-plugin-common@5.5.0 - @graphql-codegen/plugin-helpers@5.1.0 ## 4.0.10 ### Patch Changes - [#10075](https://github.com/dotansimha/graphql-code-generator/pull/10075) [`67e7556`](https://github.com/dotansimha/graphql-code-generator/commit/67e75561a3e862f26cfbb40e8ec5a08f821f9ddf) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Add note about enabling bundle size reduction for the generated `graphql` tag file. - Updated dependencies [[`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4)]: - @graphql-codegen/visitor-plugin-common@5.4.0 ## 4.0.9 ### Patch Changes - Updated dependencies [[`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2)]: - @graphql-codegen/visitor-plugin-common@5.3.1 ## 4.0.8 ### Patch Changes - Updated dependencies [[`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3), [`14ce39e`](https://github.com/dotansimha/graphql-code-generator/commit/14ce39e41dfee38c652be736664177fa2b1df421)]: - @graphql-codegen/visitor-plugin-common@5.3.0 ## 4.0.7 ### Patch Changes - Updated dependencies [[`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431), [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e)]: - @graphql-codegen/plugin-helpers@5.0.4 - @graphql-codegen/visitor-plugin-common@5.2.0 ## 4.0.6 ### Patch Changes - Updated dependencies [[`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53), [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d)]: - @graphql-codegen/visitor-plugin-common@5.1.0 ## 4.0.5 ### Patch Changes - Updated dependencies [[`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5)]: - @graphql-codegen/visitor-plugin-common@5.0.0 ## 4.0.4 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/visitor-plugin-common@4.1.2 - @graphql-codegen/plugin-helpers@5.0.3 ## 4.0.3 ### Patch Changes - Updated dependencies [[`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f)]: - @graphql-codegen/visitor-plugin-common@4.1.1 ## 4.0.2 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 - @graphql-codegen/visitor-plugin-common@4.1.0 ## 4.0.1 ### Patch Changes - Updated dependencies [[`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a)]: - @graphql-codegen/visitor-plugin-common@4.0.1 ## 4.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/10.0.0) (from `^9.0.0`, in `dependencies`) - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96), [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c), [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d), [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0), [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c)]: - @graphql-codegen/plugin-helpers@5.0.0 - @graphql-codegen/visitor-plugin-common@4.0.0 ## 3.0.1 ### Patch Changes - Updated dependencies [[`386cf9044`](https://github.com/dotansimha/graphql-code-generator/commit/386cf9044a41d87ed45069b22d26b30f4b262a85), [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00)]: - @graphql-codegen/visitor-plugin-common@3.1.1 ## 3.0.0 ### Major Changes - [#9137](https://github.com/dotansimha/graphql-code-generator/pull/9137) [`2256c8b5d`](https://github.com/dotansimha/graphql-code-generator/commit/2256c8b5d0e13057d35692bbeba3b7b8f94d8712) Thanks [@beerose](https://github.com/beerose)! - Add `TypedDocumentNode` string alternative that doesn't require GraphQL AST on the client. This change requires `@graphql-typed-document-node/core` in version `3.2.0` or higher. ### Patch Changes - Updated dependencies [[`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835), [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087), [`acb647e4e`](https://github.com/dotansimha/graphql-code-generator/commit/acb647e4efbddecf732b6e55dc47ac40c9bdaf08), [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd)]: - @graphql-codegen/visitor-plugin-common@3.1.0 - @graphql-codegen/plugin-helpers@4.2.0 ## 2.0.2 ### Patch Changes - Updated dependencies [[`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a), [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc), [`b343626c9`](https://github.com/dotansimha/graphql-code-generator/commit/b343626c978b9ee0f14e314cea6c01ae3dad057c)]: - @graphql-codegen/visitor-plugin-common@3.0.2 ## 2.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - [#8995](https://github.com/dotansimha/graphql-code-generator/pull/8995) [`fe2e9c7a5`](https://github.com/dotansimha/graphql-code-generator/commit/fe2e9c7a5f2731e06dd285e391936608dfa3fb51) Thanks [@charpeni](https://github.com/charpeni)! - Use `gqlTagName` for generated examples - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 - @graphql-codegen/visitor-plugin-common@3.0.1 ## 2.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/visitor-plugin-common@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 ## 1.6.2 ### Patch Changes - Updated dependencies [[`a98198524`](https://github.com/dotansimha/graphql-code-generator/commit/a9819852443884b43de7c15040ccffc205f9177a)]: - @graphql-codegen/visitor-plugin-common@2.13.8 ## 1.6.1 ### Patch Changes - [#8796](https://github.com/dotansimha/graphql-code-generator/pull/8796) [`902451601`](https://github.com/dotansimha/graphql-code-generator/commit/902451601b5edf9cb7768e57f332fe6ade79c20a) Thanks [@shmax](https://github.com/shmax)! - remove extra asterisk and add missing semicolon in generated output ## 1.6.0 ### Minor Changes - [#8763](https://github.com/dotansimha/graphql-code-generator/pull/8763) [`2a33fc774`](https://github.com/dotansimha/graphql-code-generator/commit/2a33fc7741f7a9532bef68606666d4e3db7785a3) Thanks [@ElvisUpUp](https://github.com/ElvisUpUp)! - change the client-preset generated template ### Patch Changes - Updated dependencies [[`eb454d06c`](https://github.com/dotansimha/graphql-code-generator/commit/eb454d06c977f11f7d4a7b0b07eb80f8fd590560)]: - @graphql-codegen/visitor-plugin-common@2.13.7 ## 1.5.12 ### Patch Changes - [#8771](https://github.com/dotansimha/graphql-code-generator/pull/8771) [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.8.0`, in `dependencies`) - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 - @graphql-codegen/visitor-plugin-common@2.13.6 ## 1.5.11 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/visitor-plugin-common@2.13.5 ## 1.5.10 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/visitor-plugin-common@2.13.4 ## 1.5.9 ### Patch Changes - Updated dependencies [[`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe)]: - @graphql-codegen/visitor-plugin-common@2.13.3 ## 1.5.8 ### Patch Changes - [#8633](https://github.com/dotansimha/graphql-code-generator/pull/8633) [`00ddc9368`](https://github.com/dotansimha/graphql-code-generator/commit/00ddc9368211a4511b9f80d543d57c85fff840cb) Thanks [@jantimon](https://github.com/jantimon)! - provide jsdoc comments for better IDE support ## 1.5.7 ### Patch Changes - Updated dependencies [[`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122)]: - @graphql-codegen/visitor-plugin-common@2.13.2 ## 1.5.6 ### Patch Changes - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/visitor-plugin-common@2.13.1 - @graphql-codegen/plugin-helpers@2.7.2 ## 1.5.5 ### Patch Changes - Updated dependencies [[`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b)]: - @graphql-codegen/visitor-plugin-common@2.13.0 ## 1.5.4 ### Patch Changes - Updated dependencies [[`1bd7f771c`](https://github.com/dotansimha/graphql-code-generator/commit/1bd7f771ccb949a5a37395c7c57cb41c19340714)]: - @graphql-codegen/visitor-plugin-common@2.12.2 ## 1.5.3 ### Patch Changes - [#8443](https://github.com/dotansimha/graphql-code-generator/pull/8443) [`e2d115146`](https://github.com/dotansimha/graphql-code-generator/commit/e2d11514695ca56674983e8b3b7549cd3b440a5d) Thanks [@charlypoly](https://github.com/charlypoly)! - fix(gql-tag-operations): issues with "no documents" scenario ## 1.5.2 ### Patch Changes - [#8402](https://github.com/dotansimha/graphql-code-generator/pull/8402) [`a76c606e3`](https://github.com/dotansimha/graphql-code-generator/commit/a76c606e3b631ef903d4066e2643bc7f95457e30) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Removed dependency [`graphql-tag@^2.0.0` ↗︎](https://www.npmjs.com/package/graphql-tag/v/2.0.0) (from `peerDependencies`) ## 1.5.1 ### Patch Changes - [#8401](https://github.com/dotansimha/graphql-code-generator/pull/8401) [`4be3dc884`](https://github.com/dotansimha/graphql-code-generator/commit/4be3dc884bebe30e75b91560820d5604c816d9dd) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Removed dependency [`graphql-tag@^2.0.0` ↗︎](https://www.npmjs.com/package/graphql-tag/v/2.0.0) (from `peerDependencies`) - [#8401](https://github.com/dotansimha/graphql-code-generator/pull/8401) [`4be3dc884`](https://github.com/dotansimha/graphql-code-generator/commit/4be3dc884bebe30e75b91560820d5604c816d9dd) Thanks [@charlypoly](https://github.com/charlypoly)! - Remove unused `graphql-tag` peer dependency ## 1.5.0 ### Minor Changes - [#8302](https://github.com/dotansimha/graphql-code-generator/pull/8302) [`876844e76`](https://github.com/dotansimha/graphql-code-generator/commit/876844e7644a917172f09b3c4eb54a2f4c90e4c6) Thanks [@charlypoly](https://github.com/charlypoly)! - **`@graphql-codegen/gql-tag-operations` and `@graphql-codegen/gql-tag-operations-preset`** Introduce a `gqlTagName` configuration option *** **`@graphql-codegen/client-preset`** New preset for GraphQL Code Generator v3, more information on the RFC: https://github.com/dotansimha/graphql-code-generator/issues/8296 *** **`@graphql-codegen/cli`** Update init wizard with 3.0 recommendations (`codegen.ts`, `client` preset) ## 1.4.1 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f), [`47d0a57e2`](https://github.com/dotansimha/graphql-code-generator/commit/47d0a57e27dd0d2334670bfc6c81c45e00ff4e74)]: - @graphql-codegen/visitor-plugin-common@2.12.1 - @graphql-codegen/plugin-helpers@2.6.2 ## 1.4.0 ### Minor Changes - 2cbcbb371: Add new flag to emit legacy common js imports. Default it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065). You can use the option in your config: ```yaml schema: 'schema.graphql' documents: - 'src/**/*.graphql' emitLegacyCommonJSImports: true ``` Alternative you can use the CLI to set this option: ```bash $ codegen --config-file=config.yml --emit-legacy-common-js-imports ``` ### Patch Changes - Updated dependencies [2cbcbb371] - @graphql-codegen/visitor-plugin-common@2.12.0 - @graphql-codegen/plugin-helpers@2.6.0 ## 1.3.1 ### Patch Changes - 525ad580b: Revert breaking change for Next.js applications that are incapable of resolving an import with a `.js` extension. - Updated dependencies [525ad580b] - @graphql-codegen/visitor-plugin-common@2.11.1 ## 1.3.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [68bb30e19] - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/visitor-plugin-common@2.11.0 - @graphql-codegen/plugin-helpers@2.5.0 ## 1.2.17 ### Patch Changes - Updated dependencies [aa1e6eafd] - Updated dependencies [a42fcbfe4] - Updated dependencies [8b10f22be] - @graphql-codegen/visitor-plugin-common@2.10.0 ## 1.2.16 ### Patch Changes - Updated dependencies [d16bebacb] - @graphql-codegen/visitor-plugin-common@2.9.1 ## 1.2.15 ### Patch Changes - Updated dependencies [c3d7b7226] - @graphql-codegen/visitor-plugin-common@2.9.0 ## 1.2.14 ### Patch Changes - Updated dependencies [f1fb77bd4] - @graphql-codegen/visitor-plugin-common@2.8.0 ## 1.2.13 ### Patch Changes - Updated dependencies [9a5f31cb6] - @graphql-codegen/visitor-plugin-common@2.7.6 ## 1.2.12 ### Patch Changes - Updated dependencies [2966686e9] - @graphql-codegen/visitor-plugin-common@2.7.5 ## 1.2.11 ### Patch Changes - Updated dependencies [337fd4f77] - @graphql-codegen/visitor-plugin-common@2.7.4 ## 1.2.10 ### Patch Changes - Updated dependencies [54718c039] - @graphql-codegen/visitor-plugin-common@2.7.3 ## 1.2.9 ### Patch Changes - Updated dependencies [11d05e361] - @graphql-codegen/visitor-plugin-common@2.7.2 ## 1.2.8 ### Patch Changes - Updated dependencies [fd55e2039] - @graphql-codegen/visitor-plugin-common@2.7.1 ## 1.2.7 ### Patch Changes - Updated dependencies [1479233df] - @graphql-codegen/visitor-plugin-common@2.7.0 ## 1.2.6 ### Patch Changes - Updated dependencies [c8ef37ae0] - Updated dependencies [754a33715] - Updated dependencies [bef4376d5] - Updated dependencies [be7cb3a82] - @graphql-codegen/visitor-plugin-common@2.6.0 - @graphql-codegen/plugin-helpers@2.4.0 ## 1.2.5 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/visitor-plugin-common@2.5.2 - @graphql-codegen/plugin-helpers@2.3.2 ## 1.2.4 ### Patch Changes - Updated dependencies [a9f1f1594] - Updated dependencies [9ea6621ec] - @graphql-codegen/visitor-plugin-common@2.5.1 ## 1.2.3 ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/visitor-plugin-common@2.5.0 - @graphql-codegen/plugin-helpers@2.3.0 ## 1.2.2 ### Patch Changes - Updated dependencies [ad02cb9b8] - @graphql-codegen/visitor-plugin-common@2.4.0 ## 1.2.1 ### Patch Changes - Updated dependencies [b9e85adae] - Updated dependencies [7c60e5acc] - Updated dependencies [3c2c847be] - @graphql-codegen/visitor-plugin-common@2.3.0 - @graphql-codegen/plugin-helpers@2.2.0 ## 1.2.0 ### Minor Changes - 1e9a7e162: feat: support module augumentation for extending the types of gql functions from existing packages via the `augmentedModuleName` config option. ## 1.1.5 ### Patch Changes - 06dfd3958: fix: follow "useTypeImports" configuration - 5394f19bb: prevent duplicate operations ## 1.1.4 ### Patch Changes - Updated dependencies [0b090e31a] - @graphql-codegen/visitor-plugin-common@2.2.1 ## 1.1.3 ### Patch Changes - Updated dependencies [d6c2d4c09] - Updated dependencies [feeae1c66] - Updated dependencies [5086791ac] - @graphql-codegen/visitor-plugin-common@2.2.0 ## 1.1.2 ### Patch Changes - Updated dependencies [6470e6cc9] - Updated dependencies [263570e50] - Updated dependencies [35199dedf] - @graphql-codegen/visitor-plugin-common@2.1.2 - @graphql-codegen/plugin-helpers@2.1.1 ## 1.1.1 ### Patch Changes - Updated dependencies [aabeff181] - @graphql-codegen/visitor-plugin-common@2.1.1 ## 1.1.0 ### Minor Changes - 0c0c8a92b: export new utility type `DocumentType`, for accessing the document node type. ```tsx import { gql, DocumentType } from '../gql' const TweetFragment = gql(/* GraphQL */ ` fragment TweetFragment on Tweet { id body } `) const Tweet = (props: { tweet: DocumentType }) => { return
    {props.body}
    } ``` - 440172cfe: support ESM ### Patch Changes - 24185985a: bump graphql-tools package versions - Updated dependencies [290170262] - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/visitor-plugin-common@2.1.0 - @graphql-codegen/plugin-helpers@2.1.0 ## 1.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Minor Changes - b0cb13df4: new plugin/preset gql-tag-operations ### Patch Changes - Updated dependencies [d80efdec4] - Updated dependencies [d80efdec4] - Updated dependencies [b0cb13df4] - @graphql-codegen/visitor-plugin-common@2.0.0 - @graphql-codegen/plugin-helpers@2.0.0 ================================================ FILE: packages/plugins/typescript/gql-tag-operations/package.json ================================================ { "name": "@graphql-codegen/gql-tag-operations", "version": "5.1.4", "description": "GraphQL Code Generator plugin for generating a typed gql tag function", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/typescript/gql-tag-operations" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "dependencies": { "@graphql-tools/utils": "^11.0.0", "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-codegen/visitor-plugin-common": "^6.2.4", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/typescript/gql-tag-operations/src/index.ts ================================================ import { normalizeImportExtension, PluginFunction } from '@graphql-codegen/plugin-helpers'; import { DocumentMode } from '@graphql-codegen/visitor-plugin-common'; import { Source } from '@graphql-tools/utils'; import { FragmentDefinitionNode, OperationDefinitionNode } from 'graphql'; export type OperationOrFragment = { initialName: string; definition: OperationDefinitionNode | FragmentDefinitionNode; }; export type SourceWithOperations = { source: Source; operations: Array; }; const documentTypePartial = ` export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any > ? TType : never; `.split(`\n`); export const plugin: PluginFunction<{ sourcesWithOperations: Array; useTypeImports?: boolean; augmentedModuleName?: string; gqlTagName?: string; emitLegacyCommonJSImports?: boolean; importExtension?: '' | `.${string}`; documentMode?: DocumentMode; }> = ( _, __, { sourcesWithOperations, useTypeImports, augmentedModuleName, gqlTagName = 'gql', emitLegacyCommonJSImports, importExtension, documentMode, }, _info ) => { const appendedImportExtension = normalizeImportExtension({ emitLegacyCommonJSImports, importExtension, }); if (documentMode === DocumentMode.string) { const code = [`import * as types from './graphql${appendedImportExtension}';\n`, `\n`]; // We need the mapping from source as written to full document source to // handle fragments. An identity function would not suffice. if (sourcesWithOperations.length > 0) { code.push([...getDocumentRegistryChunk(sourcesWithOperations)].join('')); } else { code.push('const documents = {}'); } if (sourcesWithOperations.length > 0) { code.push( [...getGqlOverloadChunk(sourcesWithOperations, gqlTagName, 'augmented', appendedImportExtension), `\n`].join('') ); } code.push( [`export function ${gqlTagName}(source: string) {\n`, ` return (documents as any)[source] ?? {};\n`, `}\n`].join( '' ) ); return code.join('\n'); } if (augmentedModuleName == null) { const code = [ `import * as types from './graphql${appendedImportExtension}';\n`, `${ useTypeImports ? 'import type' : 'import' } { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';\n`, `\n`, ]; if (sourcesWithOperations.length > 0) { code.push([...getDocumentRegistryChunk(sourcesWithOperations)].join('')); } else { code.push('const documents = {};'); } code.push( [ `\n`, `/**\n * The ${gqlTagName} function is used to parse GraphQL queries into a document that can be used by GraphQL clients.\n *\n`, ` *\n * @example\n`, ' * ```ts\n', ` * const query = ${gqlTagName}` + '(`query GetUser($id: ID!) { user(id: $id) { name } }`);\n', ' * ```\n *\n', ` * The query argument is unknown!\n`, ` * Please regenerate the types.\n`, ` */\n`, `export function ${gqlTagName}(source: string): unknown;\n`, `\n`, ].join('') ); if (sourcesWithOperations.length > 0) { code.push( [...getGqlOverloadChunk(sourcesWithOperations, gqlTagName, 'lookup', appendedImportExtension), `\n`].join('') ); } code.push( [ `export function ${gqlTagName}(source: string) {\n`, ` return (documents as any)[source] ?? {};\n`, `}\n`, `\n`, ...documentTypePartial, ].join('') ); return code.join(''); } return [ `import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';\n`, `declare module "${augmentedModuleName}" {`, [ `\n`, ...(sourcesWithOperations.length > 0 ? getGqlOverloadChunk(sourcesWithOperations, gqlTagName, 'augmented', appendedImportExtension) : []), `export function ${gqlTagName}(source: string): unknown;\n`, `\n`, ...documentTypePartial, ] .map(line => (line === `\n` ? line : ` ${line}`)) .join(``), `}`, ].join(`\n`); }; function getDocumentRegistryChunk(sourcesWithOperations: Array = []) { const lines = new Array(); // It's possible for there to be duplicate sourceOperations, this set will ensure we have unique records for our document registry const linesDupCheck = new Set(); lines.push( `/**\n * Map of all GraphQL operations in the project.\n *\n * This map has several performance disadvantages:\n`, ` * 1. It is not tree-shakeable, so it will include all operations in the project.\n`, ` * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.\n`, ` * 3. It does not support dead code elimination, so it will add unused operations.\n *\n`, ` * Therefore it is highly recommended to use the babel or swc plugin for production.\n`, ` * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size\n */\n`, `type Documents = {\n` ); for (const { operations, ...rest } of sourcesWithOperations) { const originalString = rest.source.rawSDL; const operation = operations[0]; const aboutToPushLine = ` ${JSON.stringify(originalString)}: typeof types.${operation.initialName},\n`; if (!linesDupCheck.has(aboutToPushLine)) { lines.push(aboutToPushLine); linesDupCheck.add(aboutToPushLine); } } lines.push(`};\n`, `const documents: Documents = {\n`); for (const { operations, ...rest } of sourcesWithOperations) { const originalString = rest.source.rawSDL!; const operation = operations[0]; const aboutToPushLine = ` ${JSON.stringify(originalString)}: types.${operation.initialName},\n`; if (!linesDupCheck.has(aboutToPushLine)) { lines.push(aboutToPushLine); linesDupCheck.add(aboutToPushLine); } } lines.push(`};\n`); return lines; } type Mode = 'lookup' | 'augmented'; function getGqlOverloadChunk( sourcesWithOperations: Array, gqlTagName: string, mode: Mode, importExtension: '' | `.${string}` ) { const lines = new Set(); // We intentionally don't use a generic, because TS // would print very long `gql` function signatures (duplicating the source). for (const { operations, ...rest } of sourcesWithOperations) { const originalString = rest.source.rawSDL!; const returnType = mode === 'lookup' ? `(typeof documents)[${JSON.stringify(originalString)}]` : `typeof import('./graphql${importExtension}').${operations[0].initialName}`; lines.add( `/**\n * The ${gqlTagName} function is used to parse GraphQL queries into a document that can be used by GraphQL clients.\n */\n` + `export function ${gqlTagName}(source: ${JSON.stringify(originalString)}): ${returnType};\n` ); } return lines; } ================================================ FILE: packages/plugins/typescript/gql-tag-operations/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'gql-tag-operations', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/typescript/operations/CHANGELOG.md ================================================ # @graphql-codegen/typescript-operations ## 5.0.9 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-codegen/visitor-plugin-common@^6.2.3` ↗︎](https://www.npmjs.com/package/@graphql-codegen/visitor-plugin-common/v/6.2.3) (from `6.2.3`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 - @graphql-codegen/typescript@5.0.9 - @graphql-codegen/visitor-plugin-common@6.2.4 ## 5.0.8 ### Patch Changes - [#10580](https://github.com/dotansimha/graphql-code-generator/pull/10580) [`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf) Thanks [@Georgegriff](https://github.com/Georgegriff)! - fixed invalid extracted concrete type name on shared interface - Updated dependencies [[`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf)]: - @graphql-codegen/visitor-plugin-common@6.2.3 - @graphql-codegen/typescript@5.0.8 ## 5.0.7 ### Patch Changes - Updated dependencies [[`f588d91`](https://github.com/dotansimha/graphql-code-generator/commit/f588d91ac43ea0aa5931915ce980d2e6876bb59c)]: - @graphql-codegen/visitor-plugin-common@6.2.2 - @graphql-codegen/typescript@5.0.7 ## 5.0.6 ### Patch Changes - Updated dependencies [[`b995ed1`](https://github.com/dotansimha/graphql-code-generator/commit/b995ed13a49379ea05e0e313fac68b557527523a)]: - @graphql-codegen/visitor-plugin-common@6.2.1 - @graphql-codegen/typescript@5.0.6 ## 5.0.5 ### Patch Changes - Updated dependencies [[`f821e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f821e8ab9351f23a9f7e5d5e6fc69c8e8868cad8), [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/visitor-plugin-common@6.2.0 - @graphql-codegen/plugin-helpers@6.1.0 - @graphql-codegen/typescript@5.0.5 ## 5.0.4 ### Patch Changes - Updated dependencies [[`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d)]: - @graphql-codegen/visitor-plugin-common@6.1.2 - @graphql-codegen/typescript@5.0.4 ## 5.0.3 ### Patch Changes - Updated dependencies [[`6715330`](https://github.com/dotansimha/graphql-code-generator/commit/67153304646694d75aee24afd70c3fce12e9f1f2)]: - @graphql-codegen/visitor-plugin-common@6.1.1 - @graphql-codegen/typescript@5.0.3 ## 5.0.2 ### Patch Changes - Updated dependencies [[`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26)]: - @graphql-codegen/visitor-plugin-common@6.1.0 - @graphql-codegen/typescript@5.0.2 ## 5.0.1 ### Patch Changes - Updated dependencies [[`accdab6`](https://github.com/dotansimha/graphql-code-generator/commit/accdab69106605241933e9d66d64dc7077656f30)]: - @graphql-codegen/visitor-plugin-common@6.0.1 - @graphql-codegen/typescript@5.0.1 ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGE: Use Record instead of {} for empty object type - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/visitor-plugin-common@6.0.0 - @graphql-codegen/plugin-helpers@6.0.0 - @graphql-codegen/typescript@5.0.0 ## 4.6.1 ### Patch Changes - [#10330](https://github.com/dotansimha/graphql-code-generator/pull/10330) [`c5efba3`](https://github.com/dotansimha/graphql-code-generator/commit/c5efba34a7b422720be9ce32937dd19fb0784bae) Thanks [@jnoordsij](https://github.com/jnoordsij)! - Make graphql-sock optional peerDep ## 4.6.0 ### Minor Changes - [#10323](https://github.com/dotansimha/graphql-code-generator/pull/10323) [`f3cf4df`](https://github.com/dotansimha/graphql-code-generator/commit/f3cf4df358a896c5df0a7d8909c2fbf192e10c01) Thanks [@eddeee888](https://github.com/eddeee888)! - Add support for `nullability.errorHandlingClient`. This allows clients to get stronger types with [semantic nullability](https://github.com/graphql/graphql-wg/blob/main/rfcs/SemanticNullability.md)-enabled schemas. ### Patch Changes - Updated dependencies [[`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc)]: - @graphql-codegen/visitor-plugin-common@5.8.0 - @graphql-codegen/typescript@4.1.6 ## 4.5.1 ### Patch Changes - [#10302](https://github.com/dotansimha/graphql-code-generator/pull/10302) [`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix Apollo unmask directive incorrectly generating fragmentRefs - Updated dependencies [[`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a)]: - @graphql-codegen/visitor-plugin-common@5.7.1 - @graphql-codegen/typescript@4.1.5 ## 4.5.0 ### Minor Changes - [#10270](https://github.com/dotansimha/graphql-code-generator/pull/10270) [`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c) Thanks [@adapap](https://github.com/adapap)! - feat: implement `includeExternalFragments: boolean` option ### Patch Changes - Updated dependencies [[`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c)]: - @graphql-codegen/visitor-plugin-common@5.7.0 - @graphql-codegen/typescript@4.1.4 ## 4.4.1 ### Patch Changes - Updated dependencies [[`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517)]: - @graphql-codegen/visitor-plugin-common@5.6.1 - @graphql-codegen/typescript@4.1.3 ## 4.4.0 ### Minor Changes - [#10163](https://github.com/dotansimha/graphql-code-generator/pull/10163) [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Add support for Apollo Client `@unmask` directive with fragment masking. ### Patch Changes - Updated dependencies [[`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a), [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba)]: - @graphql-codegen/visitor-plugin-common@5.6.0 - @graphql-codegen/typescript@4.1.2 ## 4.3.1 ### Patch Changes - Updated dependencies [[`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc), [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03)]: - @graphql-codegen/visitor-plugin-common@5.5.0 - @graphql-codegen/plugin-helpers@5.1.0 - @graphql-codegen/typescript@4.1.1 ## 4.3.0 ### Minor Changes - [#10077](https://github.com/dotansimha/graphql-code-generator/pull/10077) [`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4) Thanks [@eddeee888](https://github.com/eddeee888)! - Extend `config.avoidOptions` to support query, mutation and subscription Previously, `config.avoidOptions.resolvers` was being used to make query, mutation and subscription fields non-optional. Now, `config.avoidOptions.query`, `config.avoidOptions.mutation` and `config.avoidOptions.subscription` can be used to target the respective types. ### Patch Changes - Updated dependencies [[`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4)]: - @graphql-codegen/visitor-plugin-common@5.4.0 - @graphql-codegen/typescript@4.1.0 ## 4.2.3 ### Patch Changes - Updated dependencies [[`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2)]: - @graphql-codegen/visitor-plugin-common@5.3.1 - @graphql-codegen/typescript@4.0.9 ## 4.2.2 ### Patch Changes - Updated dependencies [[`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3), [`14ce39e`](https://github.com/dotansimha/graphql-code-generator/commit/14ce39e41dfee38c652be736664177fa2b1df421)]: - @graphql-codegen/visitor-plugin-common@5.3.0 - @graphql-codegen/typescript@4.0.8 ## 4.2.1 ### Patch Changes - Updated dependencies [[`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431), [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e)]: - @graphql-codegen/plugin-helpers@5.0.4 - @graphql-codegen/visitor-plugin-common@5.2.0 - @graphql-codegen/typescript@4.0.7 ## 4.2.0 ### Minor Changes - [#9652](https://github.com/dotansimha/graphql-code-generator/pull/9652) [`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53) Thanks [@gmurphey](https://github.com/gmurphey)! - Added allowUndefinedQueryVariables as config option ### Patch Changes - [#9842](https://github.com/dotansimha/graphql-code-generator/pull/9842) [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d) Thanks [@henryqdineen](https://github.com/henryqdineen)! - properly handle aliased conditionals - Updated dependencies [[`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53), [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d)]: - @graphql-codegen/visitor-plugin-common@5.1.0 - @graphql-codegen/typescript@4.0.6 ## 4.1.3 ### Patch Changes - Updated dependencies [[`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5)]: - @graphql-codegen/visitor-plugin-common@5.0.0 - @graphql-codegen/typescript@4.0.5 ## 4.1.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/visitor-plugin-common@4.1.2 - @graphql-codegen/typescript@4.0.4 - @graphql-codegen/plugin-helpers@5.0.3 ## 4.1.1 ### Patch Changes - Updated dependencies [[`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f)]: - @graphql-codegen/visitor-plugin-common@4.1.1 - @graphql-codegen/typescript@4.0.3 ## 4.1.0 ### Minor Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - fix: out-of-memory crash (fixes #7720) perf: implement a caching mechanism that makes sure the type originating at the same location is never generated twice, as long as the combination of selected fields and possible types matches feat: implement `extractAllFieldsToTypes: boolean` feat: implement `printFieldsOnNewLines: boolean` ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 - @graphql-codegen/typescript@4.0.2 - @graphql-codegen/visitor-plugin-common@4.1.0 ## 4.0.1 ### Patch Changes - [#9497](https://github.com/dotansimha/graphql-code-generator/pull/9497) [`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a) Thanks [@eddeee888](https://github.com/eddeee888)! - Revert default ID scalar input type to string We changed the ID Scalar input type from `string` to `string | number` in the latest major version of `typescript` plugin. This causes issues for server plugins (e.g. typescript-resolvers) that depends on `typescript` plugin. This is because the scalar type needs to be manually inverted on setup which is confusing. - Updated dependencies [[`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a)]: - @graphql-codegen/visitor-plugin-common@4.0.1 - @graphql-codegen/typescript@4.0.1 ## 4.0.0 ### Major Changes - [#9375](https://github.com/dotansimha/graphql-code-generator/pull/9375) [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929) Thanks [@eddeee888](https://github.com/eddeee888)! - Implement Scalars with input/output types In GraphQL, Scalar types can be different for client and server. For example, given the native GraphQL ID: - A client may send `string` or `number` in the input - A client receives `string` in its selection set (i.e output) - A server receives `string` in the resolver (GraphQL parses `string` or `number` received from the client to `string`) - A server may return `string` or `number` (GraphQL serializes the value to `string` before sending it to the client ) Currently, we represent every Scalar with only one type. This is what codegen generates as base type: ```ts export type Scalars = { ID: string } ``` Then, this is used in both input and output type e.g. ```ts export type Book = { __typename?: 'Book' id: Scalars['ID'] // Output's ID can be `string` 👍 } export type QueryBookArgs = { id: Scalars['ID'] // Input's ID can be `string` or `number`. However, the type is only `string` here 👎 } ``` This PR extends each Scalar to have input and output: ```ts export type Scalars = { ID: { input: string | number output: string } } ``` Then, each input/output GraphQL type can correctly refer to the correct input/output scalar type: ```ts export type Book = { __typename?: 'Book' id: Scalars['ID']['output'] // Output's ID can be `string` 👍 } export type QueryBookArgs = { id: Scalars['ID']['input'] // Input's ID can be `string` or `number` 👍 } ``` Note that for `typescript-resolvers`, the type of ID needs to be inverted. However, the referenced types in GraphQL input/output types should still work correctly: ```ts export type Scalars = { ID: { input: string; output: string | number; } } export type Book = { __typename?: "Book"; id: Scalars["ID"]['output']; // Resolvers can return `string` or `number` in ID fields 👍 }; export type QueryBookArgs = { id: Scalars["ID"]['input']; // Resolvers receive `string` in ID fields 👍 }; export type ResolversTypes = { ID: ID: ResolverTypeWrapper; // Resolvers can return `string` or `number` in ID fields 👍 } export type ResolversParentTypes = { ID: Scalars['ID']['output']; // Resolvers receive `string` or `number` from parents 👍 }; ``` *** Config changes: 1. Scalars option can now take input/output types: ```ts config: { scalars: { ID: { input: 'string', output: 'string | number' } } } ``` 2. If a string is given (instead of an object with input/output fields), it will be used as both input and output types: ```ts config: { scalars: { ID: 'string' // This means `string` will be used for both ID's input and output types } } ``` 3. BREAKING CHANGE: External module Scalar types need to be an object with input/output fields ```ts config: { scalars: { ID: './path/to/scalar-module' } } ``` If correctly, wired up, the following will be generated: ```ts // Previously, imported `ID` type can be a primitive type, now it must be an object with input/output fields import { ID } from './path/to/scalar-module' export type Scalars = { ID: { input: ID['input']; output: ID['output'] } } ``` *** BREAKING CHANGE: This changes Scalar types which could be referenced in other plugins. If you are a plugin maintainer and reference Scalar, please update your plugin to use the correct input/output types. - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Minor Changes - [#9196](https://github.com/dotansimha/graphql-code-generator/pull/9196) [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96) Thanks [@beerose](https://github.com/beerose)! - Add `@defer` directive support When a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved. Once start using the `@defer` directive in your queries, the generated code will automatically include support for the directive. ```jsx // src/index.tsx import { graphql } from './gql' const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `) const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `) ``` The generated type for `GetUserQuery` will have information that the fragment is _incremental,_ meaning it may not be available right away. ```tsx // gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query' } & { ' $fragmentRefs'?: { OrdersFragment: Incremental } }) ``` Apart from generating code that includes support for the `@defer` directive, the Codegen also exports a utility function called `isFragmentReady`. You can use it to conditionally render components based on whether the data for a deferred fragment is available: ```jsx const OrdersList = (props: { data: FragmentType }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && } )} ); } export default App; ``` - [#9304](https://github.com/dotansimha/graphql-code-generator/pull/9304) [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823) Thanks [@esfomeado](https://github.com/esfomeado)! - Added support for disabling suffixes on Enums. ### Patch Changes - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96), [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c), [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d), [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0), [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c)]: - @graphql-codegen/plugin-helpers@5.0.0 - @graphql-codegen/visitor-plugin-common@4.0.0 - @graphql-codegen/typescript@4.0.0 ## 3.0.4 ### Patch Changes - Updated dependencies [[`386cf9044`](https://github.com/dotansimha/graphql-code-generator/commit/386cf9044a41d87ed45069b22d26b30f4b262a85), [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00)]: - @graphql-codegen/visitor-plugin-common@3.1.1 - @graphql-codegen/typescript@3.0.4 ## 3.0.3 ### Patch Changes - Updated dependencies [[`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835), [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087), [`92d86b009`](https://github.com/dotansimha/graphql-code-generator/commit/92d86b009579edf70f60b0b8e28658af93ff9fd1), [`acb647e4e`](https://github.com/dotansimha/graphql-code-generator/commit/acb647e4efbddecf732b6e55dc47ac40c9bdaf08), [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd)]: - @graphql-codegen/visitor-plugin-common@3.1.0 - @graphql-codegen/plugin-helpers@4.2.0 - @graphql-codegen/typescript@3.0.3 ## 3.0.2 ### Patch Changes - Updated dependencies [[`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a), [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc), [`b343626c9`](https://github.com/dotansimha/graphql-code-generator/commit/b343626c978b9ee0f14e314cea6c01ae3dad057c)]: - @graphql-codegen/visitor-plugin-common@3.0.2 - @graphql-codegen/typescript@3.0.2 ## 3.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 - @graphql-codegen/typescript@3.0.1 - @graphql-codegen/visitor-plugin-common@3.0.1 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/visitor-plugin-common@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 - @graphql-codegen/typescript@3.0.0 ## 2.5.13 ### Patch Changes - Updated dependencies [[`a98198524`](https://github.com/dotansimha/graphql-code-generator/commit/a9819852443884b43de7c15040ccffc205f9177a)]: - @graphql-codegen/visitor-plugin-common@2.13.8 - @graphql-codegen/typescript@2.8.8 ## 2.5.12 ### Patch Changes - Updated dependencies [[`eb454d06c`](https://github.com/dotansimha/graphql-code-generator/commit/eb454d06c977f11f7d4a7b0b07eb80f8fd590560)]: - @graphql-codegen/visitor-plugin-common@2.13.7 - @graphql-codegen/typescript@2.8.7 ## 2.5.11 ### Patch Changes - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 - @graphql-codegen/visitor-plugin-common@2.13.6 - @graphql-codegen/typescript@2.8.6 ## 2.5.10 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/visitor-plugin-common@2.13.5 - @graphql-codegen/typescript@2.8.5 ## 2.5.9 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/visitor-plugin-common@2.13.4 - @graphql-codegen/typescript@2.8.4 ## 2.5.8 ### Patch Changes - [#8664](https://github.com/dotansimha/graphql-code-generator/pull/8664) [`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe) Thanks [@jdmoody](https://github.com/jdmoody)! - Fix issue where selection set flattening uses the wrong parent type - Updated dependencies [[`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe)]: - @graphql-codegen/visitor-plugin-common@2.13.3 - @graphql-codegen/typescript@2.8.3 ## 2.5.7 ### Patch Changes - Updated dependencies [[`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122)]: - @graphql-codegen/visitor-plugin-common@2.13.2 - @graphql-codegen/typescript@2.8.2 ## 2.5.6 ### Patch Changes - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/visitor-plugin-common@2.13.1 - @graphql-codegen/plugin-helpers@2.7.2 - @graphql-codegen/typescript@2.8.1 ## 2.5.5 ### Patch Changes - Updated dependencies [[`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b)]: - @graphql-codegen/visitor-plugin-common@2.13.0 - @graphql-codegen/typescript@2.7.5 ## 2.5.4 ### Patch Changes - Updated dependencies [[`1bd7f771c`](https://github.com/dotansimha/graphql-code-generator/commit/1bd7f771ccb949a5a37395c7c57cb41c19340714)]: - @graphql-codegen/visitor-plugin-common@2.12.2 - @graphql-codegen/typescript@2.7.4 ## 2.5.3 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f), [`47d0a57e2`](https://github.com/dotansimha/graphql-code-generator/commit/47d0a57e27dd0d2334670bfc6c81c45e00ff4e74)]: - @graphql-codegen/visitor-plugin-common@2.12.1 - @graphql-codegen/typescript@2.7.3 - @graphql-codegen/plugin-helpers@2.6.2 ## 2.5.2 ### Patch Changes - Updated dependencies [2cbcbb371] - @graphql-codegen/visitor-plugin-common@2.12.0 - @graphql-codegen/plugin-helpers@2.6.0 - @graphql-codegen/typescript@2.7.2 ## 2.5.1 ### Patch Changes - Updated dependencies [525ad580b] - @graphql-codegen/visitor-plugin-common@2.11.1 - @graphql-codegen/typescript@2.7.1 ## 2.5.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [68bb30e19] - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/visitor-plugin-common@2.11.0 - @graphql-codegen/typescript@2.7.0 - @graphql-codegen/plugin-helpers@2.5.0 ## 2.4.3 ### Patch Changes - Updated dependencies [aa1e6eafd] - Updated dependencies [a42fcbfe4] - Updated dependencies [8b10f22be] - @graphql-codegen/typescript@2.6.0 - @graphql-codegen/visitor-plugin-common@2.10.0 ## 2.4.2 ### Patch Changes - Updated dependencies [d16bebacb] - @graphql-codegen/visitor-plugin-common@2.9.1 - @graphql-codegen/typescript@2.5.1 ## 2.4.1 ### Patch Changes - Updated dependencies [c3d7b7226] - @graphql-codegen/visitor-plugin-common@2.9.0 - @graphql-codegen/typescript@2.5.0 ## 2.4.0 ### Minor Changes - f1fb77bd4: feat: Add option to squash exactly similar fragment types ### Patch Changes - Updated dependencies [f1fb77bd4] - @graphql-codegen/visitor-plugin-common@2.8.0 - @graphql-codegen/typescript@2.4.11 ## 2.3.7 ### Patch Changes - Updated dependencies [9a5f31cb6] - @graphql-codegen/typescript@2.4.10 - @graphql-codegen/visitor-plugin-common@2.7.6 ## 2.3.6 ### Patch Changes - 9312920a4: Import type definitions of dependent fragments when `inlineFragmentType` is `mask` - 2966686e9: Generate $fragmentName for fragment subtypes for fragment masking - Updated dependencies [2966686e9] - @graphql-codegen/visitor-plugin-common@2.7.5 - @graphql-codegen/typescript@2.4.9 ## 2.3.5 ### Patch Changes - Updated dependencies [337fd4f77] - @graphql-codegen/visitor-plugin-common@2.7.4 - @graphql-codegen/typescript@2.4.8 ## 2.3.4 ### Patch Changes - Updated dependencies [54718c039] - @graphql-codegen/typescript@2.4.7 - @graphql-codegen/visitor-plugin-common@2.7.3 ## 2.3.3 ### Patch Changes - Updated dependencies [11d05e361] - @graphql-codegen/visitor-plugin-common@2.7.2 - @graphql-codegen/typescript@2.4.6 ## 2.3.2 ### Patch Changes - fd55e2039: fix incorrect type generation when using the inlineFragmentTypes 'combine' option that resulted in generating masked fragment output. - Updated dependencies [fd55e2039] - @graphql-codegen/visitor-plugin-common@2.7.1 - @graphql-codegen/typescript@2.4.5 ## 2.3.1 ### Patch Changes - Updated dependencies [1479233df] - @graphql-codegen/visitor-plugin-common@2.7.0 - @graphql-codegen/typescript@2.4.4 ## 2.3.0 ### Minor Changes - 4d413b13a: feat: Support including fragments when using flattenGeneratedTypes in typescript-operations ## 2.2.4 ### Patch Changes - Updated dependencies [c8ef37ae0] - Updated dependencies [754a33715] - Updated dependencies [bef4376d5] - Updated dependencies [be7cb3a82] - @graphql-codegen/visitor-plugin-common@2.6.0 - @graphql-codegen/plugin-helpers@2.4.0 - @graphql-codegen/typescript@2.4.3 ## 2.2.3 ### Patch Changes - 7649201fe: Remove redundant mandatory 'undefined' on avoidOptionals=true ## 2.2.2 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/visitor-plugin-common@2.5.2 - @graphql-codegen/typescript@2.4.2 - @graphql-codegen/plugin-helpers@2.3.2 ## 2.2.1 ### Patch Changes - a9f1f1594: Use maybeValue as default output for optionals on preResolveTypes: true - Updated dependencies [a9f1f1594] - Updated dependencies [9ea6621ec] - @graphql-codegen/visitor-plugin-common@2.5.1 - @graphql-codegen/typescript@2.4.1 ## 2.2.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/visitor-plugin-common@2.5.0 - @graphql-codegen/typescript@2.3.0 - @graphql-codegen/plugin-helpers@2.3.0 ## 2.1.8 ### Patch Changes - 8a576b49a: avoidOptionals with skip/include directives fix - Updated dependencies [ad02cb9b8] - @graphql-codegen/visitor-plugin-common@2.4.0 - @graphql-codegen/typescript@2.2.4 ## 2.1.7 ### Patch Changes - 1d570b456: avoidOptionals sub-config fix - Updated dependencies [b9e85adae] - Updated dependencies [7c60e5acc] - Updated dependencies [3c2c847be] - @graphql-codegen/visitor-plugin-common@2.3.0 - @graphql-codegen/plugin-helpers@2.2.0 - @graphql-codegen/typescript@2.2.3 ## 2.1.6 ### Patch Changes - 5c37b9d11: Fix avoidOptional handle of Maybe types ## 2.1.5 ### Patch Changes - 25cd11d01: correctly inline Maybe types if the `preresolveTypes` config option is set to `true` ## 2.1.4 ### Patch Changes - Updated dependencies [0b090e31a] - @graphql-codegen/visitor-plugin-common@2.2.1 - @graphql-codegen/typescript@2.2.2 ## 2.1.3 ### Patch Changes - Updated dependencies [d6c2d4c09] - Updated dependencies [feeae1c66] - Updated dependencies [8261e4161] - Updated dependencies [5086791ac] - @graphql-codegen/visitor-plugin-common@2.2.0 - @graphql-codegen/typescript@2.2.0 ## 2.1.2 ### Patch Changes - Updated dependencies [6470e6cc9] - Updated dependencies [263570e50] - Updated dependencies [35199dedf] - @graphql-codegen/visitor-plugin-common@2.1.2 - @graphql-codegen/plugin-helpers@2.1.1 - @graphql-codegen/typescript@2.1.2 ## 2.1.1 ### Patch Changes - Updated dependencies [aabeff181] - @graphql-codegen/visitor-plugin-common@2.1.1 - @graphql-codegen/typescript@2.1.1 ## 2.1.0 ### Minor Changes - 440172cfe: support ESM ### Patch Changes - Updated dependencies [290170262] - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/visitor-plugin-common@2.1.0 - @graphql-codegen/plugin-helpers@2.1.0 - @graphql-codegen/typescript@2.1.0 ## 2.0.1 ### Patch Changes - e8c8e9c06: Set `preResolveTypes: true` by default (should be there since v2) ## 2.0.0 ### Major Changes - d80efdec4: Change `preResolveTypes` default to be `true` for more readable types - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - d80efdec4: Add option `inlineFragmentTypes` for deep inlining fragment types within operation types. This `inlineFragmentTypes` is set to `inline` by default (Previous behaviour is `combine`). This behavior is the better default for users that only use Fragments for building operations and then want to have access to all the data via the operation type (instead of accessing slices of the data via fragments). - Updated dependencies [d80efdec4] - Updated dependencies [d80efdec4] - Updated dependencies [b0cb13df4] - @graphql-codegen/visitor-plugin-common@2.0.0 - @graphql-codegen/typescript@2.0.0 - @graphql-codegen/plugin-helpers@2.0.0 ## 1.18.4 ### Patch Changes - Updated dependencies [df19a4ed] - Updated dependencies [470336a1] - Updated dependencies [9005cc17] - @graphql-codegen/visitor-plugin-common@1.22.0 - @graphql-codegen/plugin-helpers@1.18.8 - @graphql-codegen/typescript@1.23.0 ## 1.18.3 ### Patch Changes - 6762aff5: Fix for array types with @skip @include directives - Updated dependencies [6762aff5] - @graphql-codegen/visitor-plugin-common@1.21.3 - @graphql-codegen/typescript@1.22.4 ## 1.18.2 ### Patch Changes - 6aaecf1c: Fix issues with missing sub-fragments when skipTypename: true - Updated dependencies [6aaecf1c] - @graphql-codegen/visitor-plugin-common@1.21.2 - @graphql-codegen/typescript@1.22.3 ## 1.18.1 ### Patch Changes - Updated dependencies [cf1e5abc] - @graphql-codegen/visitor-plugin-common@1.21.1 - @graphql-codegen/typescript@1.22.2 ## 1.18.0 ### Minor Changes - 0a909869: Add arrayInputCoercion option ### Patch Changes - Updated dependencies [dfd25caf] - Updated dependencies [8da7dff6] - @graphql-codegen/visitor-plugin-common@1.21.0 - @graphql-codegen/plugin-helpers@1.18.7 - @graphql-codegen/typescript@1.22.1 ## 1.17.16 ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - Updated dependencies [f0b5ea53] - Updated dependencies [097bea2f] - @graphql-codegen/visitor-plugin-common@1.20.0 - @graphql-codegen/typescript@1.22.0 - @graphql-codegen/plugin-helpers@1.18.5 ## 1.17.15 ### Patch Changes - 1f6f3db6: Fix for @skip @include directives upon arrays - 29b75b1e: enhance(namingConvention): use change-case-all instead of individual packages for naming convention - Updated dependencies [e947f8e3] - Updated dependencies [29b75b1e] - Updated dependencies [d4942d04] - Updated dependencies [1f6f3db6] - Updated dependencies [29b75b1e] - @graphql-codegen/visitor-plugin-common@1.19.0 - @graphql-codegen/typescript@1.21.1 - @graphql-codegen/plugin-helpers@1.18.3 ## 1.17.14 ### Patch Changes - 63be0f40: Fix issues with empty interfaces causing syntax issues - 190482a1: add support for fragment variables - 142b32b3: @skip, @include directives resolve to optional fields - 142b32b3: Better support for @skip/@include directives with complex selection sets - Updated dependencies [63be0f40] - Updated dependencies [190482a1] - Updated dependencies [4444348d] - Updated dependencies [142b32b3] - Updated dependencies [42213fa0] - @graphql-codegen/visitor-plugin-common@1.18.1 - @graphql-codegen/typescript@1.20.1 ## 1.17.13 ### Patch Changes - 64293437: Support for input lists coercion - Updated dependencies [64293437] - Updated dependencies [fd5843a7] - Updated dependencies [d75051f5] - @graphql-codegen/visitor-plugin-common@1.17.22 ## 1.17.12 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/visitor-plugin-common@1.17.20 - @graphql-codegen/typescript@1.18.1 - @graphql-codegen/plugin-helpers@1.18.2 ## 1.17.11 ### Patch Changes - 7587fda4: When using avoidOptionals config, @skip, @include resolve into MakeMaybe type - Updated dependencies [99819bf1] - Updated dependencies [49242c20] - Updated dependencies [c3b59e81] - @graphql-codegen/visitor-plugin-common@1.17.19 - @graphql-codegen/typescript@1.18.0 ## 1.17.10 ### Patch Changes - 475aa9b8: @skip, @include directives resolve to optional fields - Updated dependencies [faa13973] - @graphql-codegen/visitor-plugin-common@1.17.18 ## 1.17.9 ### Patch Changes - 612e5e52: Remove broken isTypeOf call (always undefined in graphql-tools v6) - 0f35e775: Fixed issues with incorrect naming when typesSuffix is used - Updated dependencies [612e5e52] - Updated dependencies [9f2a4e2f] - Updated dependencies [0f35e775] - Updated dependencies [eaf45d1f] - @graphql-codegen/visitor-plugin-common@1.17.17 - @graphql-codegen/plugin-helpers@1.18.1 ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/visitor-plugin-common@1.17.13 - @graphql-codegen/plugin-helpers@1.17.8 - @graphql-codegen/typescript@1.17.8 ================================================ FILE: packages/plugins/typescript/operations/package.json ================================================ { "name": "@graphql-codegen/typescript-operations", "version": "5.0.9", "description": "GraphQL Code Generator plugin for generating TypeScript types for GraphQL queries, mutations, subscriptions and fragments", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/typescript/operations" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-codegen/typescript": "^5.0.9", "@graphql-codegen/visitor-plugin-common": "^6.2.4", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql-sock": "^1.0.0" }, "peerDependenciesMeta": { "graphql-sock": { "optional": true } }, "devDependencies": { "graphql-sock": "1.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/typescript/operations/src/config.ts ================================================ import { AvoidOptionalsConfig, RawDocumentsConfig } from '@graphql-codegen/visitor-plugin-common'; /** * @description This plugin generates TypeScript types based on your GraphQLSchema _and_ your GraphQL operations and fragments. * It generates types for your GraphQL documents: Query, Mutation, Subscription and Fragment. * * Note: In most configurations, this plugin requires you to use `typescript as well, because it depends on its base types. */ export interface TypeScriptDocumentsPluginConfig extends RawDocumentsConfig { /** * @description The [GraphQL spec](https://spec.graphql.org/draft/#sel-FAHjBJFCAACE_Gh7d) * allows arrays and a single primitive value for list input. This allows to * deactivate that behavior to only accept arrays instead of single values. If * set to `false`, the definition: `query foo(bar: [Int!]!): Foo` will output * `bar: Array` instead of `bar: Array | Int` for the variable part. * @default true * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * arrayInputCoercion: false * }, * }, * }, * }; * export default config; * ``` */ arrayInputCoercion?: boolean; /** * @description This will cause the generator to avoid using TypeScript optionals (`?`) on types, * so the following definition: `type A { myField: String }` will output `myField: Maybe` * instead of `myField?: Maybe`. * @default false * * @exampleMarkdown * ## Override all definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * avoidOptionals: true * }, * }, * }, * }; * export default config; * ``` * * ## Override only specific definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * avoidOptionals: { * field: true * inputValue: true * object: true * defaultValue: true * } * }, * }, * }, * }; * export default config; * ``` */ avoidOptionals?: boolean | AvoidOptionalsConfig; /** * @description Generates immutable types by adding `readonly` to properties and uses `ReadonlyArray`. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * immutableTypes: true * }, * }, * }, * }; * export default config; * ``` */ immutableTypes?: boolean; /** * @description Flatten fragment spread and inline fragments into a simple selection set before generating. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-operations'], * config: { * flattenGeneratedTypes: true * }, * }, * }, * }; * export default config; * ``` */ flattenGeneratedTypes?: boolean; /** * @description Include all fragments types when flattenGeneratedTypes is enabled. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-operations'], * config: { * flattenGeneratedTypes: true, * flattenGeneratedTypesIncludeFragments: true * }, * }, * }, * }; * export default config; * ``` */ flattenGeneratedTypesIncludeFragments?: boolean; /** * @description Set to `true` in order to generate output without `export` modifier. * This is useful if you are generating `.d.ts` file and want it to be globally available. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * noExport: true * }, * }, * }, * }; * export default config; * ``` */ noExport?: boolean; globalNamespace?: boolean; /** * @name addOperationExport * @type boolean * @description Add const export of the operation name to output file. Pay attention that the file should be `d.ts`. * You can combine it with `near-operation-file preset` and therefore the types will be generated along with graphql file. Then you need to set extension in `presetConfig` to be `.gql.d.ts` and by that you can import `gql` file in `ts` files. * It will allow you to get everything with one import: * * ```ts * import { GetClient, GetClientQuery, GetClientQueryVariables } from './GetClient.gql.js' * ``` * @default false * @see https://github.com/dotansimha/graphql-code-generator/issues/3949 * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * "./typings/api.ts": { * "plugins": [ * "typescript" * ] * }, * "./": { * "preset": "near-operation-file", * "presetConfig": { * "baseTypesPath": "./typings/api.ts", * "extension": ".gql.d.ts" * }, * "plugins": [ * "@graphql-codegen/typescript-operations" * ], * "config": { * "addOperationExport": true * } * } * }; * export default config; * ``` */ addOperationExport?: boolean; /** * @description Allow to override the type value of `Maybe`. * @default T | null * * @exampleMarkdown * ## Allow undefined * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * maybeValue: 'T | null | undefined' * }, * }, * }, * }; * export default config; * ``` * * ## Allow `null` in resolvers: * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * maybeValue: 'T extends PromiseLike ? Promise : T | null' * }, * }, * }, * }; * export default config; * ``` */ maybeValue?: string; /** * @description Adds undefined as a possible type for query variables * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * allowUndefinedQueryVariables: true * }, * }, * }, * }; * export default config; * ``` */ allowUndefinedQueryVariables?: boolean; /** * @description Options related to handling nullability * @exampleMarkdown * ## `errorHandlingClient` * An error handling client is a client which prevents the user from reading a `null` used as a placeholder for an error in a GraphQL response. * The client may do so by throwing when an errored field is accessed (as is the case for [`graphql-toe`](https://github.com/graphile/graphql-toe)), * or when a fragment containing an error is read (as is the case for Relay's `@throwOnFieldError` directive), * or by preventing any data from being read if an error occurred (as with Apollo Client's `errorPolicy: "none"`). * * When using error handling clients, a semantic non-nullable field can never be `null`. * If a semantic non-nullable field's value in the response is `null`, there must be a respective error. * The error handling client will throw in this case, so the `null` value is never read. * * To enable this option, install `graphql-sock` peer dependency: * * ```sh npm2yarn * npm install -D graphql-sock * ``` * * Now, you can enable support for error handling clients: * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-operations'], * config: { * nullability: { * errorHandlingClient: true * } * }, * }, * }, * }; * export default config; * ``` */ nullability?: { errorHandlingClient: boolean; }; } ================================================ FILE: packages/plugins/typescript/operations/src/index.ts ================================================ import { oldVisit, PluginFunction, Types } from '@graphql-codegen/plugin-helpers'; import { LoadedFragment, optimizeOperations } from '@graphql-codegen/visitor-plugin-common'; import { concatAST, FragmentDefinitionNode, GraphQLSchema, Kind } from 'graphql'; import { TypeScriptDocumentsPluginConfig } from './config.js'; import { TypeScriptDocumentsVisitor } from './visitor.js'; export { TypeScriptDocumentsPluginConfig } from './config.js'; export const plugin: PluginFunction = async ( inputSchema: GraphQLSchema, rawDocuments: Types.DocumentFile[], config: TypeScriptDocumentsPluginConfig ) => { const schema = config.nullability?.errorHandlingClient ? await semanticToStrict(inputSchema) : inputSchema; const documents = config.flattenGeneratedTypes ? optimizeOperations(schema, rawDocuments, { includeFragments: config.flattenGeneratedTypesIncludeFragments, }) : rawDocuments; const allAst = concatAST(documents.map(v => v.document)); const allFragments: LoadedFragment[] = [ ...(allAst.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION) as FragmentDefinitionNode[]).map( fragmentDef => ({ node: fragmentDef, name: fragmentDef.name.value, onType: fragmentDef.typeCondition.name.value, isExternal: false, }) ), ...(config.externalFragments || []), ]; const visitor = new TypeScriptDocumentsVisitor(schema, config, allFragments); const visitorResult = oldVisit(allAst, { leave: visitor, }); let content = visitorResult.definitions.join('\n'); if (config.addOperationExport) { const exportConsts = []; for (const d of allAst.definitions) { if ('name' in d) { exportConsts.push(`export declare const ${d.name.value}: import("graphql").DocumentNode;`); } } content = visitorResult.definitions.concat(exportConsts).join('\n'); } if (config.globalNamespace) { content = ` declare global { ${content} }`; } return { prepend: [...visitor.getImports(), ...visitor.getGlobalDeclarations(visitor.config.noExport)], content, }; }; export { TypeScriptDocumentsVisitor }; const semanticToStrict = async (schema: GraphQLSchema): Promise => { try { const sock = await import('graphql-sock'); return sock.semanticToStrict(schema); } catch { throw new Error( "To use the `nullability.errorHandlingClient` option, you must install the 'graphql-sock' package." ); } }; ================================================ FILE: packages/plugins/typescript/operations/src/ts-operation-variables-to-object.ts ================================================ import { TypeScriptOperationVariablesToObject as TSOperationVariablesToObject } from '@graphql-codegen/typescript'; export class TypeScriptOperationVariablesToObject extends TSOperationVariablesToObject { protected formatTypeString(fieldType: string, _isNonNullType: boolean, _hasDefaultValue: boolean): string { return fieldType; } } ================================================ FILE: packages/plugins/typescript/operations/src/ts-selection-set-processor.ts ================================================ import { BaseSelectionSetProcessor, LinkField, PrimitiveAliasedFields, PrimitiveField, ProcessResult, SelectionSetProcessorConfig, } from '@graphql-codegen/visitor-plugin-common'; import { GraphQLInterfaceType, GraphQLObjectType } from 'graphql'; export class TypeScriptSelectionSetProcessor extends BaseSelectionSetProcessor { transformPrimitiveFields( schemaType: GraphQLObjectType | GraphQLInterfaceType, fields: PrimitiveField[], unsetTypes?: boolean ): ProcessResult { if (fields.length === 0) { return []; } const parentName = (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') + this.config.convertName(schemaType.name, { useTypesPrefix: true, }); if (unsetTypes) { const escapedFieldNames = fields.map(field => `'${field.fieldName}'`); return [formattedUnionTransform('MakeEmpty', parentName, escapedFieldNames)]; } let hasConditionals = false; const escapedConditionalsList: string[] = []; const escapedFieldNames = fields.map(field => { if (field.isConditional) { hasConditionals = true; escapedConditionalsList.push(`'${field.fieldName}'`); } return `'${field.fieldName}'`; }); let resString = formattedUnionTransform('Pick', parentName, escapedFieldNames); if (hasConditionals) { const avoidOptional = // TODO: check type and exec only if relevant this.config.avoidOptionals === true || (typeof this.config.avoidOptionals === 'object' && (this.config.avoidOptionals.field || this.config.avoidOptionals.inputValue || this.config.avoidOptionals.object)); const transform = avoidOptional ? 'MakeMaybe' : 'MakeOptional'; resString = `${ this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '' }${formattedUnionTransform(transform, resString, escapedConditionalsList)}`; } return [resString]; } transformTypenameField(type: string, name: string): ProcessResult { return [`{ ${name}: ${type} }`]; } transformAliasesPrimitiveFields( schemaType: GraphQLObjectType | GraphQLInterfaceType, fields: PrimitiveAliasedFields[] ): ProcessResult { if (fields.length === 0) { return []; } const parentName = (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') + this.config.convertName(schemaType.name, { useTypesPrefix: true, }); const selections = fields.map(aliasedField => { const value = aliasedField.fieldName === '__typename' ? `'${schemaType.name}'` : `${parentName}['${aliasedField.fieldName}']`; return `${aliasedField.alias}: ${value}`; }); return [formatSelections(selections)]; } transformLinkFields(fields: LinkField[]): ProcessResult { if (fields.length === 0) { return []; } const selections = fields.map(field => `${field.alias || field.name}: ${field.selectionSet}`); return [formatSelections(selections)]; } } /** Equivalent to `${transformName}<${target}, ${unionElements.join(' | ')}>`, but with line feeds if necessary */ function formattedUnionTransform(transformName: string, target: string, unionElements: string[]): string { if (unionElements.length > 3) { return `${transformName}<\n ${target},\n | ${unionElements.join('\n | ')}\n >`; } return `${transformName}<${target}, ${unionElements.join(' | ')}>`; } /** Equivalent to `{ ${selections.join(', ')} }`, but with line feeds if necessary */ function formatSelections(selections: string[]): string { if (selections.length > 1) { return `{\n ${selections.map(s => s.replace(/\n/g, '\n ')).join(',\n ')},\n }`; } return `{ ${selections.join(', ')} }`; } ================================================ FILE: packages/plugins/typescript/operations/src/visitor.ts ================================================ import { BaseDocumentsVisitor, DeclarationKind, generateFragmentImportStatement, getConfigValue, LoadedFragment, normalizeAvoidOptionals, NormalizedAvoidOptionalsConfig, ParsedDocumentsConfig, PreResolveTypesProcessor, SelectionSetProcessorConfig, SelectionSetToObject, wrapTypeWithModifiers, } from '@graphql-codegen/visitor-plugin-common'; import autoBind from 'auto-bind'; import { GraphQLNamedType, GraphQLOutputType, GraphQLSchema, isEnumType, isNonNullType } from 'graphql'; import { TypeScriptDocumentsPluginConfig } from './config.js'; import { TypeScriptOperationVariablesToObject } from './ts-operation-variables-to-object.js'; import { TypeScriptSelectionSetProcessor } from './ts-selection-set-processor.js'; export interface TypeScriptDocumentsParsedConfig extends ParsedDocumentsConfig { arrayInputCoercion: boolean; avoidOptionals: NormalizedAvoidOptionalsConfig; immutableTypes: boolean; noExport: boolean; maybeValue: string; allowUndefinedQueryVariables: boolean; } export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor< TypeScriptDocumentsPluginConfig, TypeScriptDocumentsParsedConfig > { constructor(schema: GraphQLSchema, config: TypeScriptDocumentsPluginConfig, allFragments: LoadedFragment[]) { super( config, { arrayInputCoercion: getConfigValue(config.arrayInputCoercion, true), noExport: getConfigValue(config.noExport, false), avoidOptionals: normalizeAvoidOptionals(getConfigValue(config.avoidOptionals, false)), immutableTypes: getConfigValue(config.immutableTypes, false), nonOptionalTypename: getConfigValue(config.nonOptionalTypename, false), preResolveTypes: getConfigValue(config.preResolveTypes, true), mergeFragmentTypes: getConfigValue(config.mergeFragmentTypes, false), allowUndefinedQueryVariables: getConfigValue(config.allowUndefinedQueryVariables, false), } as TypeScriptDocumentsParsedConfig, schema ); autoBind(this); const preResolveTypes = getConfigValue(config.preResolveTypes, true); const defaultMaybeValue = 'T | null'; const maybeValue = getConfigValue(config.maybeValue, defaultMaybeValue); const wrapOptional = (type: string) => { if (preResolveTypes === true) { return maybeValue.replace('T', type); } const prefix = this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : ''; return `${prefix}Maybe<${type}>`; }; const wrapArray = (type: string) => { const listModifier = this.config.immutableTypes ? 'ReadonlyArray' : 'Array'; return `${listModifier}<${type}>`; }; const formatNamedField = ( name: string, type: GraphQLOutputType | GraphQLNamedType | null, isConditional = false, isOptional = false ): string => { const optional = isOptional || isConditional || (!this.config.avoidOptionals.field && !!type && !isNonNullType(type)); return (this.config.immutableTypes ? `readonly ${name}` : name) + (optional ? '?' : ''); }; const processorConfig: SelectionSetProcessorConfig = { namespacedImportName: this.config.namespacedImportName, convertName: this.convertName.bind(this), enumPrefix: this.config.enumPrefix, enumSuffix: this.config.enumSuffix, scalars: this.scalars, formatNamedField, wrapTypeWithModifiers(baseType, type) { return wrapTypeWithModifiers(baseType, type, { wrapOptional, wrapArray }); }, avoidOptionals: this.config.avoidOptionals, printFieldsOnNewLines: this.config.printFieldsOnNewLines, }; const processor = new (preResolveTypes ? PreResolveTypesProcessor : TypeScriptSelectionSetProcessor)( processorConfig ); this.setSelectionSetHandler( new SelectionSetToObject( processor, this.scalars, this.schema, this.convertName.bind(this), this.getFragmentSuffix.bind(this), allFragments, this.config ) ); const enumsNames = Object.keys(schema.getTypeMap()).filter(typeName => isEnumType(schema.getType(typeName))); this.setVariablesTransformer( new TypeScriptOperationVariablesToObject( this.scalars, this.convertName.bind(this), this.config.avoidOptionals, this.config.immutableTypes, this.config.namespacedImportName, enumsNames, this.config.enumPrefix, this.config.enumSuffix, this.config.enumValues, this.config.arrayInputCoercion, undefined, 'InputMaybe' ) ); this._declarationBlockConfig = { ignoreExport: this.config.noExport, }; } public getImports(): Array { return !this.config.globalNamespace && (this.config.inlineFragmentTypes === 'combine' || this.config.inlineFragmentTypes === 'mask') ? this.config.fragmentImports.map(fragmentImport => generateFragmentImportStatement(fragmentImport, 'type')) : []; } protected getPunctuation(_declarationKind: DeclarationKind): string { return ';'; } protected applyVariablesWrapper(variablesBlock: string, operationType: string): string { const prefix = this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : ''; const extraType = this.config.allowUndefinedQueryVariables && operationType === 'Query' ? ' | undefined' : ''; return `${prefix}Exact<${variablesBlock === '{}' ? `{ [key: string]: never; }` : variablesBlock}>${extraType}`; } } ================================================ FILE: packages/plugins/typescript/operations/tests/__snapshots__/ts-documents.spec.ts.snap ================================================ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`TypeScript Operations Plugin > Config > should include fragment variable definitions when experimentalFragmentVariables is set 1`] = ` "export type TextNotificationFragmentFragment = { __typename?: 'TextNotification', text?: string }; export type TextNotificationFragmentFragmentVariables = Exact<{ skip: Scalars['Boolean']['input']; }>; " `; exports[`TypeScript Operations Plugin > Issues > #2699 - Issues with multiple interfaces and unions 1`] = ` "export type GetEntityBrandDataQueryVariables = Exact<{ gid: Scalars['ID']['input']; brand: Scalars['ID']['input']; }>; export type GetEntityBrandDataQuery = { __typename?: 'Query', node: | { __typename: 'Company', active: boolean, id: string, createdAt: any, updatedAt: any, brandData?: { __typename?: 'EntityBrandData', active: boolean, browsable: boolean, title: string, alternateTitle?: string | null, description: string } | null, createdBy?: { __typename?: 'User', id: string, name: string } | null, updatedBy?: { __typename?: 'User', id: string, name: string } | null } | { __typename: 'Theater', active: boolean, id: string, createdAt: any, updatedAt: any, brandData?: { __typename?: 'EntityBrandData', active: boolean, browsable: boolean, title: string, alternateTitle?: string | null, description: string } | null, createdBy?: { __typename?: 'User', id: string, name: string } | null, updatedBy?: { __typename?: 'User', id: string, name: string } | null } | { __typename: 'Movie', id: string, createdAt: any, updatedAt: any, brandData?: { __typename?: 'EntityBrandData', active: boolean, browsable: boolean, title: string, alternateTitle?: string | null, description: string } | null, createdBy?: { __typename?: 'User', id: string, name: string } | null, updatedBy?: { __typename?: 'User', id: string, name: string } | null } | { __typename: 'User', id: string, createdAt: any, updatedAt: any, brandData?: { __typename?: 'EntityBrandData', active: boolean, browsable: boolean, title: string, alternateTitle?: string | null, description: string } | null, createdBy?: { __typename?: 'User', id: string, name: string } | null, updatedBy?: { __typename?: 'User', id: string, name: string } | null } }; type EntityBrandData_Company_Fragment = { __typename?: 'Company', brandData?: { __typename?: 'EntityBrandData', active: boolean, browsable: boolean, title: string, alternateTitle?: string | null, description: string } | null }; type EntityBrandData_Theater_Fragment = { __typename?: 'Theater', brandData?: { __typename?: 'EntityBrandData', active: boolean, browsable: boolean, title: string, alternateTitle?: string | null, description: string } | null }; type EntityBrandData_Movie_Fragment = { __typename?: 'Movie', brandData?: { __typename?: 'EntityBrandData', active: boolean, browsable: boolean, title: string, alternateTitle?: string | null, description: string } | null }; type EntityBrandData_User_Fragment = { __typename?: 'User', brandData?: { __typename?: 'EntityBrandData', active: boolean, browsable: boolean, title: string, alternateTitle?: string | null, description: string } | null }; export type EntityBrandDataFragment = | EntityBrandData_Company_Fragment | EntityBrandData_Theater_Fragment | EntityBrandData_Movie_Fragment | EntityBrandData_User_Fragment ; type ElementMetadata_Company_Fragment = { __typename?: 'Company', createdAt: any, updatedAt: any, createdBy?: { __typename?: 'User', id: string, name: string } | null, updatedBy?: { __typename?: 'User', id: string, name: string } | null }; type ElementMetadata_Theater_Fragment = { __typename?: 'Theater', createdAt: any, updatedAt: any, createdBy?: { __typename?: 'User', id: string, name: string } | null, updatedBy?: { __typename?: 'User', id: string, name: string } | null }; type ElementMetadata_Movie_Fragment = { __typename?: 'Movie', createdAt: any, updatedAt: any, createdBy?: { __typename?: 'User', id: string, name: string } | null, updatedBy?: { __typename?: 'User', id: string, name: string } | null }; type ElementMetadata_User_Fragment = { __typename?: 'User', createdAt: any, updatedAt: any, createdBy?: { __typename?: 'User', id: string, name: string } | null, updatedBy?: { __typename?: 'User', id: string, name: string } | null }; export type ElementMetadataFragment = | ElementMetadata_Company_Fragment | ElementMetadata_Theater_Fragment | ElementMetadata_Movie_Fragment | ElementMetadata_User_Fragment ; " `; exports[`TypeScript Operations Plugin > Issues > #2916 - Missing import prefix with preResolveTypes: true and near-operation-file preset 1`] = ` "export type UserQueryVariables = Types.Exact<{ [key: string]: never; }>; export type UserQuery = { user: { id: string, username: string, email: string, dep: Types.Department } }; " `; exports[`TypeScript Operations Plugin > Issues > #3064 - fragments over interfaces causes issues with fields 1`] = ` "type Venue_Hotel_Fragment = { __typename?: 'Hotel', id: string, gpsPosition: { __typename?: 'GPSPosition', lat: number, lng: number } }; type Venue_Transport_Fragment = { __typename?: 'Transport', id: string }; export type VenueFragment = | Venue_Hotel_Fragment | Venue_Transport_Fragment ; export type QQueryVariables = Exact<{ [key: string]: never; }>; export type QQuery = { __typename?: 'Query', hotel: { __typename?: 'Hotel', id: string, gpsPosition: { __typename?: 'GPSPosition', lat: number, lng: number } }, transport: { __typename?: 'Transport', id: string } }; " `; exports[`TypeScript Operations Plugin > Issues > #3064 - fragments over interfaces causes issues with fields 2`] = ` "export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Venue = { id: Scalars['String']['output']; name: Scalars['String']['output']; }; export type GpsPosition = { __typename?: 'GPSPosition'; lat: Scalars['Float']['output']; lng: Scalars['Float']['output']; }; export type VenueWithPosition = { id: Scalars['String']['output']; gpsPosition: GpsPosition; }; export type Hotel = VenueWithPosition & Venue & { __typename?: 'Hotel'; id: Scalars['String']['output']; gpsPosition: GpsPosition; name: Scalars['String']['output']; }; export type Transport = Venue & { __typename?: 'Transport'; id: Scalars['String']['output']; name: Scalars['String']['output']; }; export type Query = { __typename?: 'Query'; hotel: Hotel; transport: Transport; }; type Venue_Hotel_Fragment = { __typename?: 'Hotel', id: string, gpsPosition: { __typename?: 'GPSPosition', lat: number, lng: number } }; type Venue_Transport_Fragment = { __typename?: 'Transport', id: string }; export type VenueFragment = | Venue_Hotel_Fragment | Venue_Transport_Fragment ; export type QQueryVariables = Exact<{ [key: string]: never; }>; export type QQuery = { __typename?: 'Query', hotel: { __typename?: 'Hotel', id: string, gpsPosition: { __typename?: 'GPSPosition', lat: number, lng: number } }, transport: { __typename?: 'Transport', id: string } }; function test(q: QQuery) { if (q.hotel) { const t1 = q.hotel.gpsPosition.lat } if (q.transport) { const t2 = q.transport.id; } }" `; exports[`TypeScript Operations Plugin > Issues > #6874 - generates types when parent type differs from spread fragment member types and preResolveTypes=true 1`] = ` "export type SnakeQueryQueryVariables = Exact<{ [key: string]: never; }>; export type SnakeQueryQuery = { __typename?: 'Query', snake: | { __typename?: 'Snake', name: string, features: { __typename?: 'SnakeFeatures', color: string, length: number } } | { __typename?: 'Error' } }; type AnimalFragment_Bat_Fragment = { __typename?: 'Bat', features: { __typename?: 'BatFeatures', color: string, wingspan: number } }; type AnimalFragment_Snake_Fragment = { __typename?: 'Snake', features: { __typename?: 'SnakeFeatures', color: string, length: number } }; export type AnimalFragmentFragment = | AnimalFragment_Bat_Fragment | AnimalFragment_Snake_Fragment ; " `; exports[`TypeScript Operations Plugin > Issues > #8793 selecting __typename should not be optional 1`] = ` "export type SnakeQueryQueryVariables = Exact<{ [key: string]: never; }>; export type SnakeQueryQuery = { __typename: 'Query', snake: | { __typename: 'Snake' } | { __typename: 'Error' } }; " `; exports[`TypeScript Operations Plugin > Selection Set > Should generate the correct __typename when using both inline fragment and spread over type 1`] = ` "export type UserQueryQueryVariables = Exact<{ [key: string]: never; }>; export type UserQueryQuery = ( { __typename?: 'Query' } & { user?: Maybe<( { __typename?: 'User' } & Pick )> } ); export type UserFragment = ( { __typename?: 'User' } & Pick ); " `; exports[`TypeScript Operations Plugin > Selection Set > Should generate the correct __typename when using fragment over type 1`] = ` "export type UserQueryQueryVariables = Exact<{ [key: string]: never; }>; export type UserQueryQuery = ( { __typename?: 'Query' } & { user?: Maybe<( { __typename?: 'User' } & Pick )> } ); " `; exports[`TypeScript Operations Plugin > Selection Set > Should generate the correct __typename when using fragment spread over type 1`] = ` "export type UserQueryQueryVariables = Exact<{ [key: string]: never; }>; export type UserQueryQuery = ( { __typename?: 'Query' } & { user?: Maybe<( { __typename?: 'User' } & Pick )> } ); export type UserFragment = ( { __typename?: 'User' } & Pick ); " `; exports[`TypeScript Operations Plugin > Selection Set > Should generate the correct __typename when using fragment spread over union 1`] = ` "export type UserFragmentFragment = ( { __typename?: 'User' } & Pick ); export type AaaQueryVariables = Exact<{ [key: string]: never; }>; export type AaaQuery = ( { __typename?: 'Query' } & { user: | ( { __typename?: 'User' } & Pick ) | { __typename?: 'Error' } } ); " `; exports[`TypeScript Operations Plugin > Selection Set > Should generate the correct intersection for fragments when using with interfaces with same type 1`] = ` "export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = ( { __typename?: 'Query' } & { b?: Maybe< | ( { __typename?: 'A' } & Pick ) | { __typename?: 'B' } > } ); export type AFragment = ( { __typename?: 'A' } & Pick ); export type BFragment = ( { __typename?: 'A' } & Pick ); " `; exports[`TypeScript Operations Plugin > Selection Set > Should have valid __typename usage and split types according to that (with usage) 1`] = ` "type NetRoute_Ipv4Route_Fragment = ( { __typename: 'IPV4Route' } & { ipv4Address: Ipv4Route['address'], ipv4Gateway: Ipv4Route['gateway'], } ); type NetRoute_Ipv6Route_Fragment = ( { __typename: 'IPV6Route' } & { ipv6Address: Ipv6Route['address'], ipv6Gateway: Ipv6Route['gateway'], } ); export type NetRouteFragment = | NetRoute_Ipv4Route_Fragment | NetRoute_Ipv6Route_Fragment ; export type QqQueryVariables = Exact<{ [key: string]: never; }>; export type QqQuery = ( { __typename?: 'Query' } & { routes: Array< | ( { __typename: 'IPV4Route' } & { ipv4Address: Ipv4Route['address'], ipv4Gateway: Ipv4Route['gateway'], } ) | ( { __typename: 'IPV6Route' } & { ipv6Address: Ipv6Route['address'], ipv6Gateway: Ipv6Route['gateway'], } ) > } ); " `; exports[`TypeScript Operations Plugin > Selection Set > Should have valid __typename usage and split types according to that (with usage) 2`] = ` "type NetRoute_Ipv4Route_Fragment = ( { __typename: 'IPV4Route' } & { ipv4Address: Ipv4Route['address'], ipv4Gateway: Ipv4Route['gateway'], } ); type NetRoute_Ipv6Route_Fragment = ( { __typename: 'IPV6Route' } & { ipv6Address: Ipv6Route['address'], ipv6Gateway: Ipv6Route['gateway'], } ); export type NetRouteFragment = | NetRoute_Ipv4Route_Fragment | NetRoute_Ipv6Route_Fragment ; export type TestFragment = ( { __typename?: 'IPV6Route' } & { ipv6Address: Ipv6Route['address'], ipv6Gateway: Ipv6Route['gateway'], } ); export type QqQueryVariables = Exact<{ [key: string]: never; }>; export type QqQuery = ( { __typename?: 'Query' } & { routes: Array< | ( { __typename: 'IPV4Route' } & { ipv4Address: Ipv4Route['address'], ipv4Gateway: Ipv4Route['gateway'], } ) | ( { __typename: 'IPV6Route' } & { ipv6Address: Ipv6Route['address'], ipv6Gateway: Ipv6Route['gateway'], } ) > } ); " `; exports[`TypeScript Operations Plugin > Selection Set > Should have valid fragments intersection on different types (with usage) #2498 1`] = ` "export type TomFragment = ( { __typename?: 'Tom' } & Pick ); export type JerryFragment = ( { __typename?: 'Jerry' } & Pick ); type User_Tom_Fragment = ( { __typename?: 'Tom' } & Pick ); type User_Jerry_Fragment = ( { __typename?: 'Jerry' } & Pick ); export type UserFragment = | User_Tom_Fragment | User_Jerry_Fragment ; export type UserQueryQueryVariables = Exact<{ [key: string]: never; }>; export type UserQueryQuery = ( { __typename?: 'Query' } & { user?: Maybe< | ( { __typename?: 'Tom' } & Pick ) | ( { __typename?: 'Jerry' } & Pick ) > } ); " `; exports[`TypeScript Operations Plugin > Union & Interfaces > #4216 - handle fragments against unions and interfaces with flattenGeneratedTypes 1`] = ` "export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; search?: Maybe>; }; export type Concept = { id?: Maybe; }; export type Dimension = Concept & { __typename?: 'Dimension'; id?: Maybe; }; export type DimValue = { __typename?: 'DimValue'; dimension?: Maybe; value: Scalars['String']['output']; }; export type Searchable = Dimension | DimValue; export type SearchPopularQueryVariables = Exact<{ [key: string]: never; }>; export type SearchPopularQuery = ( { __typename?: 'Query' } & { search?: Maybe ) | ( { __typename?: 'DimValue' } & Pick & { dimension?: Maybe<( { __typename?: 'Dimension' } & Pick )> } ) >> } ); " `; exports[`TypeScript Operations Plugin > Union & Interfaces > Should handle union selection sets with both FragmentSpreads and InlineFragments 1`] = ` "export type UserQueryQueryVariables = Exact<{ [key: string]: never; }>; export type UserQueryQuery = ( { __typename?: 'Query' } & { user: | ( { __typename?: 'User' } & Pick ) | ( { __typename?: 'Error2' } & Pick ) | ( { __typename?: 'Error3' } & Pick & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } ) } ); export type AdditionalInfoFragment = ( { __typename?: 'AdditionalInfo' } & Pick ); type UserResult1_User_Fragment = ( { __typename?: 'User' } & Pick ); type UserResult1_Error2_Fragment = { __typename?: 'Error2' }; type UserResult1_Error3_Fragment = ( { __typename?: 'Error3' } & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } ); export type UserResult1Fragment = | UserResult1_User_Fragment | UserResult1_Error2_Fragment | UserResult1_Error3_Fragment ; type UserResult_User_Fragment = ( { __typename?: 'User' } & Pick ); type UserResult_Error2_Fragment = ( { __typename?: 'Error2' } & Pick ); type UserResult_Error3_Fragment = { __typename?: 'Error3' }; export type UserResultFragment = | UserResult_User_Fragment | UserResult_Error2_Fragment | UserResult_Error3_Fragment ; " `; exports[`TypeScript Operations Plugin > Union & Interfaces > Should handle union selection sets with both FragmentSpreads and InlineFragments with flattenGeneratedTypes 1`] = ` "export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Error = { message: Scalars['String']['output']; }; export type Error1 = Error & { __typename?: 'Error1'; message: Scalars['String']['output']; }; export type Error2 = Error & { __typename?: 'Error2'; message: Scalars['String']['output']; }; export type Error3 = Error & { __typename?: 'Error3'; message: Scalars['String']['output']; info?: Maybe; }; export type AdditionalInfo = { __typename?: 'AdditionalInfo'; message: Scalars['String']['output']; message2: Scalars['String']['output']; }; export type User = { __typename?: 'User'; id: Scalars['ID']['output']; login: Scalars['String']['output']; }; export type UserResult = User | Error2 | Error3; export type Query = { __typename?: 'Query'; user: UserResult; }; export type UserQueryQueryVariables = Exact<{ [key: string]: never; }>; export type UserQueryQuery = ( { __typename?: 'Query' } & { user: | ( { __typename?: 'User' } & Pick ) | ( { __typename?: 'Error2' } & Pick ) | ( { __typename?: 'Error3' } & Pick & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } ) } ); function t(q: UserQueryQuery) { if (q.user) { if (q.user.__typename === 'User') { if (q.user.id) { const u = q.user.login; } } if (q.user.__typename === 'Error2') { console.log(q.user.message); } if (q.user.__typename === 'Error3') { if (q.user.info) { console.log(q.user.info.__typename) } } } }" `; exports[`TypeScript Operations Plugin > Union & Interfaces > Should handle union selection sets with both FragmentSpreads and InlineFragments with flattenGeneratedTypes and directives 1`] = ` "export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Error = { message: Scalars['String']['output']; }; export type Error1 = Error & { __typename?: 'Error1'; message: Scalars['String']['output']; }; export type Error2 = Error & { __typename?: 'Error2'; message: Scalars['String']['output']; }; export type Error3 = Error & { __typename?: 'Error3'; message: Scalars['String']['output']; info?: Maybe; }; export type AdditionalInfo = { __typename?: 'AdditionalInfo'; message: Scalars['String']['output']; message2: Scalars['String']['output']; }; export type User = { __typename?: 'User'; id: Scalars['ID']['output']; login: Scalars['String']['output']; test?: Maybe; test2?: Maybe; }; export type UserResult = User | Error2 | Error3; export type Query = { __typename?: 'Query'; user: UserResult; }; export type UserQueryQueryVariables = Exact<{ [key: string]: never; }>; export type UserQueryQuery = ( { __typename?: 'Query' } & { user: | ( { __typename?: 'User' } & Pick< User, | 'id' | 'test2' | 'login' | 'test' > ) | ( { __typename?: 'Error2' } & Pick ) | ( { __typename?: 'Error3' } & Pick & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } ) } ); function t(q: UserQueryQuery) { if (q.user) { if (q.user.__typename === 'User') { if (q.user.id) { const u = q.user.login; } } if (q.user.__typename === 'Error2') { console.log(q.user.message); } if (q.user.__typename === 'Error3') { if (q.user.info) { console.log(q.user.info.__typename) } } } }" `; ================================================ FILE: packages/plugins/typescript/operations/tests/extract-all-types.spec.ts ================================================ import { mergeOutputs, Types } from '@graphql-codegen/plugin-helpers'; import { validateTs } from '@graphql-codegen/testing'; import { buildSchema, parse } from 'graphql'; import { plugin as tsPlugin } from '../../typescript/src/index.js'; import { plugin, TypeScriptDocumentsPluginConfig } from '../src/index.js'; describe('extractAllFieldsToTypes: true', () => { const validate = async (content: Types.PluginOutput, config: any = {}, pluginSchema) => { const m = mergeOutputs([await tsPlugin(pluginSchema, [], config, { outputFile: '' }), content]); validateTs(m, undefined, undefined, undefined, []); return m; }; const dummyUserTestSchema = buildSchema(/* GraphQL */ ` scalar Date type Query { me: User } interface User { id: ID! joinDate: Date! } type DummyUser implements User { id: ID! joinDate: Date! } type ActiveUser implements User { id: ID! joinDate: Date! isActive: Boolean! parentUser: User! thing: String! } `); const dummyUserDoc = parse(/* GraphQL */ ` fragment UserFragment on User { id joinDate } fragment Me on User { id ...UserFragment ... on ActiveUser { isActive parentUser { ...UserFragment } } } query OverlappingFieldsMergingTest { # this should be optimized to be: me { ...Me } since they're both selecting for 'id' me { id ...Me } } query NestedOverlappingFieldsMergingTest { # an optimization here would be for these to merge, # since ParentMe selects for the same things as the field selection in: me { id } me { ...Me ... on ActiveUser { isActive } } } `); it('should extract types from queries', async () => { const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: true, extractAllFieldsToTypes: true, printFieldsOnNewLines: true, nonOptionalTypename: true, dedupeOperationSuffix: true, }; const { content } = await plugin( dummyUserTestSchema, [{ location: 'test-file.ts', document: dummyUserDoc }], config, { outputFile: '' } ); expect(content).toMatchInlineSnapshot(` "type UserFragment_DummyUser = { __typename: 'DummyUser', id: string, joinDate: any }; type UserFragment_ActiveUser = { __typename: 'ActiveUser', id: string, joinDate: any }; export type UserFragment = | UserFragment_DummyUser | UserFragment_ActiveUser ; export type MeFragment_ActiveUser_parentUser_DummyUser = { __typename: 'DummyUser', id: string, joinDate: any }; export type MeFragment_ActiveUser_parentUser_ActiveUser = { __typename: 'ActiveUser', id: string, joinDate: any }; export type MeFragment_ActiveUser_parentUser = | MeFragment_ActiveUser_parentUser_DummyUser | MeFragment_ActiveUser_parentUser_ActiveUser ; type Me_DummyUser_Fragment = { __typename: 'DummyUser', id: string, joinDate: any }; type Me_ActiveUser_Fragment = { __typename: 'ActiveUser', isActive: boolean, id: string, joinDate: any, parentUser: MeFragment_ActiveUser_parentUser }; export type MeFragment = | Me_DummyUser_Fragment | Me_ActiveUser_Fragment ; export type OverlappingFieldsMergingTestQuery_me_DummyUser = { __typename: 'DummyUser', id: string, joinDate: any }; export type OverlappingFieldsMergingTestQuery_me_ActiveUser = { __typename: 'ActiveUser', id: string, isActive: boolean, joinDate: any, parentUser: MeFragment_ActiveUser_parentUser }; export type OverlappingFieldsMergingTestQuery_me = | OverlappingFieldsMergingTestQuery_me_DummyUser | OverlappingFieldsMergingTestQuery_me_ActiveUser ; export type OverlappingFieldsMergingTestQuery_Query = { __typename: 'Query', me?: OverlappingFieldsMergingTestQuery_me | null }; export type OverlappingFieldsMergingTestQueryVariables = Exact<{ [key: string]: never; }>; export type OverlappingFieldsMergingTestQuery = OverlappingFieldsMergingTestQuery_Query; export type NestedOverlappingFieldsMergingTestQuery_me_DummyUser = { __typename: 'DummyUser', id: string, joinDate: any }; export type NestedOverlappingFieldsMergingTestQuery_me_ActiveUser = { __typename: 'ActiveUser', isActive: boolean, id: string, joinDate: any, parentUser: MeFragment_ActiveUser_parentUser }; export type NestedOverlappingFieldsMergingTestQuery_me = | NestedOverlappingFieldsMergingTestQuery_me_DummyUser | NestedOverlappingFieldsMergingTestQuery_me_ActiveUser ; export type NestedOverlappingFieldsMergingTestQuery_Query = { __typename: 'Query', me?: NestedOverlappingFieldsMergingTestQuery_me | null }; export type NestedOverlappingFieldsMergingTestQueryVariables = Exact<{ [key: string]: never; }>; export type NestedOverlappingFieldsMergingTestQuery = NestedOverlappingFieldsMergingTestQuery_Query; " `); await validate(content, config, dummyUserTestSchema); }); const complexTestSchemaWithUnionsAndInterfaces = buildSchema(/* GraphQL */ ` interface GenericCallSummary { id: ID! timestamp: String! summary: String! isTrusted: Boolean! } type CallerID { phone: String! formattedPhone: String! name: String } enum CallType { OUTGOING INCOMING VOICEMAIL UNKNOWN } type TalkInteraction { channel: String! rel: String type: CallType! from: CallerID to: CallerID } interface ConnectionNode { id: ID! } interface ConversationEvent implements ConnectionNode { id: ID! timestamp: String! originatedFrom: OriginatedFrom! } type BrokenConversationEvent implements ConversationEvent & ConnectionNode { id: ID! timestamp: String! originatedFrom: OriginatedFrom! extraField: String! } union OriginatedFrom = EmailInteraction | CustomChannelInteraction | TalkInteraction | NativeMessagingInteraction | WhatsAppInteraction | WeChatInteraction | NotImplementedOriginatedFrom type NotImplementedOriginatedFrom { channel: String rel: String } type EmailInteraction { originalEmailURLPath: String! } interface ChannelInteraction { externalId: String! timestamp: String! resourceType: String! version: Int! } type CustomChannelInteraction implements ChannelInteraction { externalId: String! timestamp: String! resourceType: String! version: Int! } interface BrandedConversation { conversationId: ID } type NativeMessagingInteraction implements BrandedConversation { conversationId: ID } type WhatsAppInteraction implements BrandedConversation { conversationId: ID } type WeChatInteraction implements BrandedConversation { conversationId: ID } type ArchivedArticle { id: ID! title: String! url: String! htmlUrl: String! } type BotSolution implements ConnectionNode & ConversationEvent { id: ID! timestamp: String! originatedFrom: OriginatedFrom! article: ArchivedArticle! } type TalkPublicCallSummary implements ConnectionNode & ConversationEvent & GenericCallSummary { id: ID! timestamp: String! summary: String! isTrusted: Boolean! originatedFrom: OriginatedFrom! } `); const fragmentsOnComplexSchema = parse(/* GraphQL */ ` fragment ConversationBotSolution on BotSolution { id ...ConversationConversationEvent article { id htmlUrl title url } originatedFrom { ...ConversationOriginatedFrom } } fragment ConversationGenericCallSummary on GenericCallSummary { id summary } fragment ConversationTalkInteraction on TalkInteraction { channel type } fragment ConversationConversationEvent on ConversationEvent { __typename id timestamp originatedFrom { ...ConversationOriginatedFrom } } fragment MessageEnvelopeData on OriginatedFrom { ... on EmailInteraction { originalEmailURLPath } } fragment AnyChannelOriginatedFrom on CustomChannelInteraction { externalId timestamp resourceType } fragment ConversationOriginatedFrom on OriginatedFrom { __typename ... on BrandedConversation { conversationId } ...MessageEnvelopeData ...AnyChannelOriginatedFrom } fragment ConversationTalkPublicCallSummary on TalkPublicCallSummary { id ...ConversationConversationEvent ...ConversationGenericCallSummary originatedFrom { ... on TalkInteraction { ...ConversationTalkInteraction } } } `); it('should extract types from multiple fragments', async () => { const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: true, extractAllFieldsToTypes: true, nonOptionalTypename: true, dedupeOperationSuffix: true, }; const { content } = await plugin( complexTestSchemaWithUnionsAndInterfaces, [{ location: 'test-file.ts', document: fragmentsOnComplexSchema }], config, { outputFile: '' } ); expect(content).toMatchInlineSnapshot(` "export type ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle = { __typename: 'ArchivedArticle', id: string, htmlUrl: string, title: string, url: string }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction = { __typename: 'EmailInteraction', originalEmailURLPath: string }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction = { __typename: 'CustomChannelInteraction', externalId: string, timestamp: string, resourceType: string }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction = { __typename: 'TalkInteraction' }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction = { __typename: 'NativeMessagingInteraction', conversationId?: string | null }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_WhatsAppInteraction = { __typename: 'WhatsAppInteraction', conversationId?: string | null }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_WeChatInteraction = { __typename: 'WeChatInteraction', conversationId?: string | null }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_NotImplementedOriginatedFrom = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom = | ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_WhatsAppInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_WeChatInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_NotImplementedOriginatedFrom ; export type ConversationBotSolutionFragment = { __typename: 'BotSolution', id: string, timestamp: string, article: ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle, originatedFrom: ConversationBotSolutionFragment_BotSolution_originatedFrom }; export type ConversationGenericCallSummaryFragment = { __typename: 'TalkPublicCallSummary', id: string, summary: string }; export type ConversationTalkInteractionFragment = { __typename: 'TalkInteraction', channel: string, type: CallType }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction = { __typename: 'EmailInteraction', originalEmailURLPath: string }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction = { __typename: 'CustomChannelInteraction', externalId: string, timestamp: string, resourceType: string }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction = { __typename: 'TalkInteraction' }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction = { __typename: 'NativeMessagingInteraction', conversationId?: string | null }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_WhatsAppInteraction = { __typename: 'WhatsAppInteraction', conversationId?: string | null }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_WeChatInteraction = { __typename: 'WeChatInteraction', conversationId?: string | null }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_NotImplementedOriginatedFrom = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom = | ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_WhatsAppInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_WeChatInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_NotImplementedOriginatedFrom ; type ConversationConversationEvent_BrokenConversationEvent_Fragment = { __typename: 'BrokenConversationEvent', id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom }; type ConversationConversationEvent_BotSolution_Fragment = { __typename: 'BotSolution', id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom }; type ConversationConversationEvent_TalkPublicCallSummary_Fragment = { __typename: 'TalkPublicCallSummary', id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom }; export type ConversationConversationEventFragment = | ConversationConversationEvent_BrokenConversationEvent_Fragment | ConversationConversationEvent_BotSolution_Fragment | ConversationConversationEvent_TalkPublicCallSummary_Fragment ; type MessageEnvelopeData_EmailInteraction_Fragment = { __typename: 'EmailInteraction', originalEmailURLPath: string }; type MessageEnvelopeData_CustomChannelInteraction_Fragment = { __typename: 'CustomChannelInteraction' }; type MessageEnvelopeData_TalkInteraction_Fragment = { __typename: 'TalkInteraction' }; type MessageEnvelopeData_NativeMessagingInteraction_Fragment = { __typename: 'NativeMessagingInteraction' }; type MessageEnvelopeData_WhatsAppInteraction_Fragment = { __typename: 'WhatsAppInteraction' }; type MessageEnvelopeData_WeChatInteraction_Fragment = { __typename: 'WeChatInteraction' }; type MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment = { __typename: 'NotImplementedOriginatedFrom' }; export type MessageEnvelopeDataFragment = | MessageEnvelopeData_EmailInteraction_Fragment | MessageEnvelopeData_CustomChannelInteraction_Fragment | MessageEnvelopeData_TalkInteraction_Fragment | MessageEnvelopeData_NativeMessagingInteraction_Fragment | MessageEnvelopeData_WhatsAppInteraction_Fragment | MessageEnvelopeData_WeChatInteraction_Fragment | MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment ; export type AnyChannelOriginatedFromFragment = { __typename: 'CustomChannelInteraction', externalId: string, timestamp: string, resourceType: string }; type ConversationOriginatedFrom_EmailInteraction_Fragment = { __typename: 'EmailInteraction', originalEmailURLPath: string }; type ConversationOriginatedFrom_CustomChannelInteraction_Fragment = { __typename: 'CustomChannelInteraction', externalId: string, timestamp: string, resourceType: string }; type ConversationOriginatedFrom_TalkInteraction_Fragment = { __typename: 'TalkInteraction' }; type ConversationOriginatedFrom_NativeMessagingInteraction_Fragment = { __typename: 'NativeMessagingInteraction', conversationId?: string | null }; type ConversationOriginatedFrom_WhatsAppInteraction_Fragment = { __typename: 'WhatsAppInteraction', conversationId?: string | null }; type ConversationOriginatedFrom_WeChatInteraction_Fragment = { __typename: 'WeChatInteraction', conversationId?: string | null }; type ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationOriginatedFromFragment = | ConversationOriginatedFrom_EmailInteraction_Fragment | ConversationOriginatedFrom_CustomChannelInteraction_Fragment | ConversationOriginatedFrom_TalkInteraction_Fragment | ConversationOriginatedFrom_NativeMessagingInteraction_Fragment | ConversationOriginatedFrom_WhatsAppInteraction_Fragment | ConversationOriginatedFrom_WeChatInteraction_Fragment | ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment ; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction = { __typename: 'EmailInteraction', originalEmailURLPath: string }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction = { __typename: 'CustomChannelInteraction', externalId: string, timestamp: string, resourceType: string }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction = { __typename: 'TalkInteraction', channel: string, type: CallType }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction = { __typename: 'NativeMessagingInteraction', conversationId?: string | null }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WhatsAppInteraction = { __typename: 'WhatsAppInteraction', conversationId?: string | null }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WeChatInteraction = { __typename: 'WeChatInteraction', conversationId?: string | null }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom = | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WhatsAppInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WeChatInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom ; export type ConversationTalkPublicCallSummaryFragment = { __typename: 'TalkPublicCallSummary', id: string, timestamp: string, summary: string, originatedFrom: ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom }; " `); await validate(content, config, complexTestSchemaWithUnionsAndInterfaces); }); it('should extract types from multiple fragments (mergeFragmentTypes: true)', async () => { const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: true, extractAllFieldsToTypes: true, nonOptionalTypename: true, dedupeOperationSuffix: true, mergeFragmentTypes: true, }; const { content } = await plugin( complexTestSchemaWithUnionsAndInterfaces, [{ location: 'test-file.ts', document: fragmentsOnComplexSchema }], config, { outputFile: '' } ); expect(content).toMatchInlineSnapshot(` "export type ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle = ( { id: string, htmlUrl: string, title: string, url: string } & { __typename: 'ArchivedArticle' } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction = ( { originalEmailURLPath: string } & { __typename: 'EmailInteraction' } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction = ( { externalId: string, timestamp: string, resourceType: string } & { __typename: 'CustomChannelInteraction' } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction_NotImplementedOriginatedFrom = { __typename: 'TalkInteraction' | 'NotImplementedOriginatedFrom' }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction_WhatsAppInteraction_WeChatInteraction = ( { conversationId?: string | null } & { __typename: 'NativeMessagingInteraction' | 'WhatsAppInteraction' | 'WeChatInteraction' } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom = | ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction_NotImplementedOriginatedFrom | ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction_WhatsAppInteraction_WeChatInteraction ; export type ConversationBotSolutionFragment = ( { id: string, timestamp: string, article: ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle, originatedFrom: ConversationBotSolutionFragment_BotSolution_originatedFrom } & { __typename: 'BotSolution' } ); export type ConversationGenericCallSummaryFragment = ( { id: string, summary: string } & { __typename: 'TalkPublicCallSummary' } ); export type ConversationTalkInteractionFragment = ( { channel: string, type: CallType } & { __typename: 'TalkInteraction' } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction = ( { originalEmailURLPath: string } & { __typename: 'EmailInteraction' } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction = ( { externalId: string, timestamp: string, resourceType: string } & { __typename: 'CustomChannelInteraction' } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction_NotImplementedOriginatedFrom = { __typename: 'TalkInteraction' | 'NotImplementedOriginatedFrom' }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction_WhatsAppInteraction_WeChatInteraction = ( { conversationId?: string | null } & { __typename: 'NativeMessagingInteraction' | 'WhatsAppInteraction' | 'WeChatInteraction' } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom = | ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction_NotImplementedOriginatedFrom | ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction_WhatsAppInteraction_WeChatInteraction ; export type ConversationConversationEventFragment = ( { id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom } & { __typename: 'BrokenConversationEvent' | 'BotSolution' | 'TalkPublicCallSummary' } ); type MessageEnvelopeData_EmailInteraction_Fragment = ( { originalEmailURLPath: string } & { __typename: 'EmailInteraction' } ); type MessageEnvelopeData_8FBboKcmuva72FpaH1zuPdoYyrlyvueTn9fqP1dFi_Fragment = { __typename: 'CustomChannelInteraction' | 'TalkInteraction' | 'NativeMessagingInteraction' | 'WhatsAppInteraction' | 'WeChatInteraction' | 'NotImplementedOriginatedFrom' }; export type MessageEnvelopeDataFragment = | MessageEnvelopeData_EmailInteraction_Fragment | MessageEnvelopeData_8FBboKcmuva72FpaH1zuPdoYyrlyvueTn9fqP1dFi_Fragment ; export type AnyChannelOriginatedFromFragment = ( { externalId: string, timestamp: string, resourceType: string } & { __typename: 'CustomChannelInteraction' } ); type ConversationOriginatedFrom_EmailInteraction_Fragment = ( { originalEmailURLPath: string } & { __typename: 'EmailInteraction' } ); type ConversationOriginatedFrom_CustomChannelInteraction_Fragment = ( { externalId: string, timestamp: string, resourceType: string } & { __typename: 'CustomChannelInteraction' } ); type ConversationOriginatedFrom_TalkInteraction_NotImplementedOriginatedFrom_Fragment = { __typename: 'TalkInteraction' | 'NotImplementedOriginatedFrom' }; type ConversationOriginatedFrom_NativeMessagingInteraction_WhatsAppInteraction_WeChatInteraction_Fragment = ( { conversationId?: string | null } & { __typename: 'NativeMessagingInteraction' | 'WhatsAppInteraction' | 'WeChatInteraction' } ); export type ConversationOriginatedFromFragment = | ConversationOriginatedFrom_EmailInteraction_Fragment | ConversationOriginatedFrom_CustomChannelInteraction_Fragment | ConversationOriginatedFrom_TalkInteraction_NotImplementedOriginatedFrom_Fragment | ConversationOriginatedFrom_NativeMessagingInteraction_WhatsAppInteraction_WeChatInteraction_Fragment ; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction = ( { originalEmailURLPath: string } & { __typename: 'EmailInteraction' } ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction = ( { externalId: string, timestamp: string, resourceType: string } & { __typename: 'CustomChannelInteraction' } ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction = ( { channel: string, type: CallType } & { __typename: 'TalkInteraction' } ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction_WhatsAppInteraction_WeChatInteraction = ( { conversationId?: string | null } & { __typename: 'NativeMessagingInteraction' | 'WhatsAppInteraction' | 'WeChatInteraction' } ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom = | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction_WhatsAppInteraction_WeChatInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom ; export type ConversationTalkPublicCallSummaryFragment = ( { id: string, timestamp: string, summary: string, originatedFrom: ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom } & { __typename: 'TalkPublicCallSummary' } ); " `); await validate(content, config, complexTestSchemaWithUnionsAndInterfaces); }); it("should extract types from multiple fragments (inlineFragmentTypes: 'combine')", async () => { const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: true, extractAllFieldsToTypes: true, nonOptionalTypename: true, dedupeOperationSuffix: true, inlineFragmentTypes: 'combine', }; const { content } = await plugin( complexTestSchemaWithUnionsAndInterfaces, [{ location: 'test-file.ts', document: fragmentsOnComplexSchema }], config, { outputFile: '' } ); expect(content).toMatchInlineSnapshot(` "export type ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle = { __typename: 'ArchivedArticle', id: string, htmlUrl: string, title: string, url: string }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction = ( { __typename: 'EmailInteraction' } & ConversationOriginatedFrom_EmailInteraction_Fragment ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction = ( { __typename: 'CustomChannelInteraction' } & ConversationOriginatedFrom_CustomChannelInteraction_Fragment ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction = ( { __typename: 'TalkInteraction' } & ConversationOriginatedFrom_TalkInteraction_Fragment ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction = ( { __typename: 'NativeMessagingInteraction' } & ConversationOriginatedFrom_NativeMessagingInteraction_Fragment ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_WhatsAppInteraction = ( { __typename: 'WhatsAppInteraction' } & ConversationOriginatedFrom_WhatsAppInteraction_Fragment ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_WeChatInteraction = ( { __typename: 'WeChatInteraction' } & ConversationOriginatedFrom_WeChatInteraction_Fragment ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_NotImplementedOriginatedFrom = ( { __typename: 'NotImplementedOriginatedFrom' } & ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom = | ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_WhatsAppInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_WeChatInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_NotImplementedOriginatedFrom ; export type ConversationBotSolutionFragment = ( { __typename: 'BotSolution', id: string, article: ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle, originatedFrom: ConversationBotSolutionFragment_BotSolution_originatedFrom } & ConversationConversationEvent_BotSolution_Fragment ); export type ConversationGenericCallSummaryFragment = { __typename: 'TalkPublicCallSummary', id: string, summary: string }; export type ConversationTalkInteractionFragment = { __typename: 'TalkInteraction', channel: string, type: CallType }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction = ( { __typename: 'EmailInteraction' } & ConversationOriginatedFrom_EmailInteraction_Fragment ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction = ( { __typename: 'CustomChannelInteraction' } & ConversationOriginatedFrom_CustomChannelInteraction_Fragment ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction = ( { __typename: 'TalkInteraction' } & ConversationOriginatedFrom_TalkInteraction_Fragment ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction = ( { __typename: 'NativeMessagingInteraction' } & ConversationOriginatedFrom_NativeMessagingInteraction_Fragment ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_WhatsAppInteraction = ( { __typename: 'WhatsAppInteraction' } & ConversationOriginatedFrom_WhatsAppInteraction_Fragment ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_WeChatInteraction = ( { __typename: 'WeChatInteraction' } & ConversationOriginatedFrom_WeChatInteraction_Fragment ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_NotImplementedOriginatedFrom = ( { __typename: 'NotImplementedOriginatedFrom' } & ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom = | ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_WhatsAppInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_WeChatInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_NotImplementedOriginatedFrom ; type ConversationConversationEvent_BrokenConversationEvent_Fragment = { __typename: 'BrokenConversationEvent', id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom }; type ConversationConversationEvent_BotSolution_Fragment = { __typename: 'BotSolution', id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom }; type ConversationConversationEvent_TalkPublicCallSummary_Fragment = { __typename: 'TalkPublicCallSummary', id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom }; export type ConversationConversationEventFragment = | ConversationConversationEvent_BrokenConversationEvent_Fragment | ConversationConversationEvent_BotSolution_Fragment | ConversationConversationEvent_TalkPublicCallSummary_Fragment ; type MessageEnvelopeData_EmailInteraction_Fragment = { __typename: 'EmailInteraction', originalEmailURLPath: string }; type MessageEnvelopeData_CustomChannelInteraction_Fragment = { __typename: 'CustomChannelInteraction' }; type MessageEnvelopeData_TalkInteraction_Fragment = { __typename: 'TalkInteraction' }; type MessageEnvelopeData_NativeMessagingInteraction_Fragment = { __typename: 'NativeMessagingInteraction' }; type MessageEnvelopeData_WhatsAppInteraction_Fragment = { __typename: 'WhatsAppInteraction' }; type MessageEnvelopeData_WeChatInteraction_Fragment = { __typename: 'WeChatInteraction' }; type MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment = { __typename: 'NotImplementedOriginatedFrom' }; export type MessageEnvelopeDataFragment = | MessageEnvelopeData_EmailInteraction_Fragment | MessageEnvelopeData_CustomChannelInteraction_Fragment | MessageEnvelopeData_TalkInteraction_Fragment | MessageEnvelopeData_NativeMessagingInteraction_Fragment | MessageEnvelopeData_WhatsAppInteraction_Fragment | MessageEnvelopeData_WeChatInteraction_Fragment | MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment ; export type AnyChannelOriginatedFromFragment = { __typename: 'CustomChannelInteraction', externalId: string, timestamp: string, resourceType: string }; type ConversationOriginatedFrom_EmailInteraction_Fragment = ( { __typename: 'EmailInteraction' } & MessageEnvelopeData_EmailInteraction_Fragment ); type ConversationOriginatedFrom_CustomChannelInteraction_Fragment = ( { __typename: 'CustomChannelInteraction' } & MessageEnvelopeData_CustomChannelInteraction_Fragment & AnyChannelOriginatedFromFragment ); type ConversationOriginatedFrom_TalkInteraction_Fragment = ( { __typename: 'TalkInteraction' } & MessageEnvelopeData_TalkInteraction_Fragment ); type ConversationOriginatedFrom_NativeMessagingInteraction_Fragment = ( { __typename: 'NativeMessagingInteraction', conversationId?: string | null } & MessageEnvelopeData_NativeMessagingInteraction_Fragment ); type ConversationOriginatedFrom_WhatsAppInteraction_Fragment = ( { __typename: 'WhatsAppInteraction', conversationId?: string | null } & MessageEnvelopeData_WhatsAppInteraction_Fragment ); type ConversationOriginatedFrom_WeChatInteraction_Fragment = ( { __typename: 'WeChatInteraction', conversationId?: string | null } & MessageEnvelopeData_WeChatInteraction_Fragment ); type ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment = ( { __typename: 'NotImplementedOriginatedFrom' } & MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment ); export type ConversationOriginatedFromFragment = | ConversationOriginatedFrom_EmailInteraction_Fragment | ConversationOriginatedFrom_CustomChannelInteraction_Fragment | ConversationOriginatedFrom_TalkInteraction_Fragment | ConversationOriginatedFrom_NativeMessagingInteraction_Fragment | ConversationOriginatedFrom_WhatsAppInteraction_Fragment | ConversationOriginatedFrom_WeChatInteraction_Fragment | ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment ; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction = { __typename: 'EmailInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction = { __typename: 'CustomChannelInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction = ( { __typename: 'TalkInteraction' } & ConversationTalkInteractionFragment ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction = { __typename: 'NativeMessagingInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WhatsAppInteraction = { __typename: 'WhatsAppInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WeChatInteraction = { __typename: 'WeChatInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom = | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WhatsAppInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WeChatInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom ; export type ConversationTalkPublicCallSummaryFragment = ( { __typename: 'TalkPublicCallSummary', id: string, originatedFrom: ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom } & ConversationConversationEvent_TalkPublicCallSummary_Fragment & ConversationGenericCallSummaryFragment ); " `); await validate(content, config, complexTestSchemaWithUnionsAndInterfaces); }); it("should extract types from multiple fragments (inlineFragmentTypes: 'mask')", async () => { const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: true, extractAllFieldsToTypes: true, nonOptionalTypename: true, dedupeOperationSuffix: true, inlineFragmentTypes: 'mask', }; const { content } = await plugin( complexTestSchemaWithUnionsAndInterfaces, [{ location: 'test-file.ts', document: fragmentsOnComplexSchema }], config, { outputFile: '' } ); expect(content).toMatchInlineSnapshot(` "export type ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle = { __typename: 'ArchivedArticle', id: string, htmlUrl: string, title: string, url: string }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction = ( { __typename: 'EmailInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_EmailInteraction_Fragment': ConversationOriginatedFrom_EmailInteraction_Fragment } } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction = ( { __typename: 'CustomChannelInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_CustomChannelInteraction_Fragment': ConversationOriginatedFrom_CustomChannelInteraction_Fragment } } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction = ( { __typename: 'TalkInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_TalkInteraction_Fragment': ConversationOriginatedFrom_TalkInteraction_Fragment } } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction = ( { __typename: 'NativeMessagingInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_NativeMessagingInteraction_Fragment': ConversationOriginatedFrom_NativeMessagingInteraction_Fragment } } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_WhatsAppInteraction = ( { __typename: 'WhatsAppInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_WhatsAppInteraction_Fragment': ConversationOriginatedFrom_WhatsAppInteraction_Fragment } } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_WeChatInteraction = ( { __typename: 'WeChatInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_WeChatInteraction_Fragment': ConversationOriginatedFrom_WeChatInteraction_Fragment } } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_NotImplementedOriginatedFrom = ( { __typename: 'NotImplementedOriginatedFrom' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment': ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment } } ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom = | ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_WhatsAppInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_WeChatInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_NotImplementedOriginatedFrom ; export type ConversationBotSolutionFragment = ( { __typename: 'BotSolution', id: string, article: ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle, originatedFrom: ConversationBotSolutionFragment_BotSolution_originatedFrom } & { ' $fragmentRefs'?: { 'ConversationConversationEvent_BotSolution_Fragment': ConversationConversationEvent_BotSolution_Fragment } } ) & { ' $fragmentName'?: 'ConversationBotSolutionFragment' }; export type ConversationGenericCallSummaryFragment = { __typename: 'TalkPublicCallSummary', id: string, summary: string } & { ' $fragmentName'?: 'ConversationGenericCallSummaryFragment' }; export type ConversationTalkInteractionFragment = { __typename: 'TalkInteraction', channel: string, type: CallType } & { ' $fragmentName'?: 'ConversationTalkInteractionFragment' }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction = ( { __typename: 'EmailInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_EmailInteraction_Fragment': ConversationOriginatedFrom_EmailInteraction_Fragment } } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction = ( { __typename: 'CustomChannelInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_CustomChannelInteraction_Fragment': ConversationOriginatedFrom_CustomChannelInteraction_Fragment } } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction = ( { __typename: 'TalkInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_TalkInteraction_Fragment': ConversationOriginatedFrom_TalkInteraction_Fragment } } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction = ( { __typename: 'NativeMessagingInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_NativeMessagingInteraction_Fragment': ConversationOriginatedFrom_NativeMessagingInteraction_Fragment } } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_WhatsAppInteraction = ( { __typename: 'WhatsAppInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_WhatsAppInteraction_Fragment': ConversationOriginatedFrom_WhatsAppInteraction_Fragment } } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_WeChatInteraction = ( { __typename: 'WeChatInteraction' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_WeChatInteraction_Fragment': ConversationOriginatedFrom_WeChatInteraction_Fragment } } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_NotImplementedOriginatedFrom = ( { __typename: 'NotImplementedOriginatedFrom' } & { ' $fragmentRefs'?: { 'ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment': ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment } } ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom = | ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_WhatsAppInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_WeChatInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_NotImplementedOriginatedFrom ; type ConversationConversationEvent_BrokenConversationEvent_Fragment = { __typename: 'BrokenConversationEvent', id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom } & { ' $fragmentName'?: 'ConversationConversationEvent_BrokenConversationEvent_Fragment' }; type ConversationConversationEvent_BotSolution_Fragment = { __typename: 'BotSolution', id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom } & { ' $fragmentName'?: 'ConversationConversationEvent_BotSolution_Fragment' }; type ConversationConversationEvent_TalkPublicCallSummary_Fragment = { __typename: 'TalkPublicCallSummary', id: string, timestamp: string, originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom } & { ' $fragmentName'?: 'ConversationConversationEvent_TalkPublicCallSummary_Fragment' }; export type ConversationConversationEventFragment = | ConversationConversationEvent_BrokenConversationEvent_Fragment | ConversationConversationEvent_BotSolution_Fragment | ConversationConversationEvent_TalkPublicCallSummary_Fragment ; type MessageEnvelopeData_EmailInteraction_Fragment = { __typename: 'EmailInteraction', originalEmailURLPath: string } & { ' $fragmentName'?: 'MessageEnvelopeData_EmailInteraction_Fragment' }; type MessageEnvelopeData_CustomChannelInteraction_Fragment = { __typename: 'CustomChannelInteraction' } & { ' $fragmentName'?: 'MessageEnvelopeData_CustomChannelInteraction_Fragment' }; type MessageEnvelopeData_TalkInteraction_Fragment = { __typename: 'TalkInteraction' } & { ' $fragmentName'?: 'MessageEnvelopeData_TalkInteraction_Fragment' }; type MessageEnvelopeData_NativeMessagingInteraction_Fragment = { __typename: 'NativeMessagingInteraction' } & { ' $fragmentName'?: 'MessageEnvelopeData_NativeMessagingInteraction_Fragment' }; type MessageEnvelopeData_WhatsAppInteraction_Fragment = { __typename: 'WhatsAppInteraction' } & { ' $fragmentName'?: 'MessageEnvelopeData_WhatsAppInteraction_Fragment' }; type MessageEnvelopeData_WeChatInteraction_Fragment = { __typename: 'WeChatInteraction' } & { ' $fragmentName'?: 'MessageEnvelopeData_WeChatInteraction_Fragment' }; type MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment = { __typename: 'NotImplementedOriginatedFrom' } & { ' $fragmentName'?: 'MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment' }; export type MessageEnvelopeDataFragment = | MessageEnvelopeData_EmailInteraction_Fragment | MessageEnvelopeData_CustomChannelInteraction_Fragment | MessageEnvelopeData_TalkInteraction_Fragment | MessageEnvelopeData_NativeMessagingInteraction_Fragment | MessageEnvelopeData_WhatsAppInteraction_Fragment | MessageEnvelopeData_WeChatInteraction_Fragment | MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment ; export type AnyChannelOriginatedFromFragment = { __typename: 'CustomChannelInteraction', externalId: string, timestamp: string, resourceType: string } & { ' $fragmentName'?: 'AnyChannelOriginatedFromFragment' }; type ConversationOriginatedFrom_EmailInteraction_Fragment = ( { __typename: 'EmailInteraction' } & { ' $fragmentRefs'?: { 'MessageEnvelopeData_EmailInteraction_Fragment': MessageEnvelopeData_EmailInteraction_Fragment } } ) & { ' $fragmentName'?: 'ConversationOriginatedFrom_EmailInteraction_Fragment' }; type ConversationOriginatedFrom_CustomChannelInteraction_Fragment = ( { __typename: 'CustomChannelInteraction' } & { ' $fragmentRefs'?: { 'MessageEnvelopeData_CustomChannelInteraction_Fragment': MessageEnvelopeData_CustomChannelInteraction_Fragment;'AnyChannelOriginatedFromFragment': AnyChannelOriginatedFromFragment } } ) & { ' $fragmentName'?: 'ConversationOriginatedFrom_CustomChannelInteraction_Fragment' }; type ConversationOriginatedFrom_TalkInteraction_Fragment = ( { __typename: 'TalkInteraction' } & { ' $fragmentRefs'?: { 'MessageEnvelopeData_TalkInteraction_Fragment': MessageEnvelopeData_TalkInteraction_Fragment } } ) & { ' $fragmentName'?: 'ConversationOriginatedFrom_TalkInteraction_Fragment' }; type ConversationOriginatedFrom_NativeMessagingInteraction_Fragment = ( { __typename: 'NativeMessagingInteraction', conversationId?: string | null } & { ' $fragmentRefs'?: { 'MessageEnvelopeData_NativeMessagingInteraction_Fragment': MessageEnvelopeData_NativeMessagingInteraction_Fragment } } ) & { ' $fragmentName'?: 'ConversationOriginatedFrom_NativeMessagingInteraction_Fragment' }; type ConversationOriginatedFrom_WhatsAppInteraction_Fragment = ( { __typename: 'WhatsAppInteraction', conversationId?: string | null } & { ' $fragmentRefs'?: { 'MessageEnvelopeData_WhatsAppInteraction_Fragment': MessageEnvelopeData_WhatsAppInteraction_Fragment } } ) & { ' $fragmentName'?: 'ConversationOriginatedFrom_WhatsAppInteraction_Fragment' }; type ConversationOriginatedFrom_WeChatInteraction_Fragment = ( { __typename: 'WeChatInteraction', conversationId?: string | null } & { ' $fragmentRefs'?: { 'MessageEnvelopeData_WeChatInteraction_Fragment': MessageEnvelopeData_WeChatInteraction_Fragment } } ) & { ' $fragmentName'?: 'ConversationOriginatedFrom_WeChatInteraction_Fragment' }; type ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment = ( { __typename: 'NotImplementedOriginatedFrom' } & { ' $fragmentRefs'?: { 'MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment': MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment } } ) & { ' $fragmentName'?: 'ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment' }; export type ConversationOriginatedFromFragment = | ConversationOriginatedFrom_EmailInteraction_Fragment | ConversationOriginatedFrom_CustomChannelInteraction_Fragment | ConversationOriginatedFrom_TalkInteraction_Fragment | ConversationOriginatedFrom_NativeMessagingInteraction_Fragment | ConversationOriginatedFrom_WhatsAppInteraction_Fragment | ConversationOriginatedFrom_WeChatInteraction_Fragment | ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment ; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction = { __typename: 'EmailInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction = { __typename: 'CustomChannelInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction = ( { __typename: 'TalkInteraction' } & { ' $fragmentRefs'?: { 'ConversationTalkInteractionFragment': ConversationTalkInteractionFragment } } ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction = { __typename: 'NativeMessagingInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WhatsAppInteraction = { __typename: 'WhatsAppInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WeChatInteraction = { __typename: 'WeChatInteraction' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom = | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WhatsAppInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WeChatInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom ; export type ConversationTalkPublicCallSummaryFragment = ( { __typename: 'TalkPublicCallSummary', id: string, originatedFrom: ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom } & { ' $fragmentRefs'?: { 'ConversationConversationEvent_TalkPublicCallSummary_Fragment': ConversationConversationEvent_TalkPublicCallSummary_Fragment;'ConversationGenericCallSummaryFragment': ConversationGenericCallSummaryFragment } } ) & { ' $fragmentName'?: 'ConversationTalkPublicCallSummaryFragment' }; " `); await validate(content, config, complexTestSchemaWithUnionsAndInterfaces); }); it('should extract types from multiple fragments (preResolveTypes: false)', async () => { const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: false, extractAllFieldsToTypes: true, nonOptionalTypename: true, dedupeOperationSuffix: true, }; const { content } = await plugin( complexTestSchemaWithUnionsAndInterfaces, [{ location: 'test-file.ts', document: fragmentsOnComplexSchema }], config, { outputFile: '' } ); expect(content).toMatchInlineSnapshot(` "export type ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle = ( { __typename: 'ArchivedArticle' } & Pick< ArchivedArticle, | 'id' | 'htmlUrl' | 'title' | 'url' > ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction = ( { __typename: 'EmailInteraction' } & Pick ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction = ( { __typename: 'CustomChannelInteraction' } & Pick ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction = { __typename: 'TalkInteraction' }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction = ( { __typename: 'NativeMessagingInteraction' } & Pick ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_WhatsAppInteraction = ( { __typename: 'WhatsAppInteraction' } & Pick ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_WeChatInteraction = ( { __typename: 'WeChatInteraction' } & Pick ); export type ConversationBotSolutionFragment_BotSolution_originatedFrom_NotImplementedOriginatedFrom = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationBotSolutionFragment_BotSolution_originatedFrom = | ConversationBotSolutionFragment_BotSolution_originatedFrom_EmailInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_CustomChannelInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_TalkInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_NativeMessagingInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_WhatsAppInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_WeChatInteraction | ConversationBotSolutionFragment_BotSolution_originatedFrom_NotImplementedOriginatedFrom ; export type ConversationBotSolutionFragment = ( { __typename: 'BotSolution' } & Pick & { article: ConversationBotSolutionFragment_BotSolution_article_ArchivedArticle, originatedFrom: ConversationBotSolutionFragment_BotSolution_originatedFrom, } ); export type ConversationGenericCallSummaryFragment = ( { __typename: 'TalkPublicCallSummary' } & Pick ); export type ConversationTalkInteractionFragment = ( { __typename: 'TalkInteraction' } & Pick ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction = ( { __typename: 'EmailInteraction' } & Pick ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction = ( { __typename: 'CustomChannelInteraction' } & Pick ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction = { __typename: 'TalkInteraction' }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction = ( { __typename: 'NativeMessagingInteraction' } & Pick ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_WhatsAppInteraction = ( { __typename: 'WhatsAppInteraction' } & Pick ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_WeChatInteraction = ( { __typename: 'WeChatInteraction' } & Pick ); export type ConversationConversationEventFragment_ConversationEvent_originatedFrom_NotImplementedOriginatedFrom = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationConversationEventFragment_ConversationEvent_originatedFrom = | ConversationConversationEventFragment_ConversationEvent_originatedFrom_EmailInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_CustomChannelInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_TalkInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_NativeMessagingInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_WhatsAppInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_WeChatInteraction | ConversationConversationEventFragment_ConversationEvent_originatedFrom_NotImplementedOriginatedFrom ; type ConversationConversationEvent_BrokenConversationEvent_Fragment = ( { __typename: 'BrokenConversationEvent' } & Pick & { originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom } ); type ConversationConversationEvent_BotSolution_Fragment = ( { __typename: 'BotSolution' } & Pick & { originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom } ); type ConversationConversationEvent_TalkPublicCallSummary_Fragment = ( { __typename: 'TalkPublicCallSummary' } & Pick & { originatedFrom: ConversationConversationEventFragment_ConversationEvent_originatedFrom } ); export type ConversationConversationEventFragment = | ConversationConversationEvent_BrokenConversationEvent_Fragment | ConversationConversationEvent_BotSolution_Fragment | ConversationConversationEvent_TalkPublicCallSummary_Fragment ; type MessageEnvelopeData_EmailInteraction_Fragment = ( { __typename: 'EmailInteraction' } & Pick ); type MessageEnvelopeData_CustomChannelInteraction_Fragment = { __typename: 'CustomChannelInteraction' }; type MessageEnvelopeData_TalkInteraction_Fragment = { __typename: 'TalkInteraction' }; type MessageEnvelopeData_NativeMessagingInteraction_Fragment = { __typename: 'NativeMessagingInteraction' }; type MessageEnvelopeData_WhatsAppInteraction_Fragment = { __typename: 'WhatsAppInteraction' }; type MessageEnvelopeData_WeChatInteraction_Fragment = { __typename: 'WeChatInteraction' }; type MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment = { __typename: 'NotImplementedOriginatedFrom' }; export type MessageEnvelopeDataFragment = | MessageEnvelopeData_EmailInteraction_Fragment | MessageEnvelopeData_CustomChannelInteraction_Fragment | MessageEnvelopeData_TalkInteraction_Fragment | MessageEnvelopeData_NativeMessagingInteraction_Fragment | MessageEnvelopeData_WhatsAppInteraction_Fragment | MessageEnvelopeData_WeChatInteraction_Fragment | MessageEnvelopeData_NotImplementedOriginatedFrom_Fragment ; export type AnyChannelOriginatedFromFragment = ( { __typename: 'CustomChannelInteraction' } & Pick ); type ConversationOriginatedFrom_EmailInteraction_Fragment = ( { __typename: 'EmailInteraction' } & Pick ); type ConversationOriginatedFrom_CustomChannelInteraction_Fragment = ( { __typename: 'CustomChannelInteraction' } & Pick ); type ConversationOriginatedFrom_TalkInteraction_Fragment = { __typename: 'TalkInteraction' }; type ConversationOriginatedFrom_NativeMessagingInteraction_Fragment = ( { __typename: 'NativeMessagingInteraction' } & Pick ); type ConversationOriginatedFrom_WhatsAppInteraction_Fragment = ( { __typename: 'WhatsAppInteraction' } & Pick ); type ConversationOriginatedFrom_WeChatInteraction_Fragment = ( { __typename: 'WeChatInteraction' } & Pick ); type ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationOriginatedFromFragment = | ConversationOriginatedFrom_EmailInteraction_Fragment | ConversationOriginatedFrom_CustomChannelInteraction_Fragment | ConversationOriginatedFrom_TalkInteraction_Fragment | ConversationOriginatedFrom_NativeMessagingInteraction_Fragment | ConversationOriginatedFrom_WhatsAppInteraction_Fragment | ConversationOriginatedFrom_WeChatInteraction_Fragment | ConversationOriginatedFrom_NotImplementedOriginatedFrom_Fragment ; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction = ( { __typename: 'EmailInteraction' } & Pick ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction = ( { __typename: 'CustomChannelInteraction' } & Pick ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction = ( { __typename: 'TalkInteraction' } & Pick ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction = ( { __typename: 'NativeMessagingInteraction' } & Pick ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WhatsAppInteraction = ( { __typename: 'WhatsAppInteraction' } & Pick ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WeChatInteraction = ( { __typename: 'WeChatInteraction' } & Pick ); export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom = { __typename: 'NotImplementedOriginatedFrom' }; export type ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom = | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_EmailInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_CustomChannelInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_TalkInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NativeMessagingInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WhatsAppInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_WeChatInteraction | ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom_NotImplementedOriginatedFrom ; export type ConversationTalkPublicCallSummaryFragment = ( { __typename: 'TalkPublicCallSummary' } & Pick & { originatedFrom: ConversationTalkPublicCallSummaryFragment_TalkPublicCallSummary_originatedFrom } ); " `); await validate(content, config, complexTestSchemaWithUnionsAndInterfaces); }); it('fields with shared types and no fragments should use the shared type interface name', async () => { const nestedInterfacesSchema = buildSchema(/* GraphQL */ ` type Query { animals: [Animal!] } interface Animal { name: String! owner: Person! } type Cat implements Animal { name: String! owner: Person! } type Dog implements Animal { name: String! owner: Person! } interface Person { name: String! } type Trainer implements Person { name: String! } type Veterinarian implements Person { name: String! } `); const nestedInterfacesQuery = parse(/* GraphQL */ ` query GetAnimals { animals { name owner { name } } } `); const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: true, extractAllFieldsToTypes: true, nonOptionalTypename: true, dedupeOperationSuffix: true, }; const { content } = await plugin( nestedInterfacesSchema, [{ location: 'test-file.ts', document: nestedInterfacesQuery }], config, { outputFile: '' } ); // Issue #10502: When nested interfaces have the same fields, extractAllFieldsToTypes // We need to use the interface name for the nested type name. expect(content).toMatchInlineSnapshot(` "export type GetAnimalsQuery_animals_Animal_owner_Trainer = { __typename: 'Trainer', name: string }; export type GetAnimalsQuery_animals_Animal_owner_Veterinarian = { __typename: 'Veterinarian', name: string }; export type GetAnimalsQuery_animals_Animal_owner = | GetAnimalsQuery_animals_Animal_owner_Trainer | GetAnimalsQuery_animals_Animal_owner_Veterinarian ; export type GetAnimalsQuery_animals_Cat = { __typename: 'Cat', name: string, owner: GetAnimalsQuery_animals_Animal_owner }; export type GetAnimalsQuery_animals_Dog = { __typename: 'Dog', name: string, owner: GetAnimalsQuery_animals_Animal_owner }; export type GetAnimalsQuery_animals = | GetAnimalsQuery_animals_Cat | GetAnimalsQuery_animals_Dog ; export type GetAnimalsQuery_Query = { __typename: 'Query', animals?: Array | null }; export type GetAnimalsQueryVariables = Exact<{ [key: string]: never; }>; export type GetAnimalsQuery = GetAnimalsQuery_Query; " `); await validate(content, config, nestedInterfacesSchema); }); it('fragment spreads on the same interface should not force concrete parent type names (regression #10502)', async () => { const interfaceFragmentSchema = buildSchema(/* GraphQL */ ` schema { query: Query } type Query { pet(petId: ID!): Pet } interface Pet { id: ID! home: Home } type Dog implements Pet { id: ID! home: Home } type Cat implements Pet { id: ID! home: Home } interface Home { id: ID! } type House implements Home { id: ID! } `); const interfaceFragmentDoc = parse(/* GraphQL */ ` fragment GetFragmentPet on Pet { id home { id } } query GetPetData($petId: ID!) { pet(petId: $petId) { id home { id } ...GetFragmentPet } } `); const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: true, extractAllFieldsToTypes: true, nonOptionalTypename: true, dedupeOperationSuffix: true, }; const { content } = await plugin( interfaceFragmentSchema, [{ location: 'test-file.ts', document: interfaceFragmentDoc }], config, { outputFile: '' } ); // Edge case: a fragment spread on the same interface should not cause extracted types // for interface fields to be rooted to the first concrete parent (e.g. Cat). expect(content).toMatchInlineSnapshot(` "export type GetFragmentPetFragment_Pet_home_House = { __typename: 'House', id: string }; type GetFragmentPet_Dog_Fragment = { __typename: 'Dog', id: string, home?: GetFragmentPetFragment_Pet_home_House | null }; type GetFragmentPet_Cat_Fragment = { __typename: 'Cat', id: string, home?: GetFragmentPetFragment_Pet_home_House | null }; export type GetFragmentPetFragment = | GetFragmentPet_Dog_Fragment | GetFragmentPet_Cat_Fragment ; export type GetPetDataQuery_pet_Pet_home_House = { __typename: 'House', id: string }; export type GetPetDataQuery_pet_Dog = { __typename: 'Dog', id: string, home?: GetPetDataQuery_pet_Pet_home_House | null }; export type GetPetDataQuery_pet_Cat = { __typename: 'Cat', id: string, home?: GetPetDataQuery_pet_Pet_home_House | null }; export type GetPetDataQuery_pet = | GetPetDataQuery_pet_Dog | GetPetDataQuery_pet_Cat ; export type GetPetDataQuery_Query = { __typename: 'Query', pet?: GetPetDataQuery_pet | null }; export type GetPetDataQueryVariables = Exact<{ petId: Scalars['ID']['input']; }>; export type GetPetDataQuery = GetPetDataQuery_Query; " `); await validate(content, config, interfaceFragmentSchema); }); // Exception case for Issue #10502 - shared schema for fragment tests const notificationSchema = buildSchema(/* GraphQL */ ` type Query { notifications: [Notification!]! } interface Notification { id: ID! content: Content title: String! } type AppNotification implements Notification { id: ID! content: Content title: String! } type SystemNotification implements Notification { id: ID! content: Content title: String! } interface Content { id: ID! } type TextContent implements Content { id: ID! } type ImageContent implements Content { id: ID! } `); it('inline fragments should use their own type name and not parent type name', async () => { const notificationDoc = parse(/* GraphQL */ ` query GetNotifications { notifications { id ... on AppNotification { content { id } } ... on SystemNotification { content { id } } } } `); const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: true, extractAllFieldsToTypes: true, nonOptionalTypename: true, dedupeOperationSuffix: true, }; const { content } = await plugin( notificationSchema, [{ location: 'test-file.ts', document: notificationDoc }], config, { outputFile: '' } ); expect(content).toMatchInlineSnapshot(` "export type GetNotificationsQuery_notifications_AppNotification_content_TextContent = { __typename: 'TextContent', id: string }; export type GetNotificationsQuery_notifications_AppNotification_content_ImageContent = { __typename: 'ImageContent', id: string }; export type GetNotificationsQuery_notifications_AppNotification_content = | GetNotificationsQuery_notifications_AppNotification_content_TextContent | GetNotificationsQuery_notifications_AppNotification_content_ImageContent ; export type GetNotificationsQuery_notifications_SystemNotification_content_TextContent = { __typename: 'TextContent', id: string }; export type GetNotificationsQuery_notifications_SystemNotification_content_ImageContent = { __typename: 'ImageContent', id: string }; export type GetNotificationsQuery_notifications_SystemNotification_content = | GetNotificationsQuery_notifications_SystemNotification_content_TextContent | GetNotificationsQuery_notifications_SystemNotification_content_ImageContent ; export type GetNotificationsQuery_notifications_AppNotification = { __typename: 'AppNotification', id: string, content?: GetNotificationsQuery_notifications_AppNotification_content | null }; export type GetNotificationsQuery_notifications_SystemNotification = { __typename: 'SystemNotification', id: string, content?: GetNotificationsQuery_notifications_SystemNotification_content | null }; export type GetNotificationsQuery_notifications = | GetNotificationsQuery_notifications_AppNotification | GetNotificationsQuery_notifications_SystemNotification ; export type GetNotificationsQuery_Query = { __typename: 'Query', notifications: Array }; export type GetNotificationsQueryVariables = Exact<{ [key: string]: never; }>; export type GetNotificationsQuery = GetNotificationsQuery_Query; " `); await validate(content, config, notificationSchema); }); it('named fragments should use their name and not parent type name', async () => { const notificationDoc = parse(/* GraphQL */ ` fragment AppNotificationFragment on AppNotification { content { id } } fragment SystemNotificationFragment on SystemNotification { content { id } } query GetNotifications { notifications { id title ...AppNotificationFragment ...SystemNotificationFragment } } `); const config: TypeScriptDocumentsPluginConfig = { preResolveTypes: true, extractAllFieldsToTypes: true, nonOptionalTypename: true, dedupeOperationSuffix: true, }; const { content } = await plugin( notificationSchema, [{ location: 'test-file.ts', document: notificationDoc }], config, { outputFile: '' } ); expect(content).toMatchInlineSnapshot(` "export type AppNotificationFragment_AppNotification_content_TextContent = { __typename: 'TextContent', id: string }; export type AppNotificationFragment_AppNotification_content_ImageContent = { __typename: 'ImageContent', id: string }; export type AppNotificationFragment_AppNotification_content = | AppNotificationFragment_AppNotification_content_TextContent | AppNotificationFragment_AppNotification_content_ImageContent ; export type AppNotificationFragment = { __typename: 'AppNotification', content?: AppNotificationFragment_AppNotification_content | null }; export type SystemNotificationFragment_SystemNotification_content_TextContent = { __typename: 'TextContent', id: string }; export type SystemNotificationFragment_SystemNotification_content_ImageContent = { __typename: 'ImageContent', id: string }; export type SystemNotificationFragment_SystemNotification_content = | SystemNotificationFragment_SystemNotification_content_TextContent | SystemNotificationFragment_SystemNotification_content_ImageContent ; export type SystemNotificationFragment = { __typename: 'SystemNotification', content?: SystemNotificationFragment_SystemNotification_content | null }; export type GetNotificationsQuery_notifications_AppNotification = { __typename: 'AppNotification', id: string, title: string, content?: AppNotificationFragment_AppNotification_content | null }; export type GetNotificationsQuery_notifications_SystemNotification = { __typename: 'SystemNotification', id: string, title: string, content?: SystemNotificationFragment_SystemNotification_content | null }; export type GetNotificationsQuery_notifications = | GetNotificationsQuery_notifications_AppNotification | GetNotificationsQuery_notifications_SystemNotification ; export type GetNotificationsQuery_Query = { __typename: 'Query', notifications: Array }; export type GetNotificationsQueryVariables = Exact<{ [key: string]: never; }>; export type GetNotificationsQuery = GetNotificationsQuery_Query; " `); await validate(content, config, notificationSchema); }); }); ================================================ FILE: packages/plugins/typescript/operations/tests/shared/schema.ts ================================================ import { buildSchema } from 'graphql'; export const schema = buildSchema(/* GraphQL */ ` scalar DateTime input InputType { t: String } type User { id: ID! username: String! email: String! profile: Profile role: Role } type Profile { age: Int firstName: String! } type Mutation { test: String login(username: String!, password: String!): User } type Subscription { userCreated: User } interface Notifiction { id: ID! createdAt: String! } type TextNotification implements Notifiction { id: ID! text: String! createdAt: String! } type ImageNotification implements Notifiction { id: ID! imageUrl: String! metadata: ImageMetadata! createdAt: String! } type ImageMetadata { createdBy: String! } enum Role { USER ADMIN } union MyUnion = User | Profile union AnyNotification = TextNotification | ImageNotification union SearchResult = TextNotification | ImageNotification | User type Query { me: User unionTest: MyUnion notifications: [Notifiction!]! mixedNotifications: [AnyNotification!]! search(term: String!): [SearchResult!]! dummy: String dummyNonNull: String! dummyArray: [String] dummyNonNullArray: [String]! dummyNonNullArrayWithValues: [String!]! dummyWithType: Profile } schema { query: Query mutation: Mutation subscription: Subscription } `); ================================================ FILE: packages/plugins/typescript/operations/tests/ts-documents.apolloUnmask.spec.ts ================================================ import { parse } from 'graphql'; import { schema } from './shared/schema.js'; import { plugin } from '../src/index.js'; describe('TypeScript Operations Plugin - apolloUnmask', () => { it("'mask' with @unmask configured with apolloUnmask yields correct types", async () => { const ast = parse(/* GraphQL */ ` query { me { ...UserFragment @unmask } } fragment UserFragment on User { id } `); const result = await plugin( schema, [{ location: 'test-file.ts', document: ast }], { inlineFragmentTypes: 'mask', customDirectives: { apolloUnmask: true } }, { outputFile: '' } ); expect(result.content).toMatchInlineSnapshot(` "export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = { __typename?: 'Query', me?: { __typename?: 'User', id: string } | null }; export type UserFragmentFragment = { __typename?: 'User', id: string } & { ' $fragmentName'?: 'UserFragmentFragment' }; " `); }); it("'mask' with @unmask without apolloUnmask yields correct types", async () => { const ast = parse(/* GraphQL */ ` query { me { ...UserFragment @unmask } } fragment UserFragment on User { id } `); const result = await plugin( schema, [{ location: 'test-file.ts', document: ast }], { inlineFragmentTypes: 'mask' }, { outputFile: '' } ); expect(result.content).toMatchInlineSnapshot(` "export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = { __typename?: 'Query', me?: ( { __typename?: 'User' } & { ' $fragmentRefs'?: { 'UserFragmentFragment': UserFragmentFragment } } ) | null }; export type UserFragmentFragment = { __typename?: 'User', id: string } & { ' $fragmentName'?: 'UserFragmentFragment' }; " `); }); it("'mask' with @unmask with apolloUnmask explicitly disabled yields correct types", async () => { const ast = parse(/* GraphQL */ ` query { me { ...UserFragment @unmask } } fragment UserFragment on User { id } `); const result = await plugin( schema, [{ location: 'test-file.ts', document: ast }], { inlineFragmentTypes: 'mask', customDirectives: { apolloUnmask: false } }, { outputFile: '' } ); expect(result.content).toMatchInlineSnapshot(` "export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = { __typename?: 'Query', me?: ( { __typename?: 'User' } & { ' $fragmentRefs'?: { 'UserFragmentFragment': UserFragmentFragment } } ) | null }; export type UserFragmentFragment = { __typename?: 'User', id: string } & { ' $fragmentName'?: 'UserFragmentFragment' }; " `); }); it("'mask' with @unmask and masked fragments yields correct types", async () => { const ast = parse(/* GraphQL */ ` query { me { ...UserFragment @unmask ...UserFragment2 } } fragment UserFragment on User { id } fragment UserFragment2 on User { email } `); const result = await plugin( schema, [{ location: 'test-file.ts', document: ast }], { inlineFragmentTypes: 'mask', customDirectives: { apolloUnmask: true } }, { outputFile: '' } ); expect(result.content).toMatchInlineSnapshot(` "export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = { __typename?: 'Query', me?: ( { __typename?: 'User', id: string } & { ' $fragmentRefs'?: { 'UserFragment2Fragment': UserFragment2Fragment } } ) | null }; export type UserFragmentFragment = { __typename?: 'User', id: string } & { ' $fragmentName'?: 'UserFragmentFragment' }; export type UserFragment2Fragment = { __typename?: 'User', email: string } & { ' $fragmentName'?: 'UserFragment2Fragment' }; " `); }); it("'mask' with @unmask and masked fragments on overlapping fields yields correct types", async () => { const ast = parse(/* GraphQL */ ` query { me { ...UserFragment @unmask ...UserFragment2 } } fragment UserFragment on User { id email } fragment UserFragment2 on User { email } `); const result = await plugin( schema, [{ location: 'test-file.ts', document: ast }], { inlineFragmentTypes: 'mask', customDirectives: { apolloUnmask: true } }, { outputFile: '' } ); expect(result.content).toMatchInlineSnapshot(` "export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = { __typename?: 'Query', me?: ( { __typename?: 'User', id: string, email: string } & { ' $fragmentRefs'?: { 'UserFragment2Fragment': UserFragment2Fragment } } ) | null }; export type UserFragmentFragment = { __typename?: 'User', id: string, email: string } & { ' $fragmentName'?: 'UserFragmentFragment' }; export type UserFragment2Fragment = { __typename?: 'User', email: string } & { ' $fragmentName'?: 'UserFragment2Fragment' }; " `); }); }); ================================================ FILE: packages/plugins/typescript/operations/tests/ts-documents.nullability.spec.ts ================================================ import { buildSchema, parse } from 'graphql'; import * as prettier from 'prettier'; import { plugin } from '../src/index.js'; const schema = buildSchema(/* GraphQL */ ` directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION type Query { me: User } type User { field: String @semanticNonNull fieldLevel0: String @semanticNonNull(levels: [0]) fieldLevel1: String @semanticNonNull(levels: [1]) fieldBothLevels: String @semanticNonNull(levels: [0, 1]) list: [String] @semanticNonNull listLevel0: [String] @semanticNonNull(levels: [0]) listLevel1: [String] @semanticNonNull(levels: [1]) listBothLevels: [String] @semanticNonNull(levels: [0, 1]) nonNullableList: [String]! @semanticNonNull nonNullableListLevel0: [String]! @semanticNonNull(levels: [0]) nonNullableListLevel1: [String]! @semanticNonNull(levels: [1]) nonNullableListBothLevels: [String]! @semanticNonNull(levels: [0, 1]) listWithNonNullableItem: [String!] @semanticNonNull listWithNonNullableItemLevel0: [String!] @semanticNonNull(levels: [0]) listWithNonNullableItemLevel1: [String!] @semanticNonNull(levels: [1]) listWithNonNullableItemBothLevels: [String!] @semanticNonNull(levels: [0, 1]) nonNullableListWithNonNullableItem: [String!]! @semanticNonNull nonNullableListWithNonNullableItemLevel0: [String!]! @semanticNonNull(levels: [0]) nonNullableListWithNonNullableItemLevel1: [String!]! @semanticNonNull(levels: [1]) nonNullableListWithNonNullableItemBothLevels: [String!]! @semanticNonNull(levels: [0, 1]) } `); const document = parse(/* GraphQL */ ` query { me { field fieldLevel0 fieldLevel1 fieldBothLevels list listLevel0 listLevel1 listBothLevels nonNullableList nonNullableListLevel0 nonNullableListLevel1 nonNullableListBothLevels listWithNonNullableItem listWithNonNullableItemLevel0 listWithNonNullableItemLevel1 listWithNonNullableItemBothLevels nonNullableListWithNonNullableItem nonNullableListWithNonNullableItemLevel0 nonNullableListWithNonNullableItemLevel1 nonNullableListWithNonNullableItemBothLevels } } `); describe('TypeScript Operations Plugin - nullability', () => { it('converts semanticNonNull to nonNull when nullability.errorHandlingClient=true', async () => { const result = await plugin(schema, [{ document }], { nullability: { errorHandlingClient: true, }, }); const formattedContent = prettier.format(result.content, { parser: 'typescript' }); expect(formattedContent).toMatchInlineSnapshot(` "export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never }>; export type Unnamed_1_Query = { __typename?: "Query"; me?: { __typename?: "User"; field: string; fieldLevel0: string; fieldLevel1?: string | null; fieldBothLevels: string; list: Array; listLevel0: Array; listLevel1?: Array | null; listBothLevels: Array; nonNullableList: Array; nonNullableListLevel0: Array; nonNullableListLevel1: Array; nonNullableListBothLevels: Array; listWithNonNullableItem: Array; listWithNonNullableItemLevel0: Array; listWithNonNullableItemLevel1?: Array | null; listWithNonNullableItemBothLevels: Array; nonNullableListWithNonNullableItem: Array; nonNullableListWithNonNullableItemLevel0: Array; nonNullableListWithNonNullableItemLevel1: Array; nonNullableListWithNonNullableItemBothLevels: Array; } | null; }; " `); }); it('does not convert nullability to nonNull when nullability.errorHandlingClient=false', async () => { const result = await plugin(schema, [{ document }], { nullability: { errorHandlingClient: false, }, }); const formattedContent = prettier.format(result.content, { parser: 'typescript' }); expect(formattedContent).toMatchInlineSnapshot(` "export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never }>; export type Unnamed_1_Query = { __typename?: "Query"; me?: { __typename?: "User"; field?: string | null; fieldLevel0?: string | null; fieldLevel1?: string | null; fieldBothLevels?: string | null; list?: Array | null; listLevel0?: Array | null; listLevel1?: Array | null; listBothLevels?: Array | null; nonNullableList: Array; nonNullableListLevel0: Array; nonNullableListLevel1: Array; nonNullableListBothLevels: Array; listWithNonNullableItem?: Array | null; listWithNonNullableItemLevel0?: Array | null; listWithNonNullableItemLevel1?: Array | null; listWithNonNullableItemBothLevels?: Array | null; nonNullableListWithNonNullableItem: Array; nonNullableListWithNonNullableItemLevel0: Array; nonNullableListWithNonNullableItemLevel1: Array; nonNullableListWithNonNullableItemBothLevels: Array; } | null; }; " `); }); }); ================================================ FILE: packages/plugins/typescript/operations/tests/ts-documents.spec.ts ================================================ import { mergeOutputs, Types } from '@graphql-codegen/plugin-helpers'; import { validateTs } from '@graphql-codegen/testing'; import { buildClientSchema, buildSchema, parse } from 'graphql'; import { plugin as tsPlugin } from '../../typescript/src/index.js'; import { plugin } from '../src/index.js'; import { schema } from './shared/schema.js'; describe('TypeScript Operations Plugin', () => { const gitHuntSchema = buildClientSchema(require('../../../../../dev-test/githunt/schema.json')); const validate = async ( content: Types.PluginOutput, config: any = {}, pluginSchema = schema, usage = '', suspenseErrors = [] ) => { const m = mergeOutputs([await tsPlugin(pluginSchema, [], config, { outputFile: '' }), content, usage]); validateTs(m, undefined, undefined, undefined, suspenseErrors); return m; }; describe('Config', () => { it('Should not generate "export" when noExport is set to true', async () => { const ast = parse(/* GraphQL */ ` query notifications { notifications { id ... on TextNotification { text } ... on ImageNotification { imageUrl metadata { created: createdBy } } } } `); const config = { noExport: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).not.toContain('export'); await validate(content, config); }); it('Should handle "namespacedImportName" and add it when specified', async () => { const ast = parse(/* GraphQL */ ` query notifications { notifications { id ... on TextNotification { text textAlias: text } ... on TextNotification { text } ... on ImageNotification { imageUrl metadata { created: createdBy } } } } `); const config = { preResolveTypes: false, namespacedImportName: 'Types' }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type NotificationsQuery = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick & { textAlias: Types.TextNotification['text'] } ) | ( { __typename?: 'ImageNotification' } & Pick & { metadata: ( { __typename?: 'ImageMetadata' } & { created: Types.ImageMetadata['createdBy'] } ) } )> } ); `); await validate(content, config, schema, '', [`Cannot find namespace 'Types'.`]); }); it('Can merge an inline fragment with a spread', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Comment { id: ID! title: String! } type TextComment implements Comment { id: ID! title: String! text: String! } type ImageComment implements Comment { id: ID! title: String! image: String! } type Post { id: ID! comments: [Comment!]! } `); const ast = parse(/* GraphQL */ ` fragment Post on Post { id comments { ... on TextComment { text } } } fragment PostPlus on Post { ...Post comments { id } } `); const { content } = await plugin( testSchema, [{ location: 'test-file.ts', document: ast }], {}, { outputFile: '', } ); expect(content).toBeSimilarStringTo(` export type PostFragment = { __typename?: 'Post', id: string, comments: Array<{ __typename?: 'TextComment', text: string } | { __typename?: 'ImageComment' }> }; export type PostPlusFragment = { __typename?: 'Post', id: string, comments: Array<{ __typename?: 'TextComment', text: string, id: string } | { __typename?: 'ImageComment', id: string }> }; `); }); it('Should handle "namespacedImportName" and "preResolveTypes" together', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { f: E user: User! } enum E { A B } scalar JSON type User { id: ID! f: E j: JSON } `); const ast = parse(/* GraphQL */ ` query test { f user { id f j } } `); const config = { namespacedImportName: 'Types', preResolveTypes: true }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo( `export type TestQuery = { __typename?: 'Query', f?: Types.E | null, user: { __typename?: 'User', id: string, f?: Types.E | null, j?: any | null } };` ); await validate(content, config, schema, '', [`Cannot find namespace 'Types'.`]); }); it('Should generate the correct output when using immutableTypes config', async () => { const ast = parse(/* GraphQL */ ` query notifications { notifications { id ... on TextNotification { text } ... on ImageNotification { imageUrl metadata { createdBy } } } } `); const config = { preResolveTypes: false, namingConvention: 'change-case-all#lowerCase', immutableTypes: true }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type notificationsquery = ( { readonly __typename?: 'Query' } & { readonly notifications: ReadonlyArray<( { readonly __typename?: 'TextNotification' } & Pick ) | ( { readonly __typename?: 'ImageNotification' } & Pick & { readonly metadata: ( { readonly __typename?: 'ImageMetadata' } & Pick ) } )> } ); `); await validate(content, config); }); it('should include fragment variable definitions when experimentalFragmentVariables is set', async () => { const ast = parse( /* GraphQL */ ` fragment TextNotificationFragment($skip: Boolean!) on TextNotification { text @skip(if: $skip) } `, // < v15 compatibility { experimentalFragmentVariables: true, allowLegacyFragmentVariables: true } as any ); const config = { experimentalFragmentVariables: true }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toMatchSnapshot(); }); it('should resolve optionals according to maybeValue', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User! } type User { name: String! age: Int address: String! nicknames: [String!] parents: [User!]! } `); const fragment = parse(/* GraphQL */ ` query user($showProperty: Boolean!) { user { name age address @include(if: $showProperty) nicknames @include(if: $showProperty) parents @include(if: $showProperty) } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: true, maybeValue: "T | 'specialType'", }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQuery = { __typename?: 'Query', user: { __typename?: 'User', name: string, age?: number | 'specialType', address?: string, nicknames?: Array | 'specialType', parents?: Array } }; `); }); it('should add undefined as possible value according to allowUndefinedQueryVariables', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User! } type User { name: String! age: Int address: String! nicknames: [String!] parents: [User!]! } `); const fragment = parse(/* GraphQL */ ` query user($showProperty: Boolean!) { user { name age address @include(if: $showProperty) nicknames @include(if: $showProperty) parents @include(if: $showProperty) } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: true, allowUndefinedQueryVariables: true, }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ showProperty: Scalars['Boolean']['input']; }> | undefined; `); }); }); describe('Scalars', () => { it('Should include scalars when doing pick', async () => { const testSchema = buildSchema(/* GraphQL */ ` scalar Date type Query { me: User } type User { id: ID! joinDate: Date! } `); const doc = parse(/* GraphQL */ ` query { me { id joinDate } } `); const config = { preResolveTypes: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: doc }], config, { outputFile: '', }); expect(content).toContain(`Pick`); await validate(content, config, testSchema); }); }); describe('Custom Operation Result Name Suffix', () => { it('Should generate custom operation result name', async () => { const ast = parse(/* GraphQL */ ` query notifications { notifications { id ... on TextNotification { text } ... on ImageNotification { imageUrl metadata { createdBy } } } } `); const config = { operationResultSuffix: 'Result', preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo( `export type NotificationsQueryVariables = Exact<{ [key: string]: never; }>;` ); expect(content).toBeSimilarStringTo(` export type NotificationsQueryResult = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick & { metadata: ( { __typename?: 'ImageMetadata' } & Pick ) } )> } ); `); await validate(content, config); }); }); describe('Naming Convention & Types Prefix', () => { it('Should allow custom naming and point to the correct type', async () => { const ast = parse(/* GraphQL */ ` query notifications { notifications { id ... on TextNotification { text } ... on ImageNotification { imageUrl metadata { createdBy } } } } `); const config = { preResolveTypes: false, namingConvention: 'change-case-all#lowerCase' }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type notificationsquery = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick & { metadata: ( { __typename?: 'ImageMetadata' } & Pick ) } )> } ); `); await validate(content, config); }); it('Should allow custom naming and point to the correct type - with custom prefix', async () => { const ast = parse(/* GraphQL */ ` query notifications { notifications { id ... on TextNotification { text } ... on ImageNotification { imageUrl metadata { createdBy } } } } `); const config = { preResolveTypes: false, typesPrefix: 'i', namingConvention: 'change-case-all#lowerCase' }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo( `export type inotificationsqueryvariables = Exact<{ [key: string]: never; }>;` ); expect(content).toBeSimilarStringTo(` export type inotificationsquery = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick & { metadata: ( { __typename?: 'ImageMetadata' } & Pick ) } )> } ); `); await validate(content, config); }); it('Test for dedupeOperationSuffix', async () => { const ast = parse(/* GraphQL */ ` query notificationsQuery { notifications { id } } fragment MyFragment on Query { notifications { id } } `); const ast2 = parse(/* GraphQL */ ` query notifications { notifications { id } } fragment My on Query { notifications { id } } `); const ast3 = parse(/* GraphQL */ ` query notificationsQuery { ...MyFragment } fragment MyFragment on Query { notifications { id } } `); expect( (await plugin(schema, [{ location: 'test-file.ts', document: ast }], {}, { outputFile: '' })).content ).toContain('export type NotificationsQueryQuery ='); expect( (await plugin(schema, [{ location: 'test-file.ts', document: ast }], {}, { outputFile: '' })).content ).toContain('export type MyFragmentFragment ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast }], { dedupeOperationSuffix: false }, { outputFile: '' } ) ).content ).toContain('export type NotificationsQueryQuery ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast }], { dedupeOperationSuffix: true }, { outputFile: '' } ) ).content ).toContain('export type NotificationsQuery ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast }], { dedupeOperationSuffix: true }, { outputFile: '' } ) ).content ).toContain('export type MyFragment ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast2 }], { dedupeOperationSuffix: true }, { outputFile: '' } ) ).content ).toContain('export type NotificationsQuery ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast2 }], { dedupeOperationSuffix: false }, { outputFile: '' } ) ).content ).toContain('export type NotificationsQuery ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast2 }], { dedupeOperationSuffix: false }, { outputFile: '' } ) ).content ).toContain('export type MyFragment ='); const withUsage = ( await plugin( schema, [{ location: 'test-file.ts', document: ast3 }], { dedupeOperationSuffix: true, preResolveTypes: false }, { outputFile: '' } ) ).content; expect(withUsage).toBeSimilarStringTo(` export type MyFragment = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick )> } ); `); expect(withUsage).toBeSimilarStringTo(` export type NotificationsQuery = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick )> } ); `); }); }); it('Test for omitOperationSuffix', async () => { const ast = parse(/* GraphQL */ ` query notificationsQuery { notifications { id } } fragment MyFragment on Query { notifications { id } } `); const ast2 = parse(/* GraphQL */ ` query notifications { notifications { id } } fragment My on Query { notifications { id } } `); const ast3 = parse(/* GraphQL */ ` query notifications { ...My } fragment My on Query { notifications { id } } `); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast }], { preResolveTypes: false }, { outputFile: '' } ) ).content ).toContain('export type NotificationsQueryQuery ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast }], { preResolveTypes: false }, { outputFile: '' } ) ).content ).toContain('export type MyFragmentFragment ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast }], { omitOperationSuffix: true, preResolveTypes: false }, { outputFile: '' } ) ).content ).toContain('export type NotificationsQuery ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast }], { omitOperationSuffix: true, preResolveTypes: false }, { outputFile: '' } ) ).content ).toContain('export type MyFragment ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast2 }], { omitOperationSuffix: true, preResolveTypes: false }, { outputFile: '' } ) ).content ).toContain('export type Notifications ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast2 }], { omitOperationSuffix: true, preResolveTypes: false }, { outputFile: '' } ) ).content ).toContain('export type My ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast2 }], { omitOperationSuffix: false, preResolveTypes: false }, { outputFile: '' } ) ).content ).toContain('export type NotificationsQuery ='); expect( ( await plugin( schema, [{ location: 'test-file.ts', document: ast2 }], { omitOperationSuffix: false, preResolveTypes: false }, { outputFile: '' } ) ).content ).toContain('export type MyFragment ='); const withUsage = ( await plugin( schema, [{ location: 'test-file.ts', document: ast3 }], { omitOperationSuffix: true, preResolveTypes: false }, { outputFile: '' } ) ).content; expect(withUsage).toBeSimilarStringTo(` export type My = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick )> } ); `); expect(withUsage).toBeSimilarStringTo(` export type Notifications = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick )> } ); `); }); describe('__typename', () => { it('Should ignore __typename for root types with skipTypeNameForRoot = true', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Test { foo: String } type Query { test: Test } `); const ast = parse(/* GraphQL */ ` query q1 { test { foo } } `); const config = { skipTypeNameForRoot: true, preResolveTypes: false, }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo( `export type Q1Query = { test?: Maybe<( { __typename?: 'Test' } & Pick )> };` ); await validate(content, config, testSchema); }); it('Should ignore __typename for root types with skipTypeNameForRoot = true, and with nonOptionalTypename = true', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Test { foo: String } type Query { test: Test } `); const ast = parse(/* GraphQL */ ` query q1 { test { foo } } `); const config = { nonOptionalTypename: true, skipTypeNameForRoot: true, preResolveTypes: false, }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo( `export type Q1Query = { test?: Maybe<( { __typename: 'Test' } & Pick )> };` ); await validate(content, config, testSchema); }); it('Should ignore skipTypeNameForRoot = true when __typename is specified manually', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Test { foo: String } type Query { test: Test } `); const ast = parse(/* GraphQL */ ` query q1 { __typename test { foo } } `); const config = { nonOptionalTypename: true, skipTypeNameForRoot: true, preResolveTypes: false, }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo( `export type Q1Query = ( { __typename: 'Query' } & { test?: Maybe<( { __typename: 'Test' } & Pick )> } );` ); await validate(content, config, testSchema); }); it('Should add __typename correctly with nonOptionalTypename=false,skipTypename=true,preResolveTypes=true and explicit field', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Search { search: [SearchResult!]! } type Movie { id: ID! title: String! } type Person { id: ID! name: String! } union SearchResult = Movie | Person type Query { search(term: String!): [SearchResult!]! } `); const ast = parse(/* GraphQL */ ` query q1 { search { ... on Movie { __typename id title } ... on Person { __typename id name } } } query q2 { search { __typename ... on Movie { id title } ... on Person { id name } } } `); const config = { nonOptionalTypename: false, skipTypename: true, }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toContain( `\ export type Q1Query = { search: Array< | { __typename: 'Movie', id: string, title: string } | { __typename: 'Person', id: string, name: string } > };` ); expect(content).toContain( `\ export type Q2Query = { search: Array< | { __typename: 'Movie', id: string, title: string } | { __typename: 'Person', id: string, name: string } > };` ); await validate(content, config, testSchema); }); it('Should skip __typename when skipTypename is set to true', async () => { const ast = parse(/* GraphQL */ ` query { dummy } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).not.toContain(`__typename`); await validate(content, config); }); it('Should add __typename when dealing with fragments', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Node { id: ID! } type A implements Node { id: ID! A: String } type B implements Node { id: ID! B: String } type Query { some: Node } `); const ast = parse(/* GraphQL */ ` fragment Node on Node { __typename id } query Test { some { ...Node } } `); const config = { preResolveTypes: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type TestQuery = ( { __typename?: 'Query' } & { some?: Maybe<( { __typename: 'A' } & Pick ) | ( { __typename: 'B' } & Pick )> } ); `); await validate(content, config, testSchema); }); it('Should add aliased __typename correctly', async () => { const ast = parse(/* GraphQL */ ` query { type: __typename dummy } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = ( { __typename?: 'Query' } & Pick & { type: 'Query' } ); `); await validate(content, config); }); it('Should add aliased __typename correctly with preResovleTypes', async () => { const ast = parse(/* GraphQL */ ` query { type: __typename dummy } `); const config = { preResolveTypes: true }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = { __typename?: 'Query', dummy?: string | null, type: 'Query' }; `); await validate(content, config); }); it('Should add __typename as non-optional when explicitly specified', async () => { const ast = parse(/* GraphQL */ ` query { __typename dummy } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = ( { __typename: 'Query' } & Pick ); `); await validate(content, config); }); it('Should add __typename as non-optional when forced', async () => { const ast = parse(/* GraphQL */ ` query { dummy } `); const config = { nonOptionalTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = ( { __typename: 'Query' } & Pick ); `); await validate(content, config); }); it('Should add __typename as optional when its not specified', async () => { const ast = parse(/* GraphQL */ ` query { dummy } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = ( { __typename?: 'Query' } & Pick ); `); await validate(content, config); }); it('Should add __typename as non-optional when its explictly specified, even if skipTypename is true', async () => { const ast = parse(/* GraphQL */ ` query { __typename dummy } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = ( { __typename: 'Query' } & Pick ); `); await validate(content, config); }); it('Should add __typename correctly when unions are in use', async () => { const ast = parse(/* GraphQL */ ` query unionTest { unionTest { ... on User { id } ... on Profile { age } } } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type UnionTestQuery = ( { __typename?: 'Query' } & { unionTest?: Maybe<( { __typename?: 'User' } & Pick ) | ( { __typename?: 'Profile' } & Pick )> } ); `); await validate(content, config); }); it('Should add __typename correctly when interfaces are in use', async () => { const ast = parse(/* GraphQL */ ` query notifications { notifications { id ... on TextNotification { text } ... on ImageNotification { imageUrl metadata { createdBy } } } } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type NotificationsQuery = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick & { metadata: ( { __typename?: 'ImageMetadata' } & Pick ) } )> } ); `); await validate(content, config); }); it('should mark __typename as non optional in case it is included in the selection set of an interface field', async () => { const ast = parse(/* GraphQL */ ` query notifications { notifications { __typename ... on TextNotification { text } ... on ImageNotification { imageUrl } } } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type NotificationsQuery = ( { __typename?: 'Query' } & { notifications: Array<( { __typename: 'TextNotification' } & Pick ) | ( { __typename: 'ImageNotification' } & Pick )> } ); `); await validate(content, config); }); it('should mark __typename as non optional in case it is included in the selection set of an union field', async () => { const ast = parse(/* GraphQL */ ` query unionTest { unionTest { __typename ... on Profile { firstName } ... on User { email } } } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` { __typename?: 'Query' } & { unionTest?: Maybe<( { __typename: 'User' } & Pick ) | ( { __typename: 'Profile' } & Pick )> } ); `); await validate(content, config); }); }); describe('Unnamed Documents', () => { it('Should handle unnamed documents correctly', async () => { const ast = parse(/* GraphQL */ ` query { dummy } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = Pick; `); expect(content).toBeSimilarStringTo(` export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; `); await validate(content, config); }); it('Should handle unnamed documents correctly with multiple documents', async () => { const ast = parse(/* GraphQL */ ` query { dummy } query { dummy } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = Pick; `); expect(content).toBeSimilarStringTo(` export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; `); expect(content).toBeSimilarStringTo(` export type Unnamed_2_Query = Pick; `); expect(content).toBeSimilarStringTo(` export type Unnamed_2_QueryVariables = Exact<{ [key: string]: never; }>; `); await validate(content, config); }); }); describe('Selection Set', () => { it('Should detect invalid types as parent and notify', async () => { const ast = parse(/* GraphQL */ ` mutation test { test } `); const config = { preResolveTypes: false }; try { await plugin( buildSchema(/* GraphQL */ ` type Query { foo: String } `), [{ location: 'test-file.ts', document: ast }], config, { outputFile: '' } ); expect(true).toBeFalsy(); } catch (e) { expect(e.message).toBe('Unable to find root schema type for operation type "mutation"!'); } }); it('Should have valid __typename usage and split types according to that (with usage)', async () => { const testSchema = buildSchema(/* GraphQL */ ` scalar IPV4 scalar IPV6 type IPV4Route { address: IPV4 gateway: IPV4 } type IPV6Route { address: IPV6 gateway: IPV6 } union RouteUnion = IPV4Route | IPV6Route type Query { routes: [RouteUnion!]! } `); const ast = parse(/* GraphQL */ ` fragment NetRoute on RouteUnion { __typename ... on IPV4Route { ipv4Address: address ipv4Gateway: gateway } ... on IPV6Route { ipv6Address: address ipv6Gateway: gateway } } query QQ { routes { ...NetRoute } } `); const config = { preResolveTypes: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); const usage = ` type Route = QqQuery['routes'][0]; function validateGateway(route: Route) { if (route.__typename === 'IPV4Route') { console.log(route.ipv4Gateway) } else { console.log(route.ipv6Gateway) } } `; await validate(content, config, testSchema, usage); expect(mergeOutputs([content])).toMatchSnapshot(); }); it('Should generate the correct __typename when using fragment over type', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { user: User } type User { id: ID! name: String } `); const ast = parse(/* GraphQL */ ` query userQuery { user { ... on User { id name } } } `); const config = { preResolveTypes: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); await validate(content, config, testSchema); expect(mergeOutputs([content])).toMatchSnapshot(); }); it('Should generate the correct __typename when using both inline fragment and spread over type', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { user: User } type User { id: ID! name: String } `); const ast = parse(/* GraphQL */ ` query userQuery { user { ... on User { ...user } } } fragment user on User { id name } `); const config = { preResolveTypes: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); await validate(content, config, testSchema); expect(mergeOutputs([content])).toMatchSnapshot(); }); it('Should generate the correct __typename when using fragment spread over type', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { user: User } type User { id: ID! name: String } `); const ast = parse(/* GraphQL */ ` query userQuery { user { ...user } } fragment user on User { id name } `); const config = { preResolveTypes: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); await validate(content, config, testSchema); expect(mergeOutputs([content])).toMatchSnapshot(); }); it('Should generate the correct __typename when using fragment spread over union', async () => { const testSchema = buildSchema(/* GraphQL */ ` type User { id: ID! } type Error { message: String! } union UserResult = User | Error type Query { user: UserResult! } `); const ast = parse(/* GraphQL */ ` fragment UserFragment on User { id } query aaa { user { ...UserFragment } } `); const config = { preResolveTypes: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); await validate( content, config, testSchema, `function test(q: AaaQuery) { console.log(q.user.__typename === 'User' ? q.user.id : null); console.log(q.user.__typename === 'Error' ? q.user.__typename : null); }` ); expect(mergeOutputs([content])).toMatchSnapshot(); }); it('Should have valid fragments intersection on different types (with usage) #2498', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface User { id: ID! } type Tom implements User { id: ID! foo: String! } type Jerry implements User { id: ID! bar: String! } type Query { user: User } `); const ast = parse(/* GraphQL */ ` fragment tom on Tom { id foo } fragment jerry on Jerry { id bar } fragment user on User { ...tom ...jerry } query userQuery { user { ...user } } `); const config = { preResolveTypes: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); await validate( content, config, testSchema, ` function test(a: UserFragment) { if (a.__typename === 'Tom') { console.log(a.foo); } else if (a.__typename === 'Jerry') { console.log(a.bar); } }` ); expect(mergeOutputs([content])).toMatchSnapshot(); }); it('Should have valid __typename usage and split types according to that (with usage)', async () => { const testSchema = buildSchema(/* GraphQL */ ` scalar IPV4 scalar IPV6 type IPV4Route { address: IPV4 gateway: IPV4 } type IPV6Route { address: IPV6 gateway: IPV6 } union RouteUnion = IPV4Route | IPV6Route type Query { routes: [RouteUnion!]! } `); const ast = parse(/* GraphQL */ ` fragment NetRoute on RouteUnion { __typename ... on IPV4Route { ipv4Address: address ipv4Gateway: gateway } ...test } fragment test on IPV6Route { ipv6Address: address ipv6Gateway: gateway } query QQ { routes { ...NetRoute } } `); const config = { preResolveTypes: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); const usage = ` type Route = QqQuery['routes'][0]; function validateGateway(route: Route) { if (route.__typename === 'IPV4Route') { console.log(route.ipv4Gateway) } else { console.log(route.ipv6Gateway) } } `; await validate(content, config, testSchema, usage); expect(mergeOutputs([content])).toMatchSnapshot(); }); it('Should support fragment spread correctly with simple type with no other fields', async () => { const ast = parse(/* GraphQL */ ` fragment UserFields on User { id username profile { age } role } query me { me { ...UserFields } } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type MeQuery = { me?: Maybe<( Pick & { profile?: Maybe> } )> }; `); await validate(content, config); }); it('Should support fragment spread correctly with simple type with other fields', async () => { const ast = parse(/* GraphQL */ ` fragment UserFields on User { id profile { age } } query me { me { ...UserFields username } } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type MeQuery = { me?: Maybe<( Pick & { profile?: Maybe> } )> }; `); await validate(content, config); }); it('Should support fragment spread correctly with multiple fragment spread', async () => { const ast = parse(/* GraphQL */ ` fragment UserFields on User { id } fragment UserProfile on User { profile { age } } query me { me { ...UserFields ...UserProfile username } } `); const config = { skipTypename: false, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type MeQuery = ( { __typename?: 'Query' } & { me?: Maybe<( { __typename?: 'User' } & Pick & { profile?: Maybe<( { __typename?: 'Profile' } & Pick )> } )> } ); `); expect(content).toBeSimilarStringTo(` export type UserProfileFragment = ( { __typename?: 'User' } & { profile?: Maybe<( { __typename?: 'Profile' } & Pick )> } ); `); expect(content).toBeSimilarStringTo(` export type UserFieldsFragment = ( { __typename?: 'User' } & Pick ); `); await validate(content, config); }); it('Should generate the correct intersection for fragments when using with interfaces with different type', async () => { const schema = buildSchema(/* GraphQL */ ` interface Base { id: ID! } type A implements Base { id: ID! x: Int! } type B implements Base { id: ID! y: Int! } type Query { b: Base } `); const ast = parse(/* GraphQL */ ` query { b { ...a ...b } } fragment a on A { id x } fragment b on B { id y } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = ( { __typename?: 'Query' } & { b?: Maybe<( { __typename?: 'A' } & Pick ) | ( { __typename?: 'B' } & Pick )> } ); export type AFragment = ( { __typename?: 'A' } & Pick ); export type BFragment = ( { __typename?: 'B' } & Pick ); `); await validate(content, config, schema); }); it('Should generate the correct intersection for fragments when type implements 2 interfaces', async () => { const schema = buildSchema(/* GraphQL */ ` interface Base1 { foo: String! } interface Base2 { bar: String! } type MyType implements Base1 & Base2 { foo: String! bar: String! test: String! } type Query { myType: MyType! } `); const ast = parse(/* GraphQL */ ` query { myType { ...a ...b ...c } } fragment c on MyType { test } fragment a on Base1 { foo } fragment b on Base2 { bar } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = ( { __typename?: 'Query' } & { myType: ( { __typename?: 'MyType' } & Pick ) } ); `); await validate(content, config, schema); }); it('Should generate the correct intersection for fragments when using with interfaces with same type', async () => { const schema = buildSchema(/* GraphQL */ ` interface Base { id: ID! } type A implements Base { id: ID! x: Int! } type B implements Base { id: ID! y: Int! } type Query { b: Base } `); const ast = parse(/* GraphQL */ ` query { b { ...a ...b } } fragment a on A { id } fragment b on A { x } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type Unnamed_1_Query = ( { __typename?: 'Query' } & { b?: Maybe<( { __typename?: 'A' } & Pick ) | { __typename?: 'B' }> } ); export type AFragment = ( { __typename?: 'A' } & Pick ); export type BFragment = ( { __typename?: 'A' } & Pick ); `); validateTs(mergeOutputs([content]), config); expect(mergeOutputs([content])).toMatchSnapshot(); }); it('Should support interfaces correctly when used with inline fragments', async () => { const ast = parse(/* GraphQL */ ` query notifications { notifications { id ... on TextNotification { text } ... on ImageNotification { imageUrl metadata { createdBy } } } } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type NotificationsQuery = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick & { metadata: ( { __typename?: 'ImageMetadata' } & Pick ) } )> } ); `); await validate(content, config); }); it('Should support union correctly when used with inline fragments', async () => { const ast = parse(/* GraphQL */ ` query unionTest { unionTest { ... on User { id } ... on Profile { age } } } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type UnionTestQuery = ( { __typename?: 'Query' } & { unionTest?: Maybe<( { __typename?: 'User' } & Pick ) | ( { __typename?: 'Profile' } & Pick )> } ); `); await validate(content, config); }); it('Should support union correctly when used with inline fragments on types implementing common interface', async () => { const ast = parse(/* GraphQL */ ` query unionTest { mixedNotifications { ... on Notifiction { id } ... on TextNotification { text } ... on ImageNotification { imageUrl } } } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type UnionTestQuery = ( { __typename?: 'Query' } & { mixedNotifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick )> } ); `); await validate(content, config); }); it('Should support union correctly when used with inline fragments on types implementing common interface and also other types', async () => { const ast = parse(/* GraphQL */ ` query unionTest { search(term: "a") { ... on User { id } ... on Notifiction { id } ... on TextNotification { text } ... on ImageNotification { imageUrl } } } `); const config = { preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type UnionTestQuery = ( { __typename?: 'Query' } & { search: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick ) | ( { __typename?: 'User' } & Pick )> } ); `); await validate(content, config); }); it('Should support merging identical fragment union types', async () => { const ast = parse(/* GraphQL */ ` query test { notifications { ...N } } fragment N on Notifiction { id } `); const config = { preResolveTypes: true, mergeFragmentTypes: true, namingConvention: 'keep' }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type testQueryVariables = Exact<{ [key: string]: never; }>; export type testQuery = ( { notifications: Array<( { id: string } & { __typename?: 'TextNotification' | 'ImageNotification' } )> } & { __typename?: 'Query' } ); export type NFragment = ( { id: string } & { __typename?: 'TextNotification' | 'ImageNotification' } ); `); await validate(content, config); }); it('Should support computing correct names for merged fragment union types', async () => { const ast = parse(/* GraphQL */ ` fragment N on Notifiction { id ... on TextNotification { text } } `); const config = { preResolveTypes: true, mergeFragmentTypes: true, namingConvention: 'keep' }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` type N_TextNotification_Fragment = ( { text: string, id: string } & { __typename?: 'TextNotification' } ); type N_ImageNotification_Fragment = ( { id: string } & { __typename?: 'ImageNotification' } ); export type NFragment = N_TextNotification_Fragment | N_ImageNotification_Fragment; `); await validate(content, config); }); it('Should support computing correct names for large merged fragment union types', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Node { id: ID! } type A implements Node { id: ID! text: String! } type B implements Node { id: ID! text: String! } type C implements Node { id: ID! text: String! } type D implements Node { id: ID! text: String! } type E implements Node { id: ID! text: String! } `); const ast = parse(/* GraphQL */ ` fragment N on Node { id ... on A { text } } `); const config = { preResolveTypes: true, mergeFragmentTypes: true, namingConvention: 'keep' }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` type N_A_Fragment = ( { text: string, id: string } & { __typename?: 'A' } ); type N_zhJJUzpMTyh98zugnx0IKwiLetPNjV8KybSlmpAEUU_Fragment = ( { id: string } & { __typename?: 'B' | 'C' | 'D' | 'E' } ); export type NFragment = N_A_Fragment | N_zhJJUzpMTyh98zugnx0IKwiLetPNjV8KybSlmpAEUU_Fragment; `); await validate(content, config); }); it('Should not create empty types when merging fragment union types', async () => { const ast = parse(/* GraphQL */ ` fragment N on Query { notifications { ... on TextNotification { text } } } `); const config = { preResolveTypes: true, mergeFragmentTypes: true, namingConvention: 'keep' }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type NFragment = ( { notifications: Array<( { text: string } & { __typename?: 'TextNotification' } ) | { __typename?: 'ImageNotification' }> } & { __typename?: 'Query' } ); `); await validate(content, config); }); it('Should support merging identical fragment union types with skipTypename', async () => { const ast = parse(/* GraphQL */ ` query test { notifications { ...N } } fragment N on Notifiction { id } `); const config = { preResolveTypes: true, skipTypename: true, mergeFragmentTypes: true, namingConvention: 'keep' }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type testQueryVariables = Exact<{ [key: string]: never; }>; export type testQuery = { notifications: Array<{ id: string }> }; `); await validate(content, config); }); it('Should support computing correct names for merged fragment union types with skipTypename', async () => { const ast = parse(/* GraphQL */ ` fragment N on Notifiction { id ... on TextNotification { text } } `); const config = { preResolveTypes: true, skipTypename: true, mergeFragmentTypes: true, namingConvention: 'keep' }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` type N_TextNotification_Fragment = { text: string, id: string }; type N_ImageNotification_Fragment = { id: string }; export type NFragment = N_TextNotification_Fragment | N_ImageNotification_Fragment; `); await validate(content, config); }); it('Ignores merging when enabled alongside inline fragment masking', async () => { const ast = parse(/* GraphQL */ ` query test { notifications { ...N } } fragment N on Notifiction { id } `); const config = { preResolveTypes: true, mergeFragmentTypes: true, inlineFragmentTypes: 'mask' } as const; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type TestQueryVariables = Exact<{ [key: string]: never; }>; export type TestQuery = { __typename?: 'Query', notifications: Array<( { __typename?: 'TextNotification' } & { ' $fragmentRefs'?: { 'N_TextNotification_Fragment': N_TextNotification_Fragment } } ) | ( { __typename?: 'ImageNotification' } & { ' $fragmentRefs'?: { 'N_ImageNotification_Fragment': N_ImageNotification_Fragment } } )> }; type N_TextNotification_Fragment = { __typename?: 'TextNotification', id: string } & { ' $fragmentName'?: 'N_TextNotification_Fragment' }; type N_ImageNotification_Fragment = { __typename?: 'ImageNotification', id: string } & { ' $fragmentName'?: 'N_ImageNotification_Fragment' }; export type NFragment = N_TextNotification_Fragment | N_ImageNotification_Fragment; `); await validate(content, config); }); it('Should support inline fragments', async () => { const ast = parse(/* GraphQL */ ` query currentUser { me { id ... on User { username profile { age } } } } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type CurrentUserQuery = { me?: Maybe<( Pick & { profile?: Maybe> } )> }; `); await validate(content, config); }); it('Should build a basic selection set based on basic query on GitHub schema', async () => { const ast = parse(/* GraphQL */ ` query me($repoFullName: String!) { currentUser { login html_url } entry(repoFullName: $repoFullName) { id postedBy { login html_url } createdAt } } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(gitHuntSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo( `export type MeQueryVariables = Exact<{ repoFullName: Scalars['String']['input']; }>;` ); expect(content).toBeSimilarStringTo(` export type MeQuery = { currentUser?: Maybe>, entry?: Maybe<( Pick & { postedBy: Pick } )> }; `); await validate(content, config, gitHuntSchema); }); it('Should build a basic selection set based on basic query on GitHub schema with preResolveTypes=true', async () => { const ast = parse(/* GraphQL */ ` query me($repoFullName: String!) { currentUser { login html_url } entry(repoFullName: $repoFullName) { id postedBy { login html_url } createdAt } } `); const config = { preResolveTypes: true }; const { content } = await plugin(gitHuntSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type MeQuery = { __typename?: 'Query', currentUser?: { __typename?: 'User', login: string, html_url: string } | null, entry?: { __typename?: 'Entry', id: number, createdAt: number, postedBy: { __typename?: 'User', login: string, html_url: string } } | null }; `); await validate(content, config, gitHuntSchema); }); it('Should produce valid output with preResolveTypes=true and enums', async () => { const ast = parse(/* GraphQL */ ` query test { info { ...information } } fragment information on Information { entries { id value } } `); const testSchema = buildSchema(/* GraphQL */ ` type Information { entries: [Information_Entry!]! } enum Information_EntryType { NAME ADDRESS } type Information_Entry { id: Information_EntryType! value: String } type Query { info: Information } `); const config = { preResolveTypes: true }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); const o = await validate(content, config, testSchema); expect(o).toContain(`export enum Information_EntryType {`); expect(o).toContain(`__typename?: 'Information_Entry', id: Information_EntryType,`); }); it('Should produce valid output with preResolveTypes=true and enums with prefixes set', async () => { const ast = parse(/* GraphQL */ ` query test($e: Information_EntryType!) { info { ...information } infoArgTest(e: $e) { ...information } } fragment information on Information { entries { id value } } `); const testSchema = buildSchema(/* GraphQL */ ` type Information { entries: [Information_Entry!]! } enum Information_EntryType { NAME ADDRESS } type Information_Entry { id: Information_EntryType! value: String } type Query { infoArgTest(e: Information_EntryType!): Information info: Information } `); const config = { preResolveTypes: true, typesPrefix: 'I', enumPrefix: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); const o = await validate(content, config, testSchema); expect(o).toBeSimilarStringTo(` export type ITestQueryVariables = Exact<{ e: Information_EntryType; }>;`); expect(o).toContain(`export type IQuery = {`); expect(o).toContain(`export enum Information_EntryType {`); expect(o).toContain(`__typename?: 'Information_Entry', id: Information_EntryType,`); }); it('Should produce valid output with preResolveTypes=true and enums with no suffixes', async () => { const ast = parse(/* GraphQL */ ` query test($e: Information_EntryType!) { info { ...information } infoArgTest(e: $e) { ...information } } fragment information on Information { entries { id value } } `); const testSchema = buildSchema(/* GraphQL */ ` type Information { entries: [Information_Entry!]! } enum Information_EntryType { NAME ADDRESS } type Information_Entry { id: Information_EntryType! value: String } type Query { infoArgTest(e: Information_EntryType!): Information info: Information } `); const config = { preResolveTypes: true, typesSuffix: 'I', enumSuffix: false }; const { content } = await plugin(testSchema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); const o = await validate(content, config, testSchema); expect(o).toBeSimilarStringTo(` export type TestQueryVariablesI = Exact<{ e: Information_EntryType; }>;`); expect(o).toContain(`export type QueryI = {`); expect(o).toContain(`export enum Information_EntryType {`); expect(o).toContain(`__typename?: 'Information_Entry', id: Information_EntryType,`); }); it('Should build a basic selection set based on basic query', async () => { const ast = parse(/* GraphQL */ ` query dummy { dummy } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type DummyQuery = Pick; `); await validate(content, config); }); it('Should build a basic selection set based on basic query with field aliasing for basic scalar', async () => { const ast = parse(/* GraphQL */ ` query dummy { customName: dummy customName2: dummyWithType { age } } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type DummyQuery = ( { customName: Query['dummy'] } & { customName2?: Maybe> } ); `); await validate(content, config); }); it('Should build a basic selection set based on a query with inner fields', async () => { const ast = parse(/* GraphQL */ ` query currentUser { me { id username role profile { age } } } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type CurrentUserQuery = { me?: Maybe<( Pick & { profile?: Maybe> } )> }; `); await validate(content, config); }); }); describe('Fragment Definition', () => { it('Should build fragment definition correctly - with name and selection set', async () => { const ast = parse(/* GraphQL */ ` fragment UserFields on User { id username profile { age } } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type UserFieldsFragment = ( Pick & { profile?: Maybe> } ); `); await validate(content, config); }); }); describe('Operation Definition', () => { it('Should detect Mutation correctly', async () => { const ast = parse(/* GraphQL */ ` mutation login { login(username: "1", password: "2") { id username profile { age } } } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type LoginMutation = { login?: Maybe<( Pick & { profile?: Maybe> } )> }; `); await validate(content, config); }); it('Should detect Query correctly', async () => { const ast = parse(/* GraphQL */ ` query test { dummy } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type TestQuery = Pick; `); await validate(content, config); }); it('Should detect Subscription correctly', async () => { const ast = parse(/* GraphQL */ ` subscription test { userCreated { id } } `); const config = { skipTypename: true, preResolveTypes: false }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(` export type TestSubscription = { userCreated?: Maybe> }; `); await validate(content, config); }); it('Should handle operation variables correctly', async () => { const ast = parse(/* GraphQL */ ` query testQuery( $username: String $email: String $password: String! $input: InputType $mandatoryInput: InputType! $testArray: [String] $requireString: [String]! $innerRequired: [String!]! ) { dummy } `); const config = { skipTypename: true }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo( `export type TestQueryQueryVariables = Exact<{ username?: InputMaybe; email?: InputMaybe; password: Scalars['String']['input']; input?: InputMaybe; mandatoryInput: InputType; testArray?: InputMaybe> | InputMaybe>; requireString: Array> | InputMaybe; innerRequired: Array | Scalars['String']['input']; }>;` ); await validate(content, config, schema); }); it('Should handle operation variables correctly when they use custom scalars', async () => { const ast = parse(/* GraphQL */ ` query testQuery($test: DateTime) { dummy } `); const config = { skipTypename: true }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo( `export type TestQueryQueryVariables = Exact<{ test?: InputMaybe; }>;` ); await validate(content, config); }); it('Should create empty variables when there are no operation variables', async () => { const ast = parse(/* GraphQL */ ` query testQuery { dummy } `); const config = { skipTypename: true }; const { content } = await plugin(schema, [{ location: 'test-file.ts', document: ast }], config, { outputFile: '', }); expect(content).toBeSimilarStringTo(`export type TestQueryQueryVariables = Exact<{ [key: string]: never; }>;`); await validate(content, config); }); it('avoid duplicates - each type name should be unique', async () => { const testSchema = buildSchema(/* GraphQL */ ` type DeleteMutation { deleted: Boolean! } type UpdateMutation { updated: Boolean! } union MessageMutationType = DeleteMutation | UpdateMutation type Query { dummy: String } type Mutation { mutation(message: String!, type: String!): MessageMutationType! } `); const query = parse(/* GraphQL */ ` mutation SubmitMessage($message: String!) { mutation(message: $message) { ... on DeleteMutation { deleted } ... on UpdateMutation { updated } } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type SubmitMessageMutation = ( { __typename?: 'Mutation' } & { mutation: ( { __typename?: 'DeleteMutation' } & Pick ) | ( { __typename?: 'UpdateMutation' } & Pick ) } ); `); }); it('should use __typename in fragments when requested', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Post { title: String } type Query { post: Post! } `); const query = parse(/* GraphQL */ ` query Post { post { ... on Post { __typename } } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type PostQuery = ( { __typename?: 'Query' } & { post: { __typename: 'Post' } } ); `); }); it('should handle introspection types (__schema)', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Post { title: String } type Query { post: Post! } `); const query = parse(/* GraphQL */ ` query Info { __schema { queryType { fields { name } } } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type InfoQuery = ( { __typename?: 'Query' } & { __schema: ( { __typename?: '__Schema' } & { queryType: ( { __typename?: '__Type' } & { fields?: Maybe )>> } ) } ) } );`); }); it('should handle introspection types (__type)', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Post { title: String } type Query { post: Post! } `); const query = parse(/* GraphQL */ ` query Info { __type(name: "Post") { name fields { name type { name kind } } } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type InfoQuery = ( { __typename?: 'Query' } & { __type?: Maybe<( { __typename?: '__Type' } & Pick<__Type, 'name'> & { fields?: Maybe & { type: ( { __typename?: '__Type' } & Pick<__Type, 'name' | 'kind'> ) } )>> } )> } ); `); }); it('should handle introspection types (like __TypeKind)', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Post { title: String } type Query { post: Post! } `); const query = parse(/* GraphQL */ ` query Info { __type(name: "Post") { name fields { name type { name kind } } } } `); const coreContent = await tsPlugin( testSchema, [{ location: '', document: query }], {}, { outputFile: 'graphql.ts', } ); const pluginContent = await plugin( testSchema, [{ location: '', document: query }], {}, { outputFile: 'graphql.ts', } ); const content = mergeOutputs([coreContent, pluginContent]); expect(content).toBeSimilarStringTo(` /** An enum describing what kind of type a given \`__Type\` is. */ export enum __TypeKind { /** Indicates this type is a scalar. */ Scalar = 'SCALAR', /** Indicates this type is an object. \`fields\` and \`interfaces\` are valid fields. */ Object = 'OBJECT', /** Indicates this type is an interface. \`fields\`, \`interfaces\`, and \`possibleTypes\` are valid fields. */ Interface = 'INTERFACE', /** Indicates this type is a union. \`possibleTypes\` is a valid field. */ Union = 'UNION', /** Indicates this type is an enum. \`enumValues\` is a valid field. */ Enum = 'ENUM', /** Indicates this type is an input object. \`inputFields\` is a valid field. */ InputObject = 'INPUT_OBJECT', /** Indicates this type is a list. \`ofType\` is a valid field. */ List = 'LIST', /** Indicates this type is a non-null. \`ofType\` is a valid field. */ NonNull = 'NON_NULL' } `); validateTs(content); }); it('Should generate correctly when using enums and typesPrefix', async () => { const testSchema = buildSchema(/* GraphQL */ ` enum Access { Read Write All } type User { access: Access } input Filter { match: String! } type Query { users(filter: Filter!): [User] } `); const query = parse(/* GraphQL */ ` query users($filter: Filter!) { users(filter: $filter) { access } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { typesPrefix: 'PREFIX_', preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type PREFIX_UsersQueryVariables = Exact<{ filter: PREFIX_Filter; }>; `); expect(content).toBeSimilarStringTo(` export type PREFIX_UsersQuery = ( { __typename?: 'Query' } & { users?: Maybe )>>> } ); `); }); it('Should make arguments optional when there is a default value', async () => { const testSchema = buildSchema(/* GraphQL */ ` type User { name: String! } type Query { users(reverse: Boolean!): [User!]! } `); const query = parse(/* GraphQL */ ` query users($reverse: Boolean = true) { users(reverse: $reverse) { name } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], {}, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UsersQueryVariables = Exact<{ reverse?: InputMaybe; }>; `); }); }); describe('Union & Interfaces', () => { it('should generate correct types for union that returns interface types', async () => { const schema = buildSchema(/* GraphQL */ ` interface Error { message: String! } type Error1 implements Error { message: String! } type Error2 implements Error { message: String! } type Error3 implements Error { message: String! } type ComplexError implements Error { message: String! additionalInfo: String! } type FieldResultSuccess { someValue: Boolean! } union FieldResult = Error1 | Error2 | ComplexError | FieldResultSuccess type Query { field: FieldResult! } `); const query = parse(/* GraphQL */ ` query field { field { __typename ... on Error { message } ... on ComplexError { additionalInfo } ... on FieldResultSuccess { someValue } } } `); const { content } = await plugin( schema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type FieldQuery = ( { __typename?: 'Query' } & { field: ( { __typename: 'Error1' } & Pick ) | ( { __typename: 'Error2' } & Pick ) | ( { __typename: 'ComplexError' } & Pick ) | ( { __typename: 'FieldResultSuccess' } & Pick ) } ); `); }); it('should generate correct types for union that returns interface types (variant __typename in fragment)', async () => { const schema = buildSchema(/* GraphQL */ ` interface Error { message: String! } type Error1 implements Error { message: String! } type Error2 implements Error { message: String! } type Error3 implements Error { message: String! } type ComplexError implements Error { message: String! additionalInfo: String! } type FieldResultSuccess { someValue: Boolean! } union FieldResult = Error1 | Error2 | ComplexError | FieldResultSuccess type Query { field: FieldResult! } `); const query = parse(/* GraphQL */ ` query field { field { ... on Error { __typename message } ... on ComplexError { additionalInfo } ... on FieldResultSuccess { someValue } } } `); const { content } = await plugin( schema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type FieldQuery = ( { __typename?: 'Query' } & { field: ( { __typename: 'Error1' } & Pick ) | ( { __typename: 'Error2' } & Pick ) | ( { __typename: 'ComplexError' } & Pick ) | ( { __typename?: 'FieldResultSuccess' } & Pick ) } ); `); }); it('interface with same field names', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Node { id: ID! } type A implements Node { id: ID! a: String } type B implements Node { id: ID! a: Boolean } type Query { node: Node } `); const query = parse(/* GraphQL */ ` query something { node { ... on A { a } ... on B { a } } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type SomethingQuery = ( { __typename?: 'Query' } & { node?: Maybe<( { __typename?: 'A' } & Pick ) | ( { __typename?: 'B' } & Pick )> } ); `); }); it('union returning single interface types', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Error { message: String! } type Error1 implements Error { message: String! } type Error2 implements Error { message: String! } type Error3 implements Error { message: String! info: AdditionalInfo } type AdditionalInfo { message: String! } type User { id: ID! login: String! } union UserResult = User | Error2 | Error3 type Query { user: UserResult } `); const query = parse(/* GraphQL */ ` query user { user { ... on User { id login } ... on Error { message } ... on Error3 { info { message } } } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQuery = ( { __typename?: 'Query' } & { user?: Maybe<( { __typename?: 'User' } & Pick ) | ( { __typename?: 'Error2' } & Pick ) | ( { __typename?: 'Error3' } & Pick & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } )> } ); `); }); it('duplicated fragment on type includes combined types only once', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Error { message: String! } type Error1 implements Error { message: String! } type Error2 implements Error { message: String! } type Error3 implements Error { message: String! info: AdditionalInfo } type AdditionalInfo { message: String! message2: String! } type User { id: ID! login: String! } union UserResult = User | Error2 | Error3 type Query { user: UserResult } `); const query = parse(/* GraphQL */ ` query user { user { ... on User { id login } ... on Error { message ... on Error3 { info { message message2 } } } ... on Error { ... on Error3 { info { message message2 } } } ... on Error3 { info { message } } } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQuery = ( { __typename?: 'Query' } & { user?: Maybe<( { __typename?: 'User' } & Pick ) | ( { __typename?: 'Error2' } & Pick ) | ( { __typename?: 'Error3' } & Pick & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } )> } ); `); }); it('Should merge inline fragments fields correctly', async () => { const testSchema = buildSchema(/* GraphQL */ ` type User { id: ID! login: String! } type Query { user: User! } `); const query = parse(/* GraphQL */ ` query UserQuery { user { ... on User { id } ... on User { login } } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); const o = await validate(content, {}, testSchema); expect(o).toBeSimilarStringTo(` export type UserQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick ) } ); `); }); it('Should merge inline fragments fields correctly with fragment spread over the same type', async () => { const testSchema = buildSchema(/* GraphQL */ ` type User { id: ID! login: String! } type Query { user: User! } `); const query = parse(/* GraphQL */ ` query UserQuery { user { ... on User { id } ...test } } fragment test on User { login } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); const o = await validate(content, {}, testSchema); expect(o).toBeSimilarStringTo(` export type UserQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick ) } );`); expect(o).toBeSimilarStringTo(`export type TestFragment = ( { __typename?: 'User' } & Pick );`); }); it('Should handle union selection sets with both FragmentSpreads and InlineFragments', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Error { message: String! } type Error1 implements Error { message: String! } type Error2 implements Error { message: String! } type Error3 implements Error { message: String! info: AdditionalInfo } type AdditionalInfo { message: String! message2: String! } type User { id: ID! login: String! } union UserResult = User | Error2 | Error3 type Query { user: UserResult! } `); const query = parse(/* GraphQL */ ` query UserQuery { user { ...UserResult ...UserResult1 ... on User { login } ... on Error3 { message info { ...AdditionalInfo } } } } fragment AdditionalInfo on AdditionalInfo { message } fragment UserResult1 on UserResult { ... on User { id } ... on Error3 { info { message2 } } } fragment UserResult on UserResult { ... on User { id } ... on Error2 { message } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); const output = await validate( content, {}, testSchema, ` function t(q: UserQueryQuery) { if (q.user) { if (q.user.__typename === 'User') { if (q.user.id) { const u = q.user.login; } } if (q.user.__typename === 'Error2') { console.log(q.user.message); } if (q.user.__typename === 'Error3') { if (q.user.info) { console.log(q.user.info.__typename) } } } }` ); expect(mergeOutputs([content])).toMatchSnapshot(); expect(output).toBeSimilarStringTo(` export type UserQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick ) | ( { __typename?: 'Error2' } & Pick ) | ( { __typename?: 'Error3' } & Pick & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } ) } );`); expect(output).toBeSimilarStringTo(` export type AdditionalInfoFragment = ( { __typename?: 'AdditionalInfo' } & Pick ); type UserResult1_User_Fragment = ( { __typename?: 'User' } & Pick ); type UserResult1_Error2_Fragment = { __typename?: 'Error2' }; type UserResult1_Error3_Fragment = ( { __typename?: 'Error3' } & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } ); export type UserResult1Fragment = UserResult1_User_Fragment | UserResult1_Error2_Fragment | UserResult1_Error3_Fragment; type UserResult_User_Fragment = ( { __typename?: 'User' } & Pick ); type UserResult_Error2_Fragment = ( { __typename?: 'Error2' } & Pick ); type UserResult_Error3_Fragment = { __typename?: 'Error3' }; export type UserResultFragment = UserResult_User_Fragment | UserResult_Error2_Fragment | UserResult_Error3_Fragment;`); }); it('Should handle union selection sets with both FragmentSpreads and InlineFragments with flattenGeneratedTypes', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Error { message: String! } type Error1 implements Error { message: String! } type Error2 implements Error { message: String! } type Error3 implements Error { message: String! info: AdditionalInfo } type AdditionalInfo { message: String! message2: String! } type User { id: ID! login: String! } union UserResult = User | Error2 | Error3 type Query { user: UserResult! } `); const query = parse(/* GraphQL */ ` query UserQuery { user { ...UserResult ...UserResult1 ... on User { login } ... on Error3 { message info { ...AdditionalInfo } } } } fragment AdditionalInfo on AdditionalInfo { message } fragment UserResult1 on UserResult { ... on User { id } ... on Error3 { info { message2 } } } fragment UserResult on UserResult { ... on User { id } ... on Error2 { message } } `); const config = { flattenGeneratedTypes: true, preResolveTypes: false, }; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); const output = await validate( content, config, testSchema, ` function t(q: UserQueryQuery) { if (q.user) { if (q.user.__typename === 'User') { if (q.user.id) { const u = q.user.login; } } if (q.user.__typename === 'Error2') { console.log(q.user.message); } if (q.user.__typename === 'Error3') { if (q.user.info) { console.log(q.user.info.__typename) } } } }` ); expect(mergeOutputs([output])).toMatchSnapshot(); expect(output).toBeSimilarStringTo(` export type UserQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick ) | ( { __typename?: 'Error2' } & Pick ) | ( { __typename?: 'Error3' } & Pick & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } ) } ); `); }); it('#4216 - handle fragments against unions and interfaces with flattenGeneratedTypes', async () => { const testSchema = buildSchema(/* GraphQL */ ` schema { query: Query } type Query { search: [Searchable!] } interface Concept { id: String } type Dimension implements Concept { id: String } type DimValue { dimension: Dimension value: String! } union Searchable = Dimension | DimValue `); const query = parse(/* GraphQL */ ` query SearchPopular { search { ...SearchableFragment } } fragment SearchableFragment on Searchable { ...SearchConceptFragment ...SearchDimValueFragment } fragment SearchConceptFragment on Concept { id } fragment SearchDimValueFragment on DimValue { dimension { ...SearchConceptFragment } value } `); const config = { flattenGeneratedTypes: true, preResolveTypes: false, }; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); const output = await validate(content, config, testSchema); expect(mergeOutputs([output])).toMatchSnapshot(); expect(output).toBeSimilarStringTo(` export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; search?: Maybe>; }; export type Concept = { id?: Maybe; }; export type Dimension = Concept & { __typename?: 'Dimension'; id?: Maybe; }; export type DimValue = { __typename?: 'DimValue'; dimension?: Maybe; value: Scalars['String']['output']; }; export type Searchable = Dimension | DimValue; export type SearchPopularQueryVariables = Exact<{ [key: string]: never; }>; export type SearchPopularQuery = ( { __typename?: 'Query' } & { search?: Maybe ) | ( { __typename?: 'DimValue' } & Pick & { dimension?: Maybe<( { __typename?: 'Dimension' } & Pick )> } )>> } );`); }); it('Handles fragments across files with flattenGeneratedTypes', async () => { const testSchema = buildSchema(/* GraphQL */ ` schema { query: Query } type Query { search: [Dimension!] } type Dimension { id: String } `); const query = parse(/* GraphQL */ ` query SearchPopular { search { ...SearchableFragment } } # Unreferenced fragments are still dropped fragment ExtraFragment on Dimension { id } `); const fragment = parse(/* GraphQL */ ` fragment SearchableFragment on Dimension { id } `); const config = { flattenGeneratedTypes: true, flattenGeneratedTypesIncludeFragments: true, preResolveTypes: true, }; const { content } = await plugin( testSchema, [ { location: '', document: query }, { location: '', document: fragment }, ], config, { outputFile: 'graphql.ts', } ); const output = await validate(content, config, testSchema); expect(output).toBeSimilarStringTo(` export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; search?: Maybe>; }; export type Dimension = { __typename?: 'Dimension'; id?: Maybe; }; export type SearchableFragmentFragment = { __typename?: 'Dimension', id?: string | null }; export type SearchPopularQueryVariables = Exact<{ [key: string]: never; }>; export type SearchPopularQuery = { __typename?: 'Query', search?: Array<{ __typename?: 'Dimension', id?: string | null }> | null };`); }); it('Drops fragments with flattenGeneratedTypes', async () => { const testSchema = buildSchema(/* GraphQL */ ` schema { query: Query } type Query { search: [Dimension!] } type Dimension { id: String } `); const query = parse(/* GraphQL */ ` query SearchPopular { search { ...SearchableFragment } } # Unreferenced fragments should be dropped by flattenGeneratedTypes fragment ExtraFragment on Dimension { id } `); const fragment = parse(/* GraphQL */ ` # Referenced fragments should be dropped by flattenGeneratedTypes fragment SearchableFragment on Dimension { id } `); const config = { flattenGeneratedTypes: true, flattenGeneratedTypesIncludeFragments: false, preResolveTypes: true, }; const { content } = await plugin( testSchema, [ { location: '', document: query }, { location: '', document: fragment }, ], config, { outputFile: 'graphql.ts', } ); const output = await validate(content, config, testSchema); expect(output).toBeSimilarStringTo(` export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; search?: Maybe>; }; export type Dimension = { __typename?: 'Dimension'; id?: Maybe; }; export type SearchPopularQueryVariables = Exact<{ [key: string]: never; }>; export type SearchPopularQuery = { __typename?: 'Query', search?: Array<{ __typename?: 'Dimension', id?: string | null }> | null };`); }); it('Should add operation name when addOperationExport is true', async () => { const testSchema = buildSchema(/* GraphQL */ ` type User { id: ID! login: String! } type Query { user: User! } `); const query = parse(/* GraphQL */ ` query UserIdQuery { user { id } } query UserLoginQuery { user { login } } `); const config = { addOperationExport: true, preResolveTypes: false, }; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); expect(content).toBeSimilarStringTo(` export type UserIdQueryQueryVariables = Exact<{ [key: string]: never; }>; export type UserIdQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick ) } ); export type UserLoginQueryQueryVariables = Exact<{ [key: string]: never; }>; export type UserLoginQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick ) } ); export declare const UserIdQuery: import("graphql").DocumentNode; export declare const UserLoginQuery: import("graphql").DocumentNode; `); }); it('Should handle union selection sets with both FragmentSpreads and InlineFragments with flattenGeneratedTypes and directives', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Error { message: String! } type Error1 implements Error { message: String! } type Error2 implements Error { message: String! } type Error3 implements Error { message: String! info: AdditionalInfo } type AdditionalInfo { message: String! message2: String! } type User { id: ID! login: String! test: String test2: String } union UserResult = User | Error2 | Error3 type Query { user: UserResult! } directive @client on FIELD directive @connection on FIELD `); const query = parse(/* GraphQL */ ` query UserQuery { user { ...UserResult ...UserResult1 ... on User { login test @client } ... on Error3 { message info { ...AdditionalInfo } } } } fragment AdditionalInfo on AdditionalInfo { message } fragment UserResult1 on UserResult { ... on User { id test2 @connection } ... on Error3 { info { message2 } } } fragment UserResult on UserResult { ... on User { id } ... on Error2 { message } } `); const config = { flattenGeneratedTypes: true, preResolveTypes: false, }; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); const output = await validate( content, config, testSchema, ` function t(q: UserQueryQuery) { if (q.user) { if (q.user.__typename === 'User') { if (q.user.id) { const u = q.user.login; } } if (q.user.__typename === 'Error2') { console.log(q.user.message); } if (q.user.__typename === 'Error3') { if (q.user.info) { console.log(q.user.info.__typename) } } } }` ); expect(mergeOutputs([output])).toMatchSnapshot(); expect(output).toBeSimilarStringTo(` export type UserQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick ) | ( { __typename?: 'Error2' } & Pick ) | ( { __typename?: 'Error3' } & Pick & { info?: Maybe<( { __typename?: 'AdditionalInfo' } & Pick )> } ) } ); `); }); }); describe('Issues', () => { it('#4212 - Should merge TS arrays in a more elegant way', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Item { id: ID! name: String! } type Object { items: [Item!]! } type Query { obj: Object } `); const query = parse(/* GraphQL */ ` fragment Object1 on Object { items { id } } fragment Object2 on Object { items { name } } fragment CombinedObject on Object { ...Object1 ...Object2 } query test { obj { ...CombinedObject } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], {}, { outputFile: 'graphql.ts', } ); await validate( content, {}, testSchema, ` function test (t: TestQuery) { for (const item of t.obj!.items) { console.log(item.id, item.name, item.__typename); } } ` ); }); it('#5422 - Error when interface doesnt have implemeting types', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface A { a: String! } type Query { test: A } `); const query = parse(/* GraphQL */ ` query test { test { a } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).not.toContain(`Maybe<>`); expect(content).toContain(`Maybe`); }); it('#4389 - validate issues with interfaces', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface A { a: String! } interface B implements A { a: String! b: String } type C implements B { a: String! b: String c: String! } type Query { foo: C } `); const query = parse(/* GraphQL */ ` query { foo { ... on A { a } } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toContain(`{ foo?: Maybe<{ __typename?: 'C' }> }`); }); it('#5001 - incorrect output with typeSuffix', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { user(id: ID!): User! } type User { id: ID! username: String! email: String! } `); const query = parse(/* GraphQL */ ` query user { user(id: 1) { id username email } } `); const config = { typesSuffix: 'Type', }; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); expect(content).not.toContain('UserTypeQueryVariablesType'); expect(content).not.toContain('UserTypeQueryType'); expect(content).toContain('UserQueryVariablesType'); expect(content).toContain('UserQueryType'); }); it('#3064 - fragments over interfaces causes issues with fields', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Venue { id: String! name: String! } type GPSPosition { lat: Float! lng: Float! } interface VenueWithPosition { id: String! gpsPosition: GPSPosition! } type Hotel implements VenueWithPosition & Venue { id: String! gpsPosition: GPSPosition! name: String! } type Transport implements Venue { id: String! name: String! } type Query { hotel: Hotel! transport: Transport! } `); const query = parse(/* GraphQL */ ` fragment venue on Venue { id ... on VenueWithPosition { gpsPosition { lat lng } } } query q { hotel { ...venue } transport { ...venue } } `); const config = {}; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); expect(content).toMatchSnapshot(); const result = await validate( content, {}, testSchema, `function test(q: QQuery) { if (q.hotel) { const t1 = q.hotel.gpsPosition.lat } if (q.transport) { const t2 = q.transport.id; } }` ); expect(mergeOutputs([result])).toMatchSnapshot(); }); it('#2916 - Missing import prefix with preResolveTypes: true and near-operation-file preset', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { user(id: ID!): User! } enum Department { Direction Development } type User { id: ID! username: String! email: String! department: Department! } `); const query = parse(/* GraphQL */ ` query user { user(id: 1) { id username email dep: department } } `); const config = { skipTypename: true, preResolveTypes: true, namespacedImportName: 'Types', }; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); expect(content).toContain(`dep: Types.Department`); expect(content).toMatchSnapshot(); }); it('#2699 - Issues with multiple interfaces and unions', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Node { id: ID! } scalar DateTime interface Element { active: Boolean! createdAt: DateTime! createdBy: User updatedAt: DateTime! updatedBy: User } interface Entity { brandData(brand: ID!): EntityBrandData } type EntityBrandData { active: Boolean! browsable: Boolean! description: String! alternateTitle: String title: String! } type Query { node(id: ID!): Node! } type Company implements Element & Node & Entity { active: Boolean! createdAt: DateTime! createdBy: User updatedAt: DateTime! updatedBy: User id: ID! brandData(brand: ID!): EntityBrandData } type Theater implements Element & Node & Entity { active: Boolean! createdAt: DateTime! createdBy: User updatedAt: DateTime! updatedBy: User id: ID! brandData(brand: ID!): EntityBrandData } type Movie implements Element & Node & Entity { active: Boolean! createdAt: DateTime! createdBy: User updatedAt: DateTime! updatedBy: User id: ID! brandData(brand: ID!): EntityBrandData } type User implements Element & Node & Entity { active: Boolean! name: String! createdAt: DateTime! createdBy: User updatedAt: DateTime! updatedBy: User id: ID! brandData(brand: ID!): EntityBrandData } `); const query = parse(/* GraphQL */ ` query getEntityBrandData($gid: ID!, $brand: ID!) { node(gid: $gid) { __typename id ... on Entity { ...EntityBrandData } ... on Element { ...ElementMetadata } ... on Company { active } ... on Theater { active } } } fragment EntityBrandData on Entity { brandData(brand: $brand) { active browsable title alternateTitle description } } fragment ElementMetadata on Element { createdAt createdBy { id name } updatedAt updatedBy { id name } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], {}, { outputFile: 'graphql.ts', } ); expect(mergeOutputs([content])).toMatchSnapshot(); await validate( content, {}, testSchema, ` function test(q: GetEntityBrandDataQuery): void { const typeName: 'Company' | 'Theater' | 'User' | 'Movie' = q.node.__typename; // just to check that those are the types we want here const brandData = q.node.brandData; // this was missing in the original issue const createdAt = q.node.createdAt; // this was missing in the original issue if (q.node.__typename === 'Company') { console.log('Company:', q.node.active); } else if (q.node.__typename === 'Theater') { console.log('Theater:', q.node.active); } else if (q.node.__typename === 'User') { console.log('User:', q.node.id); } else if (q.node.__typename === 'Movie') { console.log('Movie:', q.node.id); } }` ); }); it('#1624 - Should work with fragment on union type', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { fooBar: [FooBar!]! } union FooBar = Foo | Bar type Foo { id: ID! } type Bar { id: ID! } `); const query = parse(/* GraphQL */ ` query TestQuery { fooBar { ...FooBarFragment } } fragment FooBarFragment on FooBar { ... on Foo { id } ... on Bar { id } } `); const { content } = await plugin( testSchema, [{ location: '', document: query }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type TestQueryQuery = ( { __typename?: 'Query' } & { fooBar: Array<( { __typename?: 'Foo' } & Pick ) | ( { __typename?: 'Bar' } & Pick )> } ); type FooBarFragment_Foo_Fragment = ( { __typename?: 'Foo' } & Pick ); type FooBarFragment_Bar_Fragment = ( { __typename?: 'Bar' } & Pick ); export type FooBarFragmentFragment = FooBarFragment_Foo_Fragment | FooBarFragment_Bar_Fragment; `); }); it('#2407 Fragment on Fragment Spread on Union type', async () => { const schema = buildSchema(/* GraphQL */ ` type Price { id: ID! item: [PriceItemUnion]! } type Product { id: ID! title: String! } union PriceItemUnion = Product type Query { price: Price! } `); const productFragmentDocument = parse(/* GraphQL */ ` fragment ProductFragment on Product { id title } `); const priceFragmentDocument = parse(/* GraphQL */ ` fragment PriceFragment on Price { id item { ... on Product { ...ProductFragment } } } `); const { content } = await plugin( schema, [ { location: '', document: productFragmentDocument }, { location: '', document: priceFragmentDocument }, ], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type ProductFragmentFragment = ( { __typename?: 'Product' } & Pick ); export type PriceFragmentFragment = ( { __typename?: 'Price' } & Pick & { item: Array )>> } ); `); }); it('#2506 - inline fragment without typeCondition specified', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User } type User { name: String } `); const fragment = parse(/* GraphQL */ ` query user($withUser: Boolean! = false) { ... @include(if: $withUser) { user { name } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQuery = ( { __typename?: 'Query' } & { user?: Maybe<( { __typename?: 'User' } & Pick )> } );`); }); it('#2436 - interface with field of same name but different type is correctly handled', async () => { const schema = buildSchema(/* GraphQL */ ` interface DashboardTile { tileId: ID! } type TileFilterMetadata { viz: String! columnInfo: String! } type DashboardTileFilterDetails implements DashboardTile { tileId: ID! md: TileFilterMetadata! } type TileParameterMetadata { viz: String! columnInfo: String! } type DashboardTileParameterDetails implements DashboardTile { tileId: ID! md: TileParameterMetadata! } type DashboardVersion { id: ID! tiles: DashboardTile! } `); const fragment = parse(/* GraphQL */ ` fragment DashboardVersionFragment on DashboardVersion { tiles { ... on DashboardTileFilterDetails { tileId md { viz columnInfo } } ... on DashboardTileParameterDetails { tileId md { viz columnInfo } } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type DashboardVersionFragmentFragment = ( { __typename?: 'DashboardVersion' } & { tiles: ( { __typename?: 'DashboardTileFilterDetails' } & Pick & { md: ( { __typename?: 'TileFilterMetadata' } & Pick ) } ) | ( { __typename?: 'DashboardTileParameterDetails' } & Pick & { md: ( { __typename?: 'TileParameterMetadata' } & Pick ) } ) } ); `); }); it('#2436 - union with field of same name but different type is correctly handled', async () => { const schema = buildSchema(/* GraphQL */ ` type TileFilterMetadata { viz: String! columnInfo: String! } type DashboardTileFilterDetails { tileId: ID! md: TileFilterMetadata! } type TileParameterMetadata { viz: String! columnInfo: String! } type DashboardTileParameterDetails { tileId: ID! md: TileParameterMetadata! } union DashboardTile = DashboardTileFilterDetails | DashboardTileParameterDetails type DashboardVersion { id: ID! tiles: DashboardTile! } `); const fragment = parse(/* GraphQL */ ` fragment DashboardVersionFragment on DashboardVersion { tiles { ... on DashboardTileFilterDetails { tileId md { viz columnInfo } } ... on DashboardTileParameterDetails { tileId md { viz columnInfo } } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type DashboardVersionFragmentFragment = ( { __typename?: 'DashboardVersion' } & { tiles: ( { __typename?: 'DashboardTileFilterDetails' } & Pick & { md: ( { __typename?: 'TileFilterMetadata' } & Pick ) } ) | ( { __typename?: 'DashboardTileParameterDetails' } & Pick & { md: ( { __typename?: 'TileParameterMetadata' } & Pick ) } ) } ); `); }); it('#3950 - Invalid output with fragments and skipTypename: true', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { animals: [Animal!]! } interface Animal { id: ID! } type Duck implements Animal { id: ID! } type Lion implements Animal { id: ID! } type Puma implements Animal { id: ID! } type Wolf implements Animal { id: ID! } `); const query = parse(/* GraphQL */ ` fragment CatFragment on Animal { ... on Lion { id } ... on Puma { id } } query kitty { animals { ...CatFragment } } `); const { content } = await plugin( schema, [{ location: '', document: query }], { skipTypename: true, }, { outputFile: 'graphql.ts', } ); expect(content).toMatchInlineSnapshot(` "type CatFragment_Duck_Fragment = Record; type CatFragment_Lion_Fragment = { id: string }; type CatFragment_Puma_Fragment = { id: string }; type CatFragment_Wolf_Fragment = Record; export type CatFragmentFragment = | CatFragment_Duck_Fragment | CatFragment_Lion_Fragment | CatFragment_Puma_Fragment | CatFragment_Wolf_Fragment ; export type KittyQueryVariables = Exact<{ [key: string]: never; }>; export type KittyQuery = { animals: Array< | { id: string } | { id: string } | Record > }; " `); }); it('#3950 - Invalid output with fragments and skipTypename: false', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { animals: [Animal!]! } interface Animal { id: ID! } type Duck implements Animal { id: ID! } type Lion implements Animal { id: ID! } type Puma implements Animal { id: ID! } type Wolf implements Animal { id: ID! } `); const query = parse(/* GraphQL */ ` fragment CatFragment on Animal { ... on Lion { id } ... on Puma { id } } query kitty { animals { ...CatFragment } } `); const { content } = await plugin( schema, [{ location: '', document: query }], { skipTypename: false, }, { outputFile: 'graphql.ts', } ); expect(content).toMatchInlineSnapshot(` "type CatFragment_Duck_Fragment = { __typename?: 'Duck' }; type CatFragment_Lion_Fragment = { __typename?: 'Lion', id: string }; type CatFragment_Puma_Fragment = { __typename?: 'Puma', id: string }; type CatFragment_Wolf_Fragment = { __typename?: 'Wolf' }; export type CatFragmentFragment = | CatFragment_Duck_Fragment | CatFragment_Lion_Fragment | CatFragment_Puma_Fragment | CatFragment_Wolf_Fragment ; export type KittyQueryVariables = Exact<{ [key: string]: never; }>; export type KittyQuery = { __typename?: 'Query', animals: Array< | { __typename?: 'Duck' } | { __typename?: 'Lion', id: string } | { __typename?: 'Puma', id: string } | { __typename?: 'Wolf' } > }; " `); }); it('#2489 - Union that only covers one possible type with selection set and no typename', async () => { const schema = buildSchema(/* GraphQL */ ` type NotFoundError { message: String! } type UserBannedError { message: String! } type User { id: ID! login: String } union UserResult = NotFoundError | UserBannedError | User type Query { user: UserResult! } `); const query = parse(/* GraphQL */ ` query user { user { ... on User { id login } } } `); const { content } = await plugin( schema, [{ location: '', document: query }], { skipTypename: true, preResolveTypes: false, }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQuery = { user: Pick | Record }; `); }); it('#4888 - Types for input Lists do not support coercion', async () => { const schema = buildSchema(/* GraphQL */ ` type User { id: ID! } type Query { search(testArray: [String], requireString: [String]!, innerRequired: [String!]!): [User!] } `); const ast = parse(/* GraphQL */ ` query user($testArray: [String], $requireString: [String]!, $innerRequired: [String!]!) { search(testArray: $testArray, requireString: $requireString, innerRequired: $innerRequired) { id } } `); const config = { preResolveTypes: true }; const { content } = await plugin(schema, [{ location: '', document: ast }], config, { outputFile: 'graphql.ts', }); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ testArray?: InputMaybe> | InputMaybe>; requireString: Array> | InputMaybe; innerRequired: Array | Scalars['String']['input']; }>;`); await validate(content, config); }); it('#5352 - Prevent array input coercion if arrayInputCoercion = false', async () => { const schema = buildSchema(/* GraphQL */ ` type User { id: ID! } type Query { search(testArray: [String], requireString: [String]!, innerRequired: [String!]!): [User!] } `); const ast = parse(/* GraphQL */ ` query user($testArray: [String], $requireString: [String]!, $innerRequired: [String!]!) { search(testArray: $testArray, requireString: $requireString, innerRequired: $innerRequired) { id } } `); const config = { preResolveTypes: true, arrayInputCoercion: false }; const { content } = await plugin(schema, [{ location: '', document: ast }], config, { outputFile: 'graphql.ts', }); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ testArray?: InputMaybe>>; requireString: Array>; innerRequired: Array; }>;`); await validate(content, config); }); it('#5263 - inline fragment spread on interface field results in incorrect types', async () => { const schema = buildSchema(/* GraphQL */ ` interface Entity { id: ID! } interface NamedEntity implements Entity { id: ID! name: String! } type Session implements Entity { id: ID! data: String! } type User implements NamedEntity & Entity { id: ID! name: String! } type Query { entity(id: ID!): Entity! } `); const document = parse(/* GraphQL */ ` query entity { entity(id: 1) { id ... on NamedEntity { name } } } `); const { content } = await plugin( schema, [{ location: '', document }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type EntityQuery = ( { __typename?: 'Query' } & { entity: ( { __typename?: 'Session' } & Pick ) | ( { __typename?: 'User' } & Pick ) } ); `); }); describe('#6149 - operation fragment merging behavior', () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User! } type User { id: ID! name: String! friends: [User!]! } `); it('InlineFragmentQuery', async () => { const document = parse(/* GraphQL */ ` query InlineFragmentQuery { user { ... on User { friends { id } } ... on User { friends { name } } } } `); const { content } = await plugin( schema, [{ location: '', document }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type InlineFragmentQueryQueryVariables = Exact<{ [key: string]: never; }>; export type InlineFragmentQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & { friends: Array<( { __typename?: 'User' } & Pick )> } ) } ); `); }); it('SpreadFragmentQuery', async () => { const document = parse(/* GraphQL */ ` fragment UserFriendsIdFragment on Query { user { friends { id } } } fragment UserFriendsNameFragment on Query { user { friends { name } } } query SpreadFragmentQuery { ...UserFriendsIdFragment ...UserFriendsNameFragment } `); const { content } = await plugin( schema, [{ location: '', document }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserFriendsIdFragmentFragment = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & { friends: Array<( { __typename?: 'User' } & Pick )> } ) } ); export type UserFriendsNameFragmentFragment = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & { friends: Array<( { __typename?: 'User' } & Pick )> } ) } ); export type SpreadFragmentQueryQueryVariables = Exact<{ [key: string]: never; }>; export type SpreadFragmentQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & { friends: Array<( { __typename?: 'User' } & Pick )> } ) } ); `); }); it('SpreadFragmentWithSelectionQuery', async () => { const document = parse(/* GraphQL */ ` fragment UserFriendsNameFragment on Query { user { friends { name } } } query SpreadFragmentWithSelectionQuery { user { id friends { id } } ...UserFriendsNameFragment } `); const { content } = await plugin( schema, [{ location: '', document }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserFriendsNameFragmentFragment = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & { friends: Array<( { __typename?: 'User' } & Pick )> } ) } ); export type SpreadFragmentWithSelectionQueryQueryVariables = Exact<{ [key: string]: never; }>; export type SpreadFragmentWithSelectionQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick & { friends: Array<( { __typename?: 'User' } & Pick )> } ) } ); `); }); it('SpreadFragmentWithSelectionQuery - flatten', async () => { const document = parse(/* GraphQL */ ` fragment UserFriendsNameFragment on Query { user { friends { name } } } query SpreadFragmentWithSelectionQuery { user { id friends { id } } ...UserFriendsNameFragment } `); const { content } = await plugin( schema, [{ location: '', document }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserFriendsNameFragmentFragment = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & { friends: Array<( { __typename?: 'User' } & Pick )> } ) } ); export type SpreadFragmentWithSelectionQueryQueryVariables = Exact<{ [key: string]: never; }>; export type SpreadFragmentWithSelectionQueryQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick & { friends: Array<( { __typename?: 'User' } & Pick )> } ) } ); `); }); }); it('#7811 - generates $fragmentName for fragment subtypes for fragment masking', async () => { const schema = buildSchema(/* GraphQL */ ` type Character { name: String } type Jedi { name: String side: String } type Droid { model: String } union People = Character | Jedi | Droid type Query { people: People! } `); const query = parse(/* GraphQL */ ` query GetPeople { people { ...PeopleInfo } } `); const fragment = parse(/* GraphQL */ ` fragment PeopleInfo on People { ... on Character { name } ... on Jedi { side } ... on Droid { model } } `); const { content } = await plugin( schema, [ { location: '', document: query }, { location: '', document: fragment }, ], { inlineFragmentTypes: 'mask' }, { outputFile: 'graphql.ts' } ); expect(content).toMatchInlineSnapshot(` "export type GetPeopleQueryVariables = Exact<{ [key: string]: never; }>; export type GetPeopleQuery = { __typename?: 'Query', people: | ( { __typename?: 'Character' } & { ' $fragmentRefs'?: { 'PeopleInfo_Character_Fragment': PeopleInfo_Character_Fragment } } ) | ( { __typename?: 'Jedi' } & { ' $fragmentRefs'?: { 'PeopleInfo_Jedi_Fragment': PeopleInfo_Jedi_Fragment } } ) | ( { __typename?: 'Droid' } & { ' $fragmentRefs'?: { 'PeopleInfo_Droid_Fragment': PeopleInfo_Droid_Fragment } } ) }; type PeopleInfo_Character_Fragment = { __typename?: 'Character', name?: string | null } & { ' $fragmentName'?: 'PeopleInfo_Character_Fragment' }; type PeopleInfo_Jedi_Fragment = { __typename?: 'Jedi', side?: string | null } & { ' $fragmentName'?: 'PeopleInfo_Jedi_Fragment' }; type PeopleInfo_Droid_Fragment = { __typename?: 'Droid', model?: string | null } & { ' $fragmentName'?: 'PeopleInfo_Droid_Fragment' }; export type PeopleInfoFragment = | PeopleInfo_Character_Fragment | PeopleInfo_Jedi_Fragment | PeopleInfo_Droid_Fragment ; " `); }); it('#6874 - generates types when parent type differs from spread fragment member types and preResolveTypes=true', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Animal { name: String! } type Bat implements Animal { name: String! features: BatFeatures! } type BatFeatures { color: String! wingspan: Int! } type Snake implements Animal { name: String! features: SnakeFeatures! } type SnakeFeatures { color: String! length: Int! } type Error { message: String! } union SnakeResult = Snake | Error type Query { snake: SnakeResult! } `); const query = parse(/* GraphQL */ ` query SnakeQuery { snake { ... on Snake { name ...AnimalFragment } } } fragment AnimalFragment on Animal { ... on Bat { features { color wingspan } } ... on Snake { features { color length } } } `); const config = { preResolveTypes: true }; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); expect(content).toMatchSnapshot(); }); it('#8793 selecting __typename should not be optional', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Animal { name: String! } type Bat implements Animal { name: String! features: BatFeatures! } type BatFeatures { color: String! wingspan: Int! } type Snake implements Animal { name: String! features: SnakeFeatures! } type SnakeFeatures { color: String! length: Int! } type Error { message: String! } union SnakeResult = Snake | Error type Query { snake: SnakeResult! } `); const query = parse(/* GraphQL */ ` query SnakeQuery { __typename snake { __typename } } `); const config = { preResolveTypes: true }; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); expect(content).toMatchSnapshot(); }); it('#8461 - conditional directives are ignored on fields with alias', async () => { const testSchema = buildSchema(/* GraphQL */ ` type User { firstName: String! lastName: Int! address: Address! } type Address { postalCode: String! } type Query { viewer: User! } `); const query = parse(/* GraphQL */ ` query UserQuery($skipFirstName: Boolean!, $skipAddress: Boolean!) { viewer { givenName: firstName @skip(if: $skipFirstName) lastName mailingAddress: address @skip(if: $skipAddress) { postalCode } } } `); const config = { preResolveTypes: true }; const { content } = await plugin(testSchema, [{ location: '', document: query }], config, { outputFile: 'graphql.ts', }); expect(content).toBeSimilarStringTo(` export type UserQueryQueryVariables = Exact<{ skipFirstName: Scalars['Boolean']['input']; skipAddress: Scalars['Boolean']['input']; }>; export type UserQueryQuery = { __typename?: 'Query', viewer: { __typename?: 'User', lastName: number, givenName?: string, mailingAddress?: { __typename?: 'Address', postalCode: string } } }; `); }); }); describe('conditional directives handling', () => { it('fields with @skip, @include should pre resolve into optional', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User! } type User { name: String! address: String! nicknames: [String!] parents: [User!]! } `); const fragment = parse(/* GraphQL */ ` query user($showAddress: Boolean!) { user { name address @include(if: $showAddress) nicknames @include(if: $showNicknames) parents @include(if: $showParents) } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: true, }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ showAddress: Scalars['Boolean']['input']; }>; export type UserQuery = { __typename?: 'Query', user: { __typename?: 'User', name: string, address?: string, nicknames?: Array | null, parents?: Array } };`); }); it('objects with @skip, @include should pre resolve into optional', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User! } type User { id: String! name: String! address: Address! friends: [User!]! moreFriends: [User!]! } type Address { city: String! } `); const fragment = parse(/* GraphQL */ ` query user($showAddress: Boolean!, $showName: Boolean!) { user { id name @include(if: $showName) address @include(if: $showAddress) { city } friends @include(if: $isFriendly) { id } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: true, }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ showAddress: Scalars['Boolean']['input']; showName: Scalars['Boolean']['input']; }>; export type UserQuery = { __typename?: 'Query', user: { __typename?: 'User', id: string, name?: string, address?: { __typename?: 'Address', city: string }, friends?: Array<{ __typename?: 'User', id: string }> } };`); }); it('fields with @skip, @include should make container resolve into MakeOptional type', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User! } type User { id: String! name: String! address: Address! friends: [User!]! } type Address { city: String! } `); const fragment = parse(/* GraphQL */ ` query user($showAddress: Boolean!, $showName: Boolean!) { user { id name @include(if: $showName) address @include(if: $showAddress) { city } friends @include(if: $isFriendly) { id } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: false }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ showAddress: Scalars['Boolean']['input']; showName: Scalars['Boolean']['input']; }>; export type UserQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & MakeOptional, 'name'> & { address?: ( { __typename?: 'Address' } & Pick ), friends?: Array<( { __typename?: 'User' } & Pick )> } ) } );`); }); it('On avoidOptionals:true, fields with @skip, @include should make container resolve into MakeMaybe type', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user(id: ID!): User! } type User { id: ID! username: String! email: String! } `); const fragment = parse(/* GraphQL */ ` query user { user(id: 1) { id username email @skip(if: true) } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { avoidOptionals: true, preResolveTypes: false, }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ [key: string]: never; }>; export type UserQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & MakeMaybe, 'email'> ) } ); `); }); it('Should handle "preResolveTypes" and "avoidOptionals" together', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user(id: ID!): User! } type User { id: ID! username: String! email: String } `); const operations = parse(/* GraphQL */ ` query user { user(id: 1) { id username email } } `); const config = { avoidOptionals: true, preResolveTypes: true }; const { content } = await plugin(schema, [{ location: '', document: operations }], config, { outputFile: 'graphql.ts', }); expect(content).toBeSimilarStringTo( `export type UserQuery = { __typename?: 'Query', user: { __typename?: 'User', id: string, username: string, email: string | null } }` ); }); it('On avoidOptionals:true, optionals (?) on types should be avoided', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { me: User! } type User { messages: [Message!]! } type Message { content: String! } `); const fragment = parse(/* GraphQL */ ` query MyQuery($include: Boolean!) { me { messages @include(if: $include) { content } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { avoidOptionals: true, nonOptionalTypename: true, preResolveTypes: false, }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type MyQueryQuery = ( { __typename: 'Query' } & { me: ( { __typename: 'User' } & { messages?: Array<( { __typename: 'Message' } & Pick )> } ) } ); `); }); it('inline fragment with conditional directives and avoidOptionals', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User group: Group! } type User { name: String } type Group { id: Int! } `); const fragment = parse(/* GraphQL */ ` query user($withUser: Boolean! = false) { ... @include(if: $withUser) { user { name } group { id } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: true, avoidOptionals: true }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQuery = { __typename?: 'Query', user?: { __typename?: 'User', name: string | null } | null, group?: { __typename?: 'Group', id: number } };`); }); it('resolve optionals according to maybeValue together with avoidOptionals and conditional directives', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User! } type User { name: String! age: Int address: String! nicknames: [String!] parents: [User!]! } `); const fragment = parse(/* GraphQL */ ` query user($showProperty: Boolean!) { user { name age address @include(if: $showProperty) nicknames @include(if: $showProperty) parents @include(if: $showProperty) } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: true, maybeValue: "T | 'specialType'", avoidOptionals: true, }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQuery = { __typename?: 'Query', user: { __typename?: 'User', name: string, age: number | 'specialType', address?: string, nicknames?: Array | 'specialType', parents?: Array } }; `); }); it('inline fragment with conditional directives and avoidOptionals, without preResolveTypes', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { user: User group: Group! } type User { name: String } type Group { id: Int! } `); const fragment = parse(/* GraphQL */ ` query user($withUser: Boolean! = false) { ... @include(if: $withUser) { user { name } group { id } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: false, avoidOptionals: true }, { outputFile: 'graphql.ts', } ); expect(content).toBeSimilarStringTo(` export type UserQuery = ( { __typename?: 'Query' } & { user?: Maybe<( { __typename?: 'User' } & Pick )>, group?: ( { __typename?: 'Group' } & Pick ) } );`); }); }); describe('incremental delivery directive handling', () => { it('should generate an union of initial and deferred fields for fragments (preResolveTypes: true)', async () => { const schema = buildSchema(` type Address { street1: String! } type Phone { home: String! } type Employment { title: String! } type User { name: String! email: String! address: Address! phone: Phone! employment: Employment! widgetCount: Int! widgetPreference: String! clearanceLevel: String! favoriteFood: String! leastFavoriteFood: String! } type Query { user: User! } `); const fragment = parse(` fragment WidgetFragment on User { widgetCount widgetPreference } fragment FoodFragment on User { favoriteFood leastFavoriteFood } fragment EmploymentFragment on User { employment { title } } query user { user { # Test inline fragment defer ... @defer { email } # Test inline fragment defer with nested selection set ... @defer { address { street1 } } # Test named fragment defer ...WidgetFragment @defer # Test a secondary named fragment defer ...FoodFragment @defer # Not deferred fields, fragments, selection sets, etc are left alone name phone { home } ...EmploymentFragment ... { clearanceLevel } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: true }, { outputFile: 'graphql.ts' } ); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ [key: string]: never; }>; export type UserQuery = { __typename?: 'Query', user: { __typename?: 'User', clearanceLevel: string, name: string, phone: { __typename?: 'Phone', home: string }, employment: { __typename?: 'Employment', title: string } } & ({ __typename?: 'User', email: string } | { __typename?: 'User', email?: never }) & ({ __typename?: 'User', address: { __typename?: 'Address', street1: string } } | { __typename?: 'User', address?: never }) & ({ __typename?: 'User', widgetCount: number, widgetPreference: string } | { __typename?: 'User', widgetCount?: never, widgetPreference?: never }) & ({ __typename?: 'User', favoriteFood: string, leastFavoriteFood: string } | { __typename?: 'User', favoriteFood?: never, leastFavoriteFood?: never }) }; `); }); it('should generate an union of initial and deferred fields for fragments using MakeEmpty (preResolveTypes: false)', async () => { const schema = buildSchema(` type Address { street1: String! } type Phone { home: String! } type Employment { title: String! } type User { name: String! email: String! address: Address! phone: Phone! employment: Employment! widgetCount: Int! clearanceLevel: String! } type Query { user: User! } `); const fragment = parse(` fragment WidgetFragment on User { widgetCount } fragment EmploymentFragment on User { employment { title } } query user { user { # Test inline fragment defer ... @defer { email } # Test inline fragment defer with nested selection set ... @defer { address { street1 } } # Test named fragment defer ...WidgetFragment @defer # Not deferred fields, fragments, selection sets, etc are left alone name phone { home } ...EmploymentFragment ... { clearanceLevel } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: false }, { outputFile: 'graphql.ts' } ); expect(content).toBeSimilarStringTo(` export type WidgetFragmentFragment = ( { __typename?: 'User' } & Pick ); export type EmploymentFragmentFragment = ( { __typename?: 'User' } & { employment: ( { __typename?: 'Employment' } & Pick ) } ); export type UserQueryVariables = Exact<{ [key: string]: never; }>; export type UserQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick & { phone: ( { __typename?: 'Phone' } & Pick ), employment: ( { __typename?: 'Employment' } & Pick ) } ) & (( { __typename?: 'User' } & Pick ) | ( { __typename?: 'User' } & MakeEmpty )) & (( { __typename?: 'User' } & { address: ( { __typename?: 'Address' } & Pick ) } ) | ( { __typename?: 'User' } & { address?: ( { __typename?: 'Address' } & Pick ) } )) & (( { __typename?: 'User' } & Pick ) | ( { __typename?: 'User' } & MakeEmpty )) } ); `); }); it('should generate an union of initial and deferred fields for fragments MakeEmpty (avoidOptionals: true)', async () => { const schema = buildSchema(` type Address { street1: String! } type Phone { home: String! } type Employment { title: String! } type User { name: String! email: String! address: Address! phone: Phone! employment: Employment! widgetName: String! widgetCount: Int! clearanceLevel: String! } type Query { user: User! } `); const fragment = parse(` fragment WidgetFragment on User { widgetName widgetCount } fragment EmploymentFragment on User { employment { title } } query user { user { # Test inline fragment defer ... @defer { email } # Test inline fragment defer with nested selection set ... @defer { address { street1 } } # Test named fragment defer ...WidgetFragment @defer # Not deferred fields, fragments, selection sets, etc are left alone name phone { home } ...EmploymentFragment ... { clearanceLevel } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { avoidOptionals: true, preResolveTypes: false, }, { outputFile: 'graphql.ts' } ); expect(content).toBeSimilarStringTo(` export type WidgetFragmentFragment = ( { __typename?: 'User' } & Pick ); export type EmploymentFragmentFragment = ( { __typename?: 'User' } & { employment: ( { __typename?: 'Employment' } & Pick ) } ); export type UserQueryVariables = Exact<{ [key: string]: never; }>; export type UserQuery = ( { __typename?: 'Query' } & { user: ( { __typename?: 'User' } & Pick & { phone: ( { __typename?: 'Phone' } & Pick ), employment: ( { __typename?: 'Employment' } & Pick ) } ) & (( { __typename?: 'User' } & Pick ) | ( { __typename?: 'User' } & MakeEmpty )) & (( { __typename?: 'User' } & { address: ( { __typename?: 'Address' } & Pick ) } ) | ( { __typename?: 'User' } & { address?: ( { __typename?: 'Address' } & Pick ) } )) & (( { __typename?: 'User' } & Pick ) | ( { __typename?: 'User' } & MakeEmpty )) } ); `); }); it('should support "preResolveTypes: true" and "avoidOptionals: true" together', async () => { const schema = buildSchema(` type Address { street1: String! } type Phone { home: String! } type Employment { title: String! } type User { name: String! email: String! address: Address! phone: Phone! employment: Employment! widgetCount: Int! clearanceLevel: String! } type Query { user: User! } `); const fragment = parse(` fragment WidgetFragment on User { widgetCount } fragment EmploymentFragment on User { employment { title } } query user { user { # Test inline fragment defer ... @defer { email } # Test inline fragment defer with nested selection set ... @defer { address { street1 } } # Test named fragment defer ...WidgetFragment @defer # Not deferred fields, fragments, selection sets, etc are left alone name phone { home } ...EmploymentFragment ... { clearanceLevel } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { avoidOptionals: true, preResolveTypes: true, }, { outputFile: 'graphql.ts' } ); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ [key: string]: never; }>; export type UserQuery = { __typename?: 'Query', user: { __typename?: 'User', clearanceLevel: string, name: string, phone: { __typename?: 'Phone', home: string }, employment: { __typename?: 'Employment', title: string } } & ({ __typename?: 'User', email: string } | { __typename?: 'User', email?: never }) & ({ __typename?: 'User', address: { __typename?: 'Address', street1: string } } | { __typename?: 'User', address?: never }) & ({ __typename?: 'User', widgetCount: number } | { __typename?: 'User', widgetCount?: never }) }; `); }); it('should resolve optionals according to maybeValue together with avoidOptionals and deferred fragments', async () => { const schema = buildSchema(` type Address { street1: String } type Phone { home: String! } type Employment { title: String! } type User { name: String! email: String! address: Address! phone: Phone! employment: Employment! widgetName: String! widgetCount: Int! clearanceLevel: String! } type Query { user: User! } `); const fragment = parse(` fragment WidgetFragment on User { widgetName widgetCount } fragment EmploymentFragment on User { employment { title } } query user { user { # Test inline fragment defer ... @defer { email } # Test inline fragment defer with nested selection set ... @defer { address { street1 } } # Test named fragment defer ...WidgetFragment @defer # Not deferred fields, fragments, selection sets, etc are left alone name phone { home } ...EmploymentFragment ... { clearanceLevel } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: true, maybeValue: "T | 'specialType'", avoidOptionals: true, }, { outputFile: 'graphql.ts' } ); expect(content).toBeSimilarStringTo(` export type UserQueryVariables = Exact<{ [key: string]: never; }>; export type UserQuery = { __typename?: 'Query', user: { __typename?: 'User', clearanceLevel: string, name: string, phone: { __typename?: 'Phone', home: string }, employment: { __typename?: 'Employment', title: string } } & ({ __typename?: 'User', email: string } | { __typename?: 'User', email?: never }) & ({ __typename?: 'User', address: { __typename?: 'Address', street1: string | 'specialType' } } | { __typename?: 'User', address?: never }) & ({ __typename?: 'User', widgetName: string, widgetCount: number } | { __typename?: 'User', widgetName?: never, widgetCount?: never }) }; `); }); it('should generate correct types with inlineFragmentTypes: "mask""', async () => { const schema = buildSchema(` type Address { street1: String! } type Phone { home: String! } type Employment { title: String! } type User { name: String! email: String! address: Address! phone: Phone! employment: Employment! widgetCount: Int! widgetPreference: String! clearanceLevel: String! favoriteFood: String! leastFavoriteFood: String! } type Query { user: User! } `); const fragment = parse(` fragment WidgetFragment on User { widgetCount widgetPreference } fragment FoodFragment on User { favoriteFood leastFavoriteFood } fragment EmploymentFragment on User { employment { title } } query user { user { # Test inline fragment defer ... @defer { email } # Test inline fragment defer with nested selection set ... @defer { address { street1 } } # Test named fragment defer ...WidgetFragment @defer # Test a secondary named fragment defer ...FoodFragment @defer # Not deferred fields, fragments, selection sets, etc are left alone name phone { home } ...EmploymentFragment ... { clearanceLevel } } } `); const { content } = await plugin( schema, [{ location: '', document: fragment }], { preResolveTypes: true, inlineFragmentTypes: 'mask' }, { outputFile: 'graphql.ts' } ); expect(content).toBeSimilarStringTo(` export type WidgetFragmentFragment = { __typename?: 'User', widgetCount: number, widgetPreference: string } & { ' $fragmentName'?: 'WidgetFragmentFragment' }; export type FoodFragmentFragment = { __typename?: 'User', favoriteFood: string, leastFavoriteFood: string } & { ' $fragmentName'?: 'FoodFragmentFragment' }; export type EmploymentFragmentFragment = { __typename?: 'User', employment: { __typename?: 'Employment', title: string } } & { ' $fragmentName'?: 'EmploymentFragmentFragment' }; export type UserQueryVariables = Exact<{ [key: string]: never; }>; export type UserQuery = { __typename?: 'Query', user: ( { __typename?: 'User', clearanceLevel: string, name: string, phone: { __typename?: 'Phone', home: string } } & { ' $fragmentRefs'?: { 'EmploymentFragmentFragment': EmploymentFragmentFragment } } ) & ({ __typename?: 'User', email: string } | { __typename?: 'User', email?: never }) & ({ __typename?: 'User', address: { __typename?: 'Address', street1: string } } | { __typename?: 'User', address?: never }) & ( { __typename?: 'User' } & { ' $fragmentRefs'?: { 'WidgetFragmentFragment': Incremental } } ) & ( { __typename?: 'User' } & { ' $fragmentRefs'?: { 'FoodFragmentFragment': Incremental } } ) }; `); }); }); it('handles unnamed queries', async () => { const ast = parse(/* GraphQL */ ` query { notifications { id } } `); const result = await plugin( schema, [{ location: 'test-file.ts', document: ast }], { preResolveTypes: false }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = ( { __typename?: 'Query' } & { notifications: Array<( { __typename?: 'TextNotification' } & Pick ) | ( { __typename?: 'ImageNotification' } & Pick )> } ); `); }); describe('inlineFragmentTypes option', () => { it("'combine' yields correct types", async () => { const ast = parse(/* GraphQL */ ` query { me { ...UserFragment } } fragment UserFragment on User { id } `); const result = await plugin( schema, [{ location: 'test-file.ts', document: ast }], { inlineFragmentTypes: 'combine' }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = { __typename?: 'Query', me?: ( { __typename?: 'User' } & UserFragmentFragment ) | null }; export type UserFragmentFragment = { __typename?: 'User', id: string }; `); }); it("'inline' yields correct types", async () => { const ast = parse(/* GraphQL */ ` query { me { ...UserFragment } } fragment UserFragment on User { id } `); const result = await plugin( schema, [{ location: 'test-file.ts', document: ast }], { inlineFragmentTypes: 'inline' }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = { __typename?: 'Query', me?: { __typename?: 'User', id: string } | null }; export type UserFragmentFragment = { __typename?: 'User', id: string }; `); }); it("'mask' yields correct types", async () => { const ast = parse(/* GraphQL */ ` query { me { ...UserFragment } } fragment UserFragment on User { id } `); const result = await plugin( schema, [{ location: 'test-file.ts', document: ast }], { inlineFragmentTypes: 'mask' }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; export type Unnamed_1_Query = { __typename?: 'Query', me?: ( { __typename?: 'User' } & { ' $fragmentRefs'?: { 'UserFragmentFragment': UserFragmentFragment } } ) | null }; export type UserFragmentFragment = { __typename?: 'User', id: string } & { ' $fragmentName'?: 'UserFragmentFragment' }; `); }); }); }); ================================================ FILE: packages/plugins/typescript/operations/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'typescript-operations', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/typescript/resolvers/CHANGELOG.md ================================================ # @graphql-codegen/typescript-resolvers ## 5.1.7 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-codegen/visitor-plugin-common@^6.2.3` ↗︎](https://www.npmjs.com/package/@graphql-codegen/visitor-plugin-common/v/6.2.3) (from `6.2.3`, in `dependencies`) - Updated dependency [`@graphql-tools/utils@^11.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/11.0.0) (from `^10.0.0`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 - @graphql-codegen/typescript@5.0.9 - @graphql-codegen/visitor-plugin-common@6.2.4 ## 5.1.6 ### Patch Changes - Updated dependencies [[`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf)]: - @graphql-codegen/visitor-plugin-common@6.2.3 - @graphql-codegen/typescript@5.0.8 ## 5.1.5 ### Patch Changes - Updated dependencies [[`f588d91`](https://github.com/dotansimha/graphql-code-generator/commit/f588d91ac43ea0aa5931915ce980d2e6876bb59c)]: - @graphql-codegen/visitor-plugin-common@6.2.2 - @graphql-codegen/typescript@5.0.7 ## 5.1.4 ### Patch Changes - Updated dependencies [[`b995ed1`](https://github.com/dotansimha/graphql-code-generator/commit/b995ed13a49379ea05e0e313fac68b557527523a)]: - @graphql-codegen/visitor-plugin-common@6.2.1 - @graphql-codegen/typescript@5.0.6 ## 5.1.3 ### Patch Changes - Updated dependencies [[`f821e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f821e8ab9351f23a9f7e5d5e6fc69c8e8868cad8), [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/visitor-plugin-common@6.2.0 - @graphql-codegen/plugin-helpers@6.1.0 - @graphql-codegen/typescript@5.0.5 ## 5.1.2 ### Patch Changes - Updated dependencies [[`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d)]: - @graphql-codegen/visitor-plugin-common@6.1.2 - @graphql-codegen/typescript@5.0.4 ## 5.1.1 ### Patch Changes - Updated dependencies [[`6715330`](https://github.com/dotansimha/graphql-code-generator/commit/67153304646694d75aee24afd70c3fce12e9f1f2)]: - @graphql-codegen/visitor-plugin-common@6.1.1 - @graphql-codegen/typescript@5.0.3 ## 5.1.0 ### Minor Changes - [#10449](https://github.com/dotansimha/graphql-code-generator/pull/10449) [`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26) Thanks [@eddeee888](https://github.com/eddeee888)! - Add `addInterfaceFieldResolverTypes` option to support custom Interface resolver inheritance behaviour (such as the one enabled by [makeExecutableSchema's inheritResolversFromInterfaces](https://the-guild.dev/graphql/tools/docs/generate-schema#makeexecutableschema)) ### Patch Changes - Updated dependencies [[`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26)]: - @graphql-codegen/visitor-plugin-common@6.1.0 - @graphql-codegen/typescript@5.0.2 ## 5.0.1 ### Patch Changes - Updated dependencies [[`accdab6`](https://github.com/dotansimha/graphql-code-generator/commit/accdab69106605241933e9d66d64dc7077656f30)]: - @graphql-codegen/visitor-plugin-common@6.0.1 - @graphql-codegen/typescript@5.0.1 ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGES: Do not generate \_\_isTypeOf for non-implementing types or non-union members - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGE: Use Record instead of {} for empty object type - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Ensure Federation Interfaces have `__resolveReference` if they are resolvable entities BREAKING CHANGES: Deprecate `onlyResolveTypeForInterfaces` because majority of use cases cannot implement resolvers in Interfaces. Interface normal resolvers are not generated by default. Use `addInterfaceFieldResolverTypes` option released in `@graphql-codegen/typescript-resolvers@5.1.0` to support custom Interface resolver inheritance behaviour (such as the one enabled by [makeExecutableSchema's inheritResolversFromInterfaces](https://the-guild.dev/graphql/tools/docs/generate-schema#makeexecutableschema)) BREAKING CHANGES: Deprecate `generateInternalResolversIfNeeded.__resolveReference` because types do not have `__resolveReference` if they are not Federation entities or are not resolvable. Users should not have to manually set this option. This option was put in to wait for this major version. - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGE: Improve Federation Entity's resolvers' parent param type: These types were using reference types inline. This makes it hard to handle mappers. The Parent type now all comes from ParentResolverTypes to make handling mappers and parent types simpler. - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix `mappers` usage with Federation `mappers` was previously used as `__resolveReference`'s first param (usually called "reference"). However, this is incorrect because `reference` interface comes directly from `@key` and `@requires` directives. This patch fixes the issue by creating a new `FederationTypes` type and use it as the base for federation entity types when being used to type entity references. BREAKING CHANGES: No longer generate `UnwrappedObject` utility type, as this was used to support the wrong previously generated type. - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Minor Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Report to meta user defined objects whether they have isTypeOf resolver ### Patch Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Update @requires type - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix fields or object types marked with @external being wrongly generated - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/visitor-plugin-common@6.0.0 - @graphql-codegen/plugin-helpers@6.0.0 - @graphql-codegen/typescript@5.0.0 ## 4.5.2 ### Patch Changes - [#10419](https://github.com/dotansimha/graphql-code-generator/pull/10419) [`2fc3869`](https://github.com/dotansimha/graphql-code-generator/commit/2fc3869de216554fa896359a082066eaa18e8634) Thanks [@chdanielmueller](https://github.com/chdanielmueller)! - Fix enum resolver for partially mapped enumValues ## 4.5.1 ### Patch Changes - [#10330](https://github.com/dotansimha/graphql-code-generator/pull/10330) [`c5efba3`](https://github.com/dotansimha/graphql-code-generator/commit/c5efba34a7b422720be9ce32937dd19fb0784bae) Thanks [@jnoordsij](https://github.com/jnoordsij)! - Make graphql-sock optional peerDep ## 4.5.0 ### Minor Changes - [#10315](https://github.com/dotansimha/graphql-code-generator/pull/10315) [`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc) Thanks [@eddeee888](https://github.com/eddeee888)! - Implement semanticNonNull custom directive ### Patch Changes - Updated dependencies [[`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc)]: - @graphql-codegen/visitor-plugin-common@5.8.0 - @graphql-codegen/typescript@4.1.6 ## 4.4.4 ### Patch Changes - Updated dependencies [[`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a)]: - @graphql-codegen/visitor-plugin-common@5.7.1 - @graphql-codegen/typescript@4.1.5 ## 4.4.3 ### Patch Changes - Updated dependencies [[`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c)]: - @graphql-codegen/visitor-plugin-common@5.7.0 - @graphql-codegen/typescript@4.1.4 ## 4.4.2 ### Patch Changes - [#10230](https://github.com/dotansimha/graphql-code-generator/pull/10230) [`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix generateInternalResolversIfNeeded.\_\_resolveReference making the resolver required `__resolveReference`'s default behaviour when not declared is to pass the ref to subsequent resolvers i.e. becoming the `parent`. So, it means we don't have to make this resolver required. This patch makes `__resolveReference` optional when `generateInternalResolversIfNeeded.__resolveReference` is set to true. - Updated dependencies [[`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517)]: - @graphql-codegen/visitor-plugin-common@5.6.1 - @graphql-codegen/typescript@4.1.3 ## 4.4.1 ### Patch Changes - [#10187](https://github.com/dotansimha/graphql-code-generator/pull/10187) [`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a) Thanks [@gilgardosh](https://github.com/gilgardosh)! - Fix: type naming for imported enums - Updated dependencies [[`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a), [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba)]: - @graphql-codegen/visitor-plugin-common@5.6.0 - @graphql-codegen/typescript@4.1.2 ## 4.4.0 ### Minor Changes - [#9989](https://github.com/dotansimha/graphql-code-generator/pull/9989) [`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc) Thanks [@eddeee888](https://github.com/eddeee888)! - Add `generateInternalResolversIfNeeded` option This option can be used to generate more correct types for internal resolvers. For example, only generate `__resolveReference` if the federation object has a resolvable `@key`. In the future, this option can be extended to support other internal resolvers e.g. `__isTypeOf` is only generated for implementing types and union members. - [#10141](https://github.com/dotansimha/graphql-code-generator/pull/10141) [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03) Thanks [@eddeee888](https://github.com/eddeee888)! - Add avoidCheckingAbstractTypesRecursively to avoid checking and generating abstract types recursively For users that already sets recursive default mappers e.g. `Partial<{T}>` or `DeepPartial<{T}>`, having both options on will cause a nested loop which eventually crashes Codegen. In such case, setting `avoidCheckingAbstractTypesRecursively: true` allows users to continue to use recursive default mappers as before. ### Patch Changes - Updated dependencies [[`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc), [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03)]: - @graphql-codegen/visitor-plugin-common@5.5.0 - @graphql-codegen/plugin-helpers@5.1.0 - @graphql-codegen/typescript@4.1.1 ## 4.3.0 ### Minor Changes - [#10077](https://github.com/dotansimha/graphql-code-generator/pull/10077) [`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4) Thanks [@eddeee888](https://github.com/eddeee888)! - Extend `config.avoidOptions` to support query, mutation and subscription Previously, `config.avoidOptions.resolvers` was being used to make query, mutation and subscription fields non-optional. Now, `config.avoidOptions.query`, `config.avoidOptions.mutation` and `config.avoidOptions.subscription` can be used to target the respective types. ### Patch Changes - Updated dependencies [[`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4)]: - @graphql-codegen/visitor-plugin-common@5.4.0 - @graphql-codegen/typescript@4.1.0 ## 4.2.1 ### Patch Changes - [#10014](https://github.com/dotansimha/graphql-code-generator/pull/10014) [`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix object types with fields being abstract types not pointing to resolver types correctly - Updated dependencies [[`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2)]: - @graphql-codegen/visitor-plugin-common@5.3.1 - @graphql-codegen/typescript@4.0.9 ## 4.2.0 ### Minor Changes - [#10007](https://github.com/dotansimha/graphql-code-generator/pull/10007) [`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3) Thanks [@eddeee888](https://github.com/eddeee888)! - Add generated resolvers map type name to typescript-resolvers plugin meta ### Patch Changes - Updated dependencies [[`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3), [`14ce39e`](https://github.com/dotansimha/graphql-code-generator/commit/14ce39e41dfee38c652be736664177fa2b1df421)]: - @graphql-codegen/visitor-plugin-common@5.3.0 - @graphql-codegen/typescript@4.0.8 ## 4.1.0 ### Minor Changes - [#9961](https://github.com/dotansimha/graphql-code-generator/pull/9961) [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e) Thanks [@eddeee888](https://github.com/eddeee888)! - Update typescript-resolvers to report generated resolver types in the run to meta field in the output ### Patch Changes - [#9944](https://github.com/dotansimha/graphql-code-generator/pull/9944) [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431) Thanks [@eddeee888](https://github.com/eddeee888)! - Add \_ prefix to generated `RefType` in `ResolversInterfaceTypes` and `ResolversUnionTypes` as it is sometimes unused - [#9962](https://github.com/dotansimha/graphql-code-generator/pull/9962) [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix interface mappers not working in nested/self-referencing scenarios - Updated dependencies [[`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431), [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e)]: - @graphql-codegen/plugin-helpers@5.0.4 - @graphql-codegen/visitor-plugin-common@5.2.0 - @graphql-codegen/typescript@4.0.7 ## 4.0.6 ### Patch Changes - Updated dependencies [[`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53), [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d)]: - @graphql-codegen/visitor-plugin-common@5.1.0 - @graphql-codegen/typescript@4.0.6 ## 4.0.5 ### Patch Changes - Updated dependencies [[`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5)]: - @graphql-codegen/visitor-plugin-common@5.0.0 - @graphql-codegen/typescript@4.0.5 ## 4.0.4 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/visitor-plugin-common@4.1.2 - @graphql-codegen/typescript@4.0.4 - @graphql-codegen/plugin-helpers@5.0.3 ## 4.0.3 ### Patch Changes - [#9673](https://github.com/dotansimha/graphql-code-generator/pull/9673) [`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f) Thanks [@maclockard](https://github.com/maclockard)! - Respect avoidOptionals when all arguments are optional - Updated dependencies [[`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f)]: - @graphql-codegen/visitor-plugin-common@4.1.1 - @graphql-codegen/typescript@4.0.3 ## 4.0.2 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 - @graphql-codegen/typescript@4.0.2 - @graphql-codegen/visitor-plugin-common@4.1.0 ## 4.0.1 ### Patch Changes - [#9497](https://github.com/dotansimha/graphql-code-generator/pull/9497) [`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a) Thanks [@eddeee888](https://github.com/eddeee888)! - Revert default ID scalar input type to string We changed the ID Scalar input type from `string` to `string | number` in the latest major version of `typescript` plugin. This causes issues for server plugins (e.g. typescript-resolvers) that depends on `typescript` plugin. This is because the scalar type needs to be manually inverted on setup which is confusing. - Updated dependencies [[`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a)]: - @graphql-codegen/visitor-plugin-common@4.0.1 - @graphql-codegen/typescript@4.0.1 ## 4.0.0 ### Major Changes - [#9375](https://github.com/dotansimha/graphql-code-generator/pull/9375) [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929) Thanks [@eddeee888](https://github.com/eddeee888)! - Implement Scalars with input/output types In GraphQL, Scalar types can be different for client and server. For example, given the native GraphQL ID: - A client may send `string` or `number` in the input - A client receives `string` in its selection set (i.e output) - A server receives `string` in the resolver (GraphQL parses `string` or `number` received from the client to `string`) - A server may return `string` or `number` (GraphQL serializes the value to `string` before sending it to the client ) Currently, we represent every Scalar with only one type. This is what codegen generates as base type: ```ts export type Scalars = { ID: string } ``` Then, this is used in both input and output type e.g. ```ts export type Book = { __typename?: 'Book' id: Scalars['ID'] // Output's ID can be `string` 👍 } export type QueryBookArgs = { id: Scalars['ID'] // Input's ID can be `string` or `number`. However, the type is only `string` here 👎 } ``` This PR extends each Scalar to have input and output: ```ts export type Scalars = { ID: { input: string | number output: string } } ``` Then, each input/output GraphQL type can correctly refer to the correct input/output scalar type: ```ts export type Book = { __typename?: 'Book' id: Scalars['ID']['output'] // Output's ID can be `string` 👍 } export type QueryBookArgs = { id: Scalars['ID']['input'] // Input's ID can be `string` or `number` 👍 } ``` Note that for `typescript-resolvers`, the type of ID needs to be inverted. However, the referenced types in GraphQL input/output types should still work correctly: ```ts export type Scalars = { ID: { input: string; output: string | number; } } export type Book = { __typename?: "Book"; id: Scalars["ID"]['output']; // Resolvers can return `string` or `number` in ID fields 👍 }; export type QueryBookArgs = { id: Scalars["ID"]['input']; // Resolvers receive `string` in ID fields 👍 }; export type ResolversTypes = { ID: ID: ResolverTypeWrapper; // Resolvers can return `string` or `number` in ID fields 👍 } export type ResolversParentTypes = { ID: Scalars['ID']['output']; // Resolvers receive `string` or `number` from parents 👍 }; ``` *** Config changes: 1. Scalars option can now take input/output types: ```ts config: { scalars: { ID: { input: 'string', output: 'string | number' } } } ``` 2. If a string is given (instead of an object with input/output fields), it will be used as both input and output types: ```ts config: { scalars: { ID: 'string' // This means `string` will be used for both ID's input and output types } } ``` 3. BREAKING CHANGE: External module Scalar types need to be an object with input/output fields ```ts config: { scalars: { ID: './path/to/scalar-module' } } ``` If correctly, wired up, the following will be generated: ```ts // Previously, imported `ID` type can be a primitive type, now it must be an object with input/output fields import { ID } from './path/to/scalar-module' export type Scalars = { ID: { input: ID['input']; output: ID['output'] } } ``` *** BREAKING CHANGE: This changes Scalar types which could be referenced in other plugins. If you are a plugin maintainer and reference Scalar, please update your plugin to use the correct input/output types. - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Minor Changes - [#9196](https://github.com/dotansimha/graphql-code-generator/pull/9196) [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96) Thanks [@beerose](https://github.com/beerose)! - Add `@defer` directive support When a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved. Once start using the `@defer` directive in your queries, the generated code will automatically include support for the directive. ```jsx // src/index.tsx import { graphql } from './gql' const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `) const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `) ``` The generated type for `GetUserQuery` will have information that the fragment is _incremental,_ meaning it may not be available right away. ```tsx // gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query' } & { ' $fragmentRefs'?: { OrdersFragment: Incremental } }) ``` Apart from generating code that includes support for the `@defer` directive, the Codegen also exports a utility function called `isFragmentReady`. You can use it to conditionally render components based on whether the data for a deferred fragment is available: ```jsx const OrdersList = (props: { data: FragmentType }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && } )} ); } export default App; ``` - [#9339](https://github.com/dotansimha/graphql-code-generator/pull/9339) [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c) Thanks [@AaronMoat](https://github.com/AaronMoat)! - Add excludeTypes config to resolversNonOptionalTypename This disables the adding of `__typename` in resolver types for any specified typename. This could be useful e.g. if you're wanting to enable this for all new types going forward but not do a big migration. Usage example: ```typescript const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: { unionMember: true, excludeTypes: ['MyType'] } } } } } ``` - [#9229](https://github.com/dotansimha/graphql-code-generator/pull/9229) [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c) Thanks [@eddeee888](https://github.com/eddeee888)! - Use generic to simplify ResolversUnionTypes This follows the `ResolversInterfaceTypes`'s approach where the `RefType` generic is used to refer back to `ResolversTypes` or `ResolversParentTypes` in cases of nested Union types - [#9304](https://github.com/dotansimha/graphql-code-generator/pull/9304) [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823) Thanks [@esfomeado](https://github.com/esfomeado)! - Added support for disabling suffixes on Enums. - [#9229](https://github.com/dotansimha/graphql-code-generator/pull/9229) [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c) Thanks [@eddeee888](https://github.com/eddeee888)! - Extract interfaces to ResolversInterfaceTypes and add to resolversNonOptionalTypename 1. `ResolversInterfaceTypes` is a new type that keeps track of a GraphQL interface and its implementing types. For example, consider this schema: ```graphql extend type Query { character(id: ID!): CharacterNode } interface CharacterNode { id: ID! } type Wizard implements CharacterNode { id: ID! screenName: String! spells: [String!]! } type Fighter implements CharacterNode { id: ID! screenName: String! powerLevel: Int! } ``` The generated types will look like this: ```ts export type ResolversInterfaceTypes> = { CharacterNode: Fighter | Wizard } export type ResolversTypes = { // other types... CharacterNode: ResolverTypeWrapper['CharacterNode']> Fighter: ResolverTypeWrapper Wizard: ResolverTypeWrapper // other types... } export type ResolversParentTypes = { // other types... CharacterNode: ResolversInterfaceTypes['CharacterNode'] Fighter: Fighter Wizard: Wizard // other types... } ``` The `RefType` generic is used to reference back to `ResolversTypes` and `ResolversParentTypes` in some cases such as field returning a Union. 2. `resolversNonOptionalTypename` also affects `ResolversInterfaceTypes` Using the schema above, if we use `resolversNonOptionalTypename` option: ```typescript const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: true // Or `resolversNonOptionalTypename: { interfaceImplementingType: true }` } } } } ``` Then, the generated type looks like this: ```ts export type ResolversInterfaceTypes> = { CharacterNode: (Fighter & { __typename: 'Fighter' }) | (Wizard & { __typename: 'Wizard' }) } export type ResolversTypes = { // other types... CharacterNode: ResolverTypeWrapper['CharacterNode']> Fighter: ResolverTypeWrapper Wizard: ResolverTypeWrapper // other types... } export type ResolversParentTypes = { // other types... CharacterNode: ResolversInterfaceTypes['CharacterNode'] Fighter: Fighter Wizard: Wizard // other types... } ``` ### Patch Changes - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/10.0.0) (from `^9.0.0`, in `dependencies`) - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96), [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c), [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d), [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0), [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c)]: - @graphql-codegen/plugin-helpers@5.0.0 - @graphql-codegen/visitor-plugin-common@4.0.0 - @graphql-codegen/typescript@4.0.0 ## 3.2.1 ### Patch Changes - [#9231](https://github.com/dotansimha/graphql-code-generator/pull/9231) [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00) Thanks [@eddeee888](https://github.com/eddeee888)! - Implement resolversNonOptionalTypename for mapper cases - Updated dependencies [[`386cf9044`](https://github.com/dotansimha/graphql-code-generator/commit/386cf9044a41d87ed45069b22d26b30f4b262a85), [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00)]: - @graphql-codegen/visitor-plugin-common@3.1.1 - @graphql-codegen/typescript@3.0.4 ## 3.2.0 ### Minor Changes - [#9146](https://github.com/dotansimha/graphql-code-generator/pull/9146) [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd) Thanks [@eddeee888](https://github.com/eddeee888)! - [typescript-resolvers] Add `resolversNonOptionalTypename` config option. This is extending on `ResolversUnionTypes` implemented in https://github.com/dotansimha/graphql-code-generator/pull/9069 `resolversNonOptionalTypename` adds non-optional `__typename` to union members of `ResolversUnionTypes`, without affecting the union members' base intefaces. A common use case for non-optional `__typename` of union members is using it as the common field to work out the final schema type. This makes implementing the union's `__resolveType` very simple as we can use `__typename` to decide which union member the resolved object is. Without this, we have to check the existence of field/s on the incoming object which could be verbose. For example, consider this schema: ```graphql type Query { book(id: ID!): BookPayload! } type Book { id: ID! isbn: String! } type BookResult { node: Book } type PayloadError { message: String! } union BookPayload = BookResult | PayloadError ``` _With optional `__typename`:_ We need to check existence of certain fields to resolve type in the union resolver: ```ts // Query/book.ts export const book = async () => { try { const book = await fetchBook() // 1. No `__typename` in resolver results... return { node: book } } catch (e) { return { message: 'Failed to fetch book' } } } // BookPayload.ts export const BookPayload = { __resolveType: parent => { // 2. ... means more checks in `__resolveType` if ('message' in parent) { return 'PayloadError' } return 'BookResult' } } ``` _With non-optional `__typename`:_ Resolvers declare the type. This which gives us better TypeScript support in resolvers and simplify `__resolveType` implementation: ```ts // Query/book.ts export const book = async () => { try { const book = await fetchBook() // 1. `__typename` is declared in resolver results... return { __typename: 'BookResult', // 1a. this also types `node` for us 🎉 node: book } } catch (e) { return { __typename: 'PayloadError', message: 'Failed to fetch book' } } } // BookPayload.ts export const BookPayload = { __resolveType: parent => parent.__typename // 2. ... means a very simple check in `__resolveType` } ``` _Using `resolversNonOptionalTypename`:_ add it into `typescript-resolvers` plugin config: ```ts // codegen.ts const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: true // Or `resolversNonOptionalTypename: { unionMember: true }` } } } } ``` ### Patch Changes - [#9206](https://github.com/dotansimha/graphql-code-generator/pull/9206) [`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix `ResolversUnionTypes` being used in `ResolversParentTypes` Previously, objects with mappable fields are converted to Omit format that references its own type group or `ResolversTypes` or `ResolversParentTypes` e.g. ```ts export type ResolversTypes = { Book: ResolverTypeWrapper BookPayload: ResolversTypes['BookResult'] | ResolversTypes['StandardError'] // Note: `result` on the next line references `ResolversTypes["Book"]` BookResult: ResolverTypeWrapper & { result?: Maybe }> StandardError: ResolverTypeWrapper } export type ResolversParentTypes = { Book: BookMapper BookPayload: ResolversParentTypes['BookResult'] | ResolversParentTypes['StandardError'] // Note: `result` on the next line references `ResolversParentTypes["Book"]` BookResult: Omit & { result?: Maybe } StandardError: StandardError } ``` In https://github.com/dotansimha/graphql-code-generator/pull/9069, we extracted resolver union types to its own group: ```ts export type ResolversUnionTypes = { // Note: `result` on the next line references `ResolversTypes["Book"]` which is only correct for the `ResolversTypes` case BookPayload: (Omit & { result?: Maybe }) | StandardError } export type ResolversTypes = { Book: ResolverTypeWrapper BookPayload: ResolverTypeWrapper BookResult: ResolverTypeWrapper & { result?: Maybe }> StandardError: ResolverTypeWrapper } export type ResolversParentTypes = { Book: BookMapper BookPayload: ResolversUnionTypes['BookPayload'] BookResult: Omit & { result?: Maybe } StandardError: StandardError } ``` This change creates an extra `ResolversUnionParentTypes` that is referenced by `ResolversParentTypes` to ensure backwards compatibility: ```ts export type ResolversUnionTypes = { BookPayload: (Omit & { result?: Maybe }) | StandardError } // ... and the reference is changed in ResolversParentTypes: export type ResolversParentTypes = { // ... other fields BookPayload: ResolversUnionParentTypes['BookPayload'] } ``` - [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087) Thanks [@saihaj](https://github.com/saihaj)! - Resolve issue with nesting fields in `@provides` directive being prevented - Updated dependencies [[`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835), [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087), [`92d86b009`](https://github.com/dotansimha/graphql-code-generator/commit/92d86b009579edf70f60b0b8e28658af93ff9fd1), [`acb647e4e`](https://github.com/dotansimha/graphql-code-generator/commit/acb647e4efbddecf732b6e55dc47ac40c9bdaf08), [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd)]: - @graphql-codegen/visitor-plugin-common@3.1.0 - @graphql-codegen/plugin-helpers@4.2.0 - @graphql-codegen/typescript@3.0.3 ## 3.1.1 ### Patch Changes - [#9110](https://github.com/dotansimha/graphql-code-generator/pull/9110) [`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a) Thanks [@gilgardosh](https://github.com/gilgardosh)! - Custom mappers with placeholder will apply omit - [#9069](https://github.com/dotansimha/graphql-code-generator/pull/9069) [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc) Thanks [@eddeee888](https://github.com/eddeee888)! - Extract union types to ResolversUnionTypes - Updated dependencies [[`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a), [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc), [`b343626c9`](https://github.com/dotansimha/graphql-code-generator/commit/b343626c978b9ee0f14e314cea6c01ae3dad057c)]: - @graphql-codegen/visitor-plugin-common@3.0.2 - @graphql-codegen/typescript@3.0.2 ## 3.1.0 ### Minor Changes - [#8853](https://github.com/dotansimha/graphql-code-generator/pull/8853) [`b13aa7449`](https://github.com/dotansimha/graphql-code-generator/commit/b13aa7449637eaf28976ea7e31730b0290609919) Thanks [@KGAdamCook](https://github.com/KGAdamCook)! - Updated customResolveInfo to use the correct importType for external imports ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 - @graphql-codegen/typescript@3.0.1 - @graphql-codegen/visitor-plugin-common@3.0.1 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - [#8871](https://github.com/dotansimha/graphql-code-generator/pull/8871) [`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5) Thanks [@B2o5T](https://github.com/B2o5T)! - eslint fixes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/visitor-plugin-common@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 - @graphql-codegen/typescript@3.0.0 ## 2.7.13 ### Patch Changes - Updated dependencies [[`a98198524`](https://github.com/dotansimha/graphql-code-generator/commit/a9819852443884b43de7c15040ccffc205f9177a)]: - @graphql-codegen/visitor-plugin-common@2.13.8 - @graphql-codegen/typescript@2.8.8 ## 2.7.12 ### Patch Changes - Updated dependencies [[`eb454d06c`](https://github.com/dotansimha/graphql-code-generator/commit/eb454d06c977f11f7d4a7b0b07eb80f8fd590560)]: - @graphql-codegen/visitor-plugin-common@2.13.7 - @graphql-codegen/typescript@2.8.7 ## 2.7.11 ### Patch Changes - [#8771](https://github.com/dotansimha/graphql-code-generator/pull/8771) [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.8.0`, in `dependencies`) - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 - @graphql-codegen/visitor-plugin-common@2.13.6 - @graphql-codegen/typescript@2.8.6 ## 2.7.10 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/visitor-plugin-common@2.13.5 - @graphql-codegen/typescript@2.8.5 ## 2.7.9 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/visitor-plugin-common@2.13.4 - @graphql-codegen/typescript@2.8.4 ## 2.7.8 ### Patch Changes - Updated dependencies [[`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe)]: - @graphql-codegen/visitor-plugin-common@2.13.3 - @graphql-codegen/typescript@2.8.3 ## 2.7.7 ### Patch Changes - Updated dependencies [[`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122)]: - @graphql-codegen/visitor-plugin-common@2.13.2 - @graphql-codegen/typescript@2.8.2 ## 2.7.6 ### Patch Changes - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/visitor-plugin-common@2.13.1 - @graphql-codegen/plugin-helpers@2.7.2 - @graphql-codegen/typescript@2.8.1 ## 2.7.5 ### Patch Changes - Updated dependencies [[`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b)]: - @graphql-codegen/visitor-plugin-common@2.13.0 - @graphql-codegen/typescript@2.7.5 ## 2.7.4 ### Patch Changes - Updated dependencies [[`1bd7f771c`](https://github.com/dotansimha/graphql-code-generator/commit/1bd7f771ccb949a5a37395c7c57cb41c19340714)]: - @graphql-codegen/visitor-plugin-common@2.12.2 - @graphql-codegen/typescript@2.7.4 ## 2.7.3 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f), [`47d0a57e2`](https://github.com/dotansimha/graphql-code-generator/commit/47d0a57e27dd0d2334670bfc6c81c45e00ff4e74)]: - @graphql-codegen/visitor-plugin-common@2.12.1 - @graphql-codegen/typescript@2.7.3 - @graphql-codegen/plugin-helpers@2.6.2 ## 2.7.2 ### Patch Changes - Updated dependencies [2cbcbb371] - @graphql-codegen/visitor-plugin-common@2.12.0 - @graphql-codegen/plugin-helpers@2.6.0 - @graphql-codegen/typescript@2.7.2 ## 2.7.1 ### Patch Changes - 525ad580b: Revert breaking change for Next.js applications that are incapable of resolving an import with a `.js` extension. - Updated dependencies [525ad580b] - @graphql-codegen/visitor-plugin-common@2.11.1 - @graphql-codegen/typescript@2.7.1 ## 2.7.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [68bb30e19] - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/visitor-plugin-common@2.11.0 - @graphql-codegen/typescript@2.7.0 - @graphql-codegen/plugin-helpers@2.5.0 ## 2.6.7 ### Patch Changes - Updated dependencies [aa1e6eafd] - Updated dependencies [a42fcbfe4] - Updated dependencies [8b10f22be] - @graphql-codegen/typescript@2.6.0 - @graphql-codegen/visitor-plugin-common@2.10.0 ## 2.6.6 ### Patch Changes - Updated dependencies [d16bebacb] - @graphql-codegen/visitor-plugin-common@2.9.1 - @graphql-codegen/typescript@2.5.1 ## 2.6.5 ### Patch Changes - Updated dependencies [c3d7b7226] - @graphql-codegen/visitor-plugin-common@2.9.0 - @graphql-codegen/typescript@2.5.0 ## 2.6.4 ### Patch Changes - Updated dependencies [f1fb77bd4] - @graphql-codegen/visitor-plugin-common@2.8.0 - @graphql-codegen/typescript@2.4.11 ## 2.6.3 ### Patch Changes - Updated dependencies [9a5f31cb6] - @graphql-codegen/typescript@2.4.10 - @graphql-codegen/visitor-plugin-common@2.7.6 ## 2.6.2 ### Patch Changes - Updated dependencies [2966686e9] - @graphql-codegen/visitor-plugin-common@2.7.5 - @graphql-codegen/typescript@2.4.9 ## 2.6.1 ### Patch Changes - 337fd4f77: WP: [typescript-resolvers] Add directiveContextTypes option - Updated dependencies [337fd4f77] - @graphql-codegen/visitor-plugin-common@2.7.4 - @graphql-codegen/typescript@2.4.8 ## 2.6.0 ### Minor Changes - a3b348cd7: feat(resolvers): add factory signature to 'selectionSet' param of stitching resolvers ## 2.5.4 ### Patch Changes - Updated dependencies [54718c039] - @graphql-codegen/typescript@2.4.7 - @graphql-codegen/visitor-plugin-common@2.7.3 ## 2.5.3 ### Patch Changes - 1f5aaf097: Fix #7566 external resolver name export for directiveResolverMappings - Updated dependencies [11d05e361] - @graphql-codegen/visitor-plugin-common@2.7.2 - @graphql-codegen/typescript@2.4.6 ## 2.5.2 ### Patch Changes - Updated dependencies [fd55e2039] - @graphql-codegen/visitor-plugin-common@2.7.1 - @graphql-codegen/typescript@2.4.5 ## 2.5.1 ### Patch Changes - Updated dependencies [1479233df] - @graphql-codegen/visitor-plugin-common@2.7.0 - @graphql-codegen/typescript@2.4.4 ## 2.5.0 ### Minor Changes - bef4376d5: fix: RequireFields generic making all other fields optional ### Patch Changes - c8ef37ae0: fix(typescript-resolvers): Fix optional field types - Updated dependencies [c8ef37ae0] - Updated dependencies [754a33715] - Updated dependencies [bef4376d5] - Updated dependencies [be7cb3a82] - @graphql-codegen/visitor-plugin-common@2.6.0 - @graphql-codegen/plugin-helpers@2.4.0 - @graphql-codegen/typescript@2.4.3 ## 2.4.3 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/visitor-plugin-common@2.5.2 - @graphql-codegen/typescript@2.4.2 - @graphql-codegen/plugin-helpers@2.3.2 ## 2.4.2 ### Patch Changes - Updated dependencies [a9f1f1594] - Updated dependencies [9ea6621ec] - @graphql-codegen/visitor-plugin-common@2.5.1 - @graphql-codegen/typescript@2.4.1 ## 2.4.1 ### Patch Changes - 3d57ec666: loosen return type of SubscriptionSubscribeFn from `PromiseOrValue` to `PromiseOrValue`. This fixes type conflicts with libraries such as `ix/asynciterable` and is what `graphql-js` expects. ## 2.4.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/visitor-plugin-common@2.5.0 - @graphql-codegen/typescript@2.3.0 - @graphql-codegen/plugin-helpers@2.3.0 ## 2.3.2 ### Patch Changes - Updated dependencies [ad02cb9b8] - @graphql-codegen/visitor-plugin-common@2.4.0 - @graphql-codegen/typescript@2.2.4 ## 2.3.1 ### Patch Changes - Updated dependencies [b9e85adae] - Updated dependencies [7c60e5acc] - Updated dependencies [3c2c847be] - @graphql-codegen/visitor-plugin-common@2.3.0 - @graphql-codegen/plugin-helpers@2.2.0 - @graphql-codegen/typescript@2.2.3 ## 2.3.0 ### Minor Changes - 46b38d9c1: Add makeResolverTypeCallable property to config which allows a resolver function to be called ## 2.2.1 ### Patch Changes - Updated dependencies [0b090e31a] - @graphql-codegen/visitor-plugin-common@2.2.1 - @graphql-codegen/typescript@2.2.2 ## 2.2.0 ### Minor Changes - 5086791ac: Allow overwriting the resolver type signature based on directive usages. **WARNING:** Using this option does only change the generated type definitions. For actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://www.graphql-tools.com/docs/schema-directives)) that apply those rules! Otherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors. Example configuration: ```yaml config: # This was possible before customResolverFn: ../resolver-types.ts#UnauthenticatedResolver # This is new directiveResolverMappings: authenticated: ../resolvers-types.ts#AuthenticatedResolver ``` Example mapping file (`resolver-types.ts`): ```ts export type UnauthenticatedContext = { user: null } export type AuthenticatedContext = { user: { id: string } } export type UnauthenticatedResolver = ( parent: TParent, args: TArgs, context: UnauthenticatedContext, info: GraphQLResolveInfo ) => Promise | TResult export type AuthenticatedResolver = ( parent: TParent, args: TArgs, context: AuthenticatedContext, info: GraphQLResolveInfo ) => Promise | TResult ``` Example Schema: ```graphql directive @authenticated on FIELD_DEFINITION type Query { yee: String foo: String @authenticated } ``` ### Patch Changes - Updated dependencies [d6c2d4c09] - Updated dependencies [feeae1c66] - Updated dependencies [8261e4161] - Updated dependencies [5086791ac] - @graphql-codegen/visitor-plugin-common@2.2.0 - @graphql-codegen/typescript@2.2.0 ## 2.1.2 ### Patch Changes - Updated dependencies [6470e6cc9] - Updated dependencies [263570e50] - Updated dependencies [35199dedf] - @graphql-codegen/visitor-plugin-common@2.1.2 - @graphql-codegen/plugin-helpers@2.1.1 - @graphql-codegen/typescript@2.1.2 ## 2.1.1 ### Patch Changes - Updated dependencies [aabeff181] - @graphql-codegen/visitor-plugin-common@2.1.1 - @graphql-codegen/typescript@2.1.1 ## 2.1.0 ### Minor Changes - 39773f59b: enhance(plugins): use getDocumentNodeFromSchema and other utilities from @graphql-tools/utils - 440172cfe: support ESM ### Patch Changes - 24185985a: bump graphql-tools package versions - 440172cfe: export config types - Updated dependencies [290170262] - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/visitor-plugin-common@2.1.0 - @graphql-codegen/plugin-helpers@2.1.0 - @graphql-codegen/typescript@2.1.0 ## 2.0.0 ### Major Changes - d80efdec4: Set `noSchemaStitching: true` by default. If you need the resolvers signature to support schema-stitching, please add to your config: ```yaml noSchemaStitching: false ``` - d80efdec4: Remove deprecated `IDirectiveResolvers` and `IResolvers` signatures Please use `DirectiveResolvers` and `Resolvers` types instead. - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [d80efdec4] - Updated dependencies [d80efdec4] - Updated dependencies [b0cb13df4] - @graphql-codegen/visitor-plugin-common@2.0.0 - @graphql-codegen/typescript@2.0.0 - @graphql-codegen/plugin-helpers@2.0.0 ## 1.20.0 ### Minor Changes - 8e4d5826: Add a new type for StitchResolver without selectionSet - 9005cc17: add `allowEnumStringTypes` option for allowing string literals as valid return types from resolvers in addition to enum values.\_ ### Patch Changes - df19a4ed: Allow multiple `{T}` instances in defaultMapper - Updated dependencies [df19a4ed] - Updated dependencies [470336a1] - Updated dependencies [9005cc17] - @graphql-codegen/visitor-plugin-common@1.22.0 - @graphql-codegen/plugin-helpers@1.18.8 - @graphql-codegen/typescript@1.23.0 ## 1.19.5 ### Patch Changes - Updated dependencies [6762aff5] - @graphql-codegen/visitor-plugin-common@1.21.3 - @graphql-codegen/typescript@1.22.4 ## 1.19.4 ### Patch Changes - Updated dependencies [6aaecf1c] - @graphql-codegen/visitor-plugin-common@1.21.2 - @graphql-codegen/typescript@1.22.3 ## 1.19.3 ### Patch Changes - Updated dependencies [cf1e5abc] - @graphql-codegen/visitor-plugin-common@1.21.1 - @graphql-codegen/typescript@1.22.2 ## 1.19.2 ### Patch Changes - dfd25caf: chore(deps): bump graphql-tools versions - Updated dependencies [dfd25caf] - Updated dependencies [8da7dff6] - @graphql-codegen/visitor-plugin-common@1.21.0 - @graphql-codegen/plugin-helpers@1.18.7 - @graphql-codegen/typescript@1.22.1 ## 1.19.1 ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - Updated dependencies [f0b5ea53] - Updated dependencies [097bea2f] - @graphql-codegen/visitor-plugin-common@1.20.0 - @graphql-codegen/typescript@1.22.0 - @graphql-codegen/plugin-helpers@1.18.5 ## 1.19.0 ### Minor Changes - d4942d04: NEW CONFIG (`onlyResolveTypeForInterfaces`): Allow to generate only \_\_resolveType for interfaces ### Patch Changes - 29b75b1e: enhance(namingConvention): use change-case-all instead of individual packages for naming convention - Updated dependencies [e947f8e3] - Updated dependencies [29b75b1e] - Updated dependencies [d4942d04] - Updated dependencies [1f6f3db6] - Updated dependencies [29b75b1e] - @graphql-codegen/visitor-plugin-common@1.19.0 - @graphql-codegen/typescript@1.21.1 - @graphql-codegen/plugin-helpers@1.18.3 ## 1.18.2 ### Patch Changes - 5749cb8a: chore: fix type-level incompatibilities of the `avoidOptionals` - Updated dependencies [34b8087e] - Updated dependencies [5749cb8a] - Updated dependencies [5a12fe58] - @graphql-codegen/typescript@1.21.0 - @graphql-codegen/visitor-plugin-common@1.18.3 ## 1.18.1 ### Patch Changes - fd5843a7: Fixed a bug where some import namespacing is missed when generating resolver types. - Updated dependencies [64293437] - Updated dependencies [fd5843a7] - Updated dependencies [d75051f5] - @graphql-codegen/visitor-plugin-common@1.17.22 ## 1.18.0 ### Minor Changes - 8356f8a2: Added a new config flag for customizing `isTypeOf` and `resolveType` prefix (`internalResolversPrefix`) ### Patch Changes - Updated dependencies [8356f8a2] - Updated dependencies [1d6a593f] - @graphql-codegen/visitor-plugin-common@1.17.21 - @graphql-codegen/typescript@1.19.0 ## 1.17.12 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/visitor-plugin-common@1.17.20 - @graphql-codegen/typescript@1.18.1 - @graphql-codegen/plugin-helpers@1.18.2 ## 1.17.11 ### Patch Changes - faa13973: Fixed issues with mappers setup - Updated dependencies [faa13973] - @graphql-codegen/visitor-plugin-common@1.17.18 ## 1.17.10 ### Patch Changes - d2cde3d5: fixed isTypeOf resolvers signature - 89a6aa80: Fixes issues with typesSuffix and arguments type name - Updated dependencies [d2cde3d5] - Updated dependencies [89a6aa80] - Updated dependencies [f603b8f8] - Updated dependencies [7ad7a1ae] - Updated dependencies [da8bdd17] - @graphql-codegen/visitor-plugin-common@1.17.15 - @graphql-codegen/typescript@1.17.10 - @graphql-codegen/plugin-helpers@1.17.9 ## 1.17.9 ### Patch Changes - ed7f6b97: Fix issues with mappers not being applied for interfaces or unions ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - af3803b8: only transform federated parent types when they contain @external directive - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/visitor-plugin-common@1.17.13 - @graphql-codegen/plugin-helpers@1.17.8 - @graphql-codegen/typescript@1.17.8 ================================================ FILE: packages/plugins/typescript/resolvers/package.json ================================================ { "name": "@graphql-codegen/typescript-resolvers", "version": "5.1.7", "description": "GraphQL Code Generator plugin for generating TypeScript types for resolvers signature", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/typescript/resolvers" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-codegen/typescript": "^5.0.9", "@graphql-codegen/visitor-plugin-common": "^6.2.4", "@graphql-tools/utils": "^11.0.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql-sock": "^1.0.0" }, "peerDependenciesMeta": { "graphql-sock": { "optional": true } }, "devDependencies": { "graphql-subscriptions": "3.0.0", "graphql-sock": "1.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/typescript/resolvers/src/config.ts ================================================ import { RawResolversConfig } from '@graphql-codegen/visitor-plugin-common'; /** * @description This plugin generates TypeScript signature for `resolve` functions of your GraphQL API. * You can use this plugin to generate simple resolvers signature based on your GraphQL types, or you can change its behavior be providing custom model types (mappers). * * You can find a blog post explaining the usage of this plugin here: https://the-guild.dev/blog/better-type-safety-for-resolvers-with-graphql-codegen * */ export interface TypeScriptResolversPluginConfig extends RawResolversConfig { /** * @description Adds an index signature to any generates resolver. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * useIndexSignature: true * }, * }, * }, * }; * export default config; * ``` */ useIndexSignature?: boolean; /** * @description Disables/Enables Schema Stitching support. * By default, the resolver signature does not include the support for schema-stitching. * Set to `false` to enable that. * * @default true * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * noSchemaStitching: false * }, * }, * }, * }; * export default config; * ``` */ noSchemaStitching?: boolean; /** * @description Set to `true` in order to wrap field definitions with `FieldWrapper`. * This is useful to allow return types such as Promises and functions. Needed for * compatibility with `federation: true` when * @default true */ wrapFieldDefinitions?: boolean; /** * @description You can provide your custom GraphQLResolveInfo instead of the default one from graphql-js * @default "graphql#GraphQLResolveInfo" * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * customResolveInfo: './my-types#MyResolveInfo' * }, * }, * }, * }; * export default config; * ``` */ customResolveInfo?: string; /** * @description You can provide your custom ResolveFn instead the default. It has to be a type that uses the generics `` * @default "(parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo) => Promise | TResult" * * @exampleMarkdown * ## Custom Signature * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * customResolverFn: './my-types#MyResolveFn' * }, * }, * }, * }; * export default config; * ``` * * ## With Graphile * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * customResolverFn: './my-types#MyResolveFn' * }, * }, * }, * }; * export default config; * ``` * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * "path/to/file.ts": { * "plugins": [ * { * "add": { * "content": "import { GraphileHelpers } from 'graphile-utils/node8plus/fieldHelpers';" * } * }, * "typescript", * "typescript-resolvers" * ], * "config": { * "customResolverFn": "(\n parent: TParent,\n args: TArgs,\n context: TContext,\n info: GraphQLResolveInfo & { graphile: GraphileHelpers }\n) => Promise | TResult;\n" * } * } * } * }; * export default config; * ``` * */ customResolverFn?: string; /** * @description Map the usage of a directive into using a specific resolver. * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * customResolverFn: '../resolver-types.ts#UnauthenticatedResolver', * directiveResolverMappings: { * authenticated: '../resolvers-types.ts#AuthenticatedResolver', * }, * }, * }, * }, * }; * export default config; * ``` */ directiveResolverMappings?: Record; /** * @description Allow you to override the `ParentType` generic in each resolver, by avoid enforcing the base type of the generated generic type. * * This will generate `ParentType = Type` instead of `ParentType extends Type = Type` in each resolver. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * allowParentTypeOverride: true * }, * }, * }, * }; * export default config; * ``` * */ allowParentTypeOverride?: boolean; /** * @description Sets `info` argument of resolver function to be optional field. Useful for testing. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * optionalInfoArgument: true * }, * }, * }, * }; * export default config; * ``` * */ optionalInfoArgument?: boolean; /** * @description Set to `true` in order to allow the Resolver type to be callable * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * makeResolverTypeCallable: true * }, * }, * }, * }; * export default config; * ``` */ makeResolverTypeCallable?: boolean; } ================================================ FILE: packages/plugins/typescript/resolvers/src/index.ts ================================================ import { addFederationReferencesToSchema, getCachedDocumentNodeFromSchema, oldVisit, PluginFunction, Types, } from '@graphql-codegen/plugin-helpers'; import { parseMapper, type RootResolver } from '@graphql-codegen/visitor-plugin-common'; import { GraphQLSchema } from 'graphql'; import { TypeScriptResolversPluginConfig } from './config.js'; import { TypeScriptResolversVisitor } from './visitor.js'; const capitalize = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1); export const plugin: PluginFunction< TypeScriptResolversPluginConfig, Types.ComplexPluginOutput<{ generatedResolverTypes: RootResolver['generatedResolverTypes']; }> > = async (schema: GraphQLSchema, documents: Types.DocumentFile[], config: TypeScriptResolversPluginConfig) => { const imports = []; if (!config.customResolveInfo) { imports.push('GraphQLResolveInfo'); } const showUnusedMappers = typeof config.showUnusedMappers === 'boolean' ? config.showUnusedMappers : true; const noSchemaStitching = typeof config.noSchemaStitching === 'boolean' ? config.noSchemaStitching : true; const indexSignature = config.useIndexSignature ? [ 'export type WithIndex = TObject & Record;', 'export type ResolversObject = WithIndex;', ].join('\n') : ''; const importType = config.useTypeImports ? 'import type' : 'import'; const emptyObjectType = `Record`; const prepend: string[] = []; const defsToInclude: string[] = []; const directiveResolverMappings = {} as Record; if (config.directiveResolverMappings) { for (const [directiveName, mapper] of Object.entries(config.directiveResolverMappings)) { const parsedMapper = parseMapper(mapper); const capitalizedDirectiveName = capitalize(directiveName); const resolverFnName = `ResolverFn${capitalizedDirectiveName}`; const resolverFnUsage = `${resolverFnName}`; const resolverWithResolveUsage = `Resolver${capitalizedDirectiveName}WithResolve`; const resolverWithResolve = ` export type Resolver${capitalizedDirectiveName}WithResolve = { resolve: ${resolverFnName}; };`; const resolverTypeName = `Resolver${capitalizedDirectiveName}`; const resolverType = `export type ${resolverTypeName} =`; if (parsedMapper.isExternal) { if (parsedMapper.default) { prepend.push(`${importType} ${resolverFnName} from '${parsedMapper.source}';`); } else { prepend.push( `${importType} { ${parsedMapper.import} ${ parsedMapper.import === resolverFnName ? '' : `as ${resolverFnName} ` }} from '${parsedMapper.source}';` ); } prepend.push(`export${config.useTypeImports ? ' type' : ''} { ${resolverFnName} };`); } else { defsToInclude.push(`export type ${resolverFnName} = ${parsedMapper.type}`); } if (config.makeResolverTypeCallable) { defsToInclude.push(`${resolverType} ${resolverFnUsage};`); } else { defsToInclude.push(resolverWithResolve, `${resolverType} ${resolverFnUsage} | ${resolverWithResolveUsage};`); } directiveResolverMappings[directiveName] = resolverTypeName; } } let { transformedSchema, federationMeta } = config.federation ? addFederationReferencesToSchema(schema) : { transformedSchema: schema, federationMeta: {} }; transformedSchema = config.customDirectives?.semanticNonNull ? await semanticToStrict(transformedSchema) : transformedSchema; const visitor = new TypeScriptResolversVisitor( { ...config, directiveResolverMappings }, transformedSchema, federationMeta ); const namespacedImportPrefix = visitor.config.namespacedImportName ? `${visitor.config.namespacedImportName}.` : ''; const astNode = getCachedDocumentNodeFromSchema(transformedSchema); // runs visitor const visitorResult = oldVisit(astNode, { leave: visitor }); const optionalSignForInfoArg = visitor.config.optionalInfoArgument ? '?' : ''; const legacyStitchingResolverType = ` export type LegacyStitchingResolver = { fragment: string; resolve: ResolverFn; };`; const newStitchingResolverType = ` export type NewStitchingResolver = { selectionSet: string | ((fieldNode: FieldNode) => SelectionSetNode); resolve: ResolverFn; };`; const stitchingResolverType = `export type StitchingResolver = LegacyStitchingResolver | NewStitchingResolver;`; const resolverWithResolve = ` export type ResolverWithResolve = { resolve: ResolverFn; };`; const resolverType = `export type Resolver =`; const resolverFnUsage = `ResolverFn`; const resolverWithResolveUsage = `ResolverWithResolve`; const stitchingResolverUsage = `StitchingResolver`; if (visitor.hasFederation()) { defsToInclude.push( `export type ReferenceResolver = ( reference: TReference, context: TContext, info${optionalSignForInfoArg}: GraphQLResolveInfo ) => Promise | TResult;`, ` type ScalarCheck = S extends true ? T : NullableCheck; type NullableCheck = ${namespacedImportPrefix}Maybe extends T ? ${namespacedImportPrefix}Maybe, S>> : ListCheck; type ListCheck = T extends (infer U)[] ? NullableCheck[] : GraphQLRecursivePick; export type GraphQLRecursivePick = { [K in keyof T & keyof S]: ScalarCheck }; ` ); } if (!config.makeResolverTypeCallable) { defsToInclude.push(resolverWithResolve); } if (noSchemaStitching) { const defs = config.makeResolverTypeCallable ? // Resolver = ResolverFn `${resolverType} ${resolverFnUsage};` : // Resolver = ResolverFn | ResolverWithResolve `${resolverType} ${resolverFnUsage} | ${resolverWithResolveUsage};`; defsToInclude.push(defs); } else { // StitchingResolver // Resolver = // | ResolverFn // | ResolverWithResolve // | StitchingResolver; defsToInclude.push( [ legacyStitchingResolverType, newStitchingResolverType, stitchingResolverType, resolverType, ` | ${resolverFnUsage}`, config.makeResolverTypeCallable ? `` : ` | ${resolverWithResolveUsage}`, ` | ${stitchingResolverUsage};`, ].join('\n') ); imports.push('SelectionSetNode', 'FieldNode'); } if (config.customResolverFn) { const parsedMapper = parseMapper(config.customResolverFn); if (parsedMapper.isExternal) { if (parsedMapper.default) { prepend.push(`${importType} ResolverFn from '${parsedMapper.source}';`); } else { prepend.push( `${importType} { ${parsedMapper.import} ${ parsedMapper.import === 'ResolverFn' ? '' : 'as ResolverFn ' }} from '${parsedMapper.source}';` ); } prepend.push(`export${config.useTypeImports ? ' type' : ''} { ResolverFn };`); } else { prepend.push(`export type ResolverFn = ${parsedMapper.type}`); } } else { const defaultResolverFn = ` export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info${optionalSignForInfoArg}: GraphQLResolveInfo ) => Promise | TResult;`; defsToInclude.push(defaultResolverFn); } const header = `${indexSignature} ${visitor.getResolverTypeWrapperSignature()} ${defsToInclude.join('\n')} export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info${optionalSignForInfoArg}: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info${optionalSignForInfoArg}: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn = ( parent: TParent, context: TContext, info${optionalSignForInfoArg}: GraphQLResolveInfo ) => ${namespacedImportPrefix}Maybe | Promise<${namespacedImportPrefix}Maybe>; export type IsTypeOfResolverFn = (obj: T, context: TContext, info${optionalSignForInfoArg}: GraphQLResolveInfo) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info${optionalSignForInfoArg}: GraphQLResolveInfo ) => TResult | Promise; `; const federationTypes = visitor.buildFederationTypes(); const federationReferenceTypes = visitor.buildFederationReferenceTypes(); const resolversTypeMapping = visitor.buildResolversTypes(); const resolversParentTypeMapping = visitor.buildResolversParentTypes(); const resolversUnionTypesMapping = visitor.buildResolversUnionTypes(); const resolversInterfaceTypesMapping = visitor.buildResolversInterfaceTypes(); const { getRootResolver, getAllDirectiveResolvers, mappersImports, unusedMappers, hasScalars } = visitor; if (hasScalars()) { imports.push('GraphQLScalarType', 'GraphQLScalarTypeConfig'); } if (showUnusedMappers && unusedMappers.length) { // eslint-disable-next-line no-console console.warn(`Unused mappers: ${unusedMappers.join(',')}`); } if (imports.length) { prepend.push(`${importType} { ${imports.join(', ')} } from 'graphql';`); } if (config.customResolveInfo) { const parsedMapper = parseMapper(config.customResolveInfo); if (parsedMapper.isExternal) { if (parsedMapper.default) { prepend.push(`${importType} GraphQLResolveInfo from '${parsedMapper.source}'`); } prepend.push( `${importType} { ${parsedMapper.import} ${ parsedMapper.import === 'GraphQLResolveInfo' ? '' : 'as GraphQLResolveInfo' } } from '${parsedMapper.source}';` ); } else { prepend.push(`type GraphQLResolveInfo = ${parsedMapper.type}`); } } prepend.push(...mappersImports, ...visitor.globalDeclarations); const rootResolver = getRootResolver(); return { prepend, content: [ header, federationTypes, federationReferenceTypes, resolversUnionTypesMapping, resolversInterfaceTypesMapping, resolversTypeMapping, resolversParentTypeMapping, ...visitorResult.definitions.filter(d => typeof d === 'string'), rootResolver.content, getAllDirectiveResolvers(), ].join('\n'), meta: { generatedResolverTypes: rootResolver.generatedResolverTypes, }, }; }; export { TypeScriptResolversPluginConfig, TypeScriptResolversVisitor }; const semanticToStrict = async (schema: GraphQLSchema): Promise => { try { const sock = await import('graphql-sock'); return sock.semanticToStrict(schema); } catch { throw new Error( "To use the `customDirective.semanticNonNull` option, you must install the 'graphql-sock' package." ); } }; ================================================ FILE: packages/plugins/typescript/resolvers/src/visitor.ts ================================================ import { TypeScriptOperationVariablesToObject } from '@graphql-codegen/typescript'; import { BaseResolversVisitor, DeclarationKind, DEFAULT_SCALARS, getConfigValue, normalizeAvoidOptionals, ParsedResolversConfig, } from '@graphql-codegen/visitor-plugin-common'; import type { FederationMeta } from '@graphql-codegen/plugin-helpers'; import autoBind from 'auto-bind'; import { EnumTypeDefinitionNode, GraphQLSchema, ListTypeNode, NamedTypeNode, NonNullTypeNode } from 'graphql'; import { TypeScriptResolversPluginConfig } from './config.js'; export const ENUM_RESOLVERS_SIGNATURE = 'export type EnumResolverSignature = { [key in keyof T]?: AllowedValues };'; export interface ParsedTypeScriptResolversConfig extends ParsedResolversConfig { useIndexSignature: boolean; wrapFieldDefinitions: boolean; allowParentTypeOverride: boolean; optionalInfoArgument: boolean; } export class TypeScriptResolversVisitor extends BaseResolversVisitor< TypeScriptResolversPluginConfig, ParsedTypeScriptResolversConfig > { constructor(pluginConfig: TypeScriptResolversPluginConfig, schema: GraphQLSchema, federationMeta: FederationMeta) { super( pluginConfig, { avoidOptionals: normalizeAvoidOptionals(pluginConfig.avoidOptionals), useIndexSignature: getConfigValue(pluginConfig.useIndexSignature, false), wrapFieldDefinitions: getConfigValue(pluginConfig.wrapFieldDefinitions, false), allowParentTypeOverride: getConfigValue(pluginConfig.allowParentTypeOverride, false), optionalInfoArgument: getConfigValue(pluginConfig.optionalInfoArgument, false), } as ParsedTypeScriptResolversConfig, schema, DEFAULT_SCALARS, federationMeta ); autoBind(this); this.setVariablesTransformer( new TypeScriptOperationVariablesToObject( this.scalars, this.convertName, this.config.avoidOptionals, this.config.immutableTypes, this.config.namespacedImportName, [], this.config.enumPrefix, this.config.enumSuffix, this.config.enumValues ) ); if (this.config.useIndexSignature) { this._declarationBlockConfig = { blockTransformer(block) { return `ResolversObject<${block}>`; }, }; } } protected transformParentGenericType(parentType: string): string { if (this.config.allowParentTypeOverride) { return `ParentType = ${parentType}`; } return `ParentType extends ${parentType} = ${parentType}`; } protected formatRootResolver(schemaTypeName: string, resolverType: string, declarationKind: DeclarationKind): string { const avoidOptionals = this.config.avoidOptionals.resolvers; return `${schemaTypeName}${avoidOptionals ? '' : '?'}: ${resolverType}${this.getPunctuation(declarationKind)}`; } private clearOptional(str: string): string { if (str.startsWith('Maybe')) { return str.replace(/Maybe<(.*?)>$/, '$1'); } return str; } ListType(node: ListTypeNode): string { return `Maybe<${super.ListType(node)}>`; } protected wrapWithListType(str: string): string { return `${this.config.immutableTypes ? 'ReadonlyArray' : 'Array'}<${str}>`; } NamedType(node: NamedTypeNode): string { return `Maybe<${super.NamedType(node)}>`; } NonNullType(node: NonNullTypeNode): string { const baseValue = super.NonNullType(node); return this.clearOptional(baseValue); } protected getPunctuation(_declarationKind: DeclarationKind): string { return ';'; } protected buildEnumResolverContentBlock(node: EnumTypeDefinitionNode, mappedEnumType: string): string { const valuesMap = `{ ${(node.values || []) .map(v => `${v.name.value}${this.config.avoidOptionals.resolvers ? '' : '?'}: any`) .join(', ')} }`; this._globalDeclarations.add(ENUM_RESOLVERS_SIGNATURE); return `EnumResolverSignature<${valuesMap}, ${mappedEnumType}>`; } protected buildEnumResolversExplicitMappedValues( node: EnumTypeDefinitionNode, valuesMapping: { [valueName: string]: string | number } ): string { return `{ ${(node.values || []) .map(v => { const valueName = v.name.value; const mappedValue = valuesMapping[valueName] ?? valueName; const hasMapping = !!valuesMapping[valueName]; return `${valueName}${hasMapping || this.config.avoidOptionals.resolvers ? '' : '?'}: ${ typeof mappedValue === 'number' ? mappedValue : `'${mappedValue}'` }`; }) .join(', ')} }`; } } ================================================ FILE: packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap ================================================ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`TypeScript Resolvers Plugin > Config > allowParentTypeOverride - should allow to have less strict resolvers by overrding parent type 1`] = ` "export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; export type Omit = Pick>; export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } MyScalar: { input: any; output: any; } }; export type MyType = { __typename?: 'MyType'; foo: Scalars['String']['output']; otherType?: Maybe; withArgs?: Maybe; unionChild?: Maybe; }; export type MyTypeWithArgsArgs = { arg?: InputMaybe; arg2: Scalars['String']['input']; }; export type Child = { __typename?: 'Child'; bar: Scalars['String']['output']; parent?: Maybe; }; export type MyOtherType = { __typename?: 'MyOtherType'; bar: Scalars['String']['output']; }; export type ChildUnion = Child | MyOtherType; export type Query = { __typename?: 'Query'; something: MyType; }; export type Subscription = { __typename?: 'Subscription'; somethingChanged?: Maybe; }; export type Node = { id: Scalars['ID']['output']; }; export type SomeNode = Node & { __typename?: 'SomeNode'; id: Scalars['ID']['output']; }; export type AnotherNode = { id: Scalars['ID']['output']; }; export type WithChild = { unionChild?: Maybe; node?: Maybe; }; export type WithChildren = { unionChildren: Array; nodes: Array; }; export type AnotherNodeWithChild = AnotherNode & WithChild & { __typename?: 'AnotherNodeWithChild'; id: Scalars['ID']['output']; unionChild?: Maybe; interfaceChild?: Maybe; }; export type AnotherNodeWithAll = AnotherNode & WithChild & WithChildren & { __typename?: 'AnotherNodeWithAll'; id: Scalars['ID']['output']; unionChild?: Maybe; unionChildren: Array; interfaceChild?: Maybe; interfaceChildren: Array; }; export type MyUnion = MyType | MyOtherType; export type WithIndex = TObject & Record; export type ResolversObject = WithIndex; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver, TContext = Record, TArgs = Record> = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver, TContext = Record, TArgs = Record> = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = (obj: T, context: TContext, info: GraphQLResolveInfo) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn, TParent = Record, TContext = Record, TArgs = Record> = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping of union types */ export type ResolversUnionTypes<_RefType extends Record> = ResolversObject<{ ChildUnion: | ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ) ; MyUnion: | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']> } ) | ( MyOtherType ) ; }>; /** Mapping of interface types */ export type ResolversInterfaceTypes<_RefType extends Record> = ResolversObject<{ Node: ( SomeNode ); AnotherNode: | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ) ; WithChild: | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ) ; WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }>; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = ResolversObject<{ MyType: ResolverTypeWrapper & { unionChild?: Maybe }>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }>; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = ResolversObject<{ MyType: Omit & { unionChild?: Maybe }; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: Omit & { unionChild?: Maybe, interfaceChild?: Maybe }; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }>; export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; export type MyDirectiveDirectiveResolver = DirectiveResolverFn; export type AuthenticatedDirectiveArgs = { }; export type AuthenticatedDirectiveResolver = DirectiveResolverFn; export type MyTypeResolvers = ResolversObject<{ foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type ChildResolvers = ResolversObject<{ bar?: Resolver; parent?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type MyOtherTypeResolvers = ResolversObject<{ bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; export type ChildUnionResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'Child' | 'MyOtherType', ParentType, ContextType>; }>; export type QueryResolvers = ResolversObject<{ something?: Resolver; }>; export type SubscriptionResolvers = ResolversObject<{ somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }>; export type NodeResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }>; export type SomeNodeResolvers = ResolversObject<{ id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; export type AnotherNodeResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'AnotherNodeWithChild' | 'AnotherNodeWithAll', ParentType, ContextType>; }>; export type WithChildResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'AnotherNodeWithChild' | 'AnotherNodeWithAll', ParentType, ContextType>; }>; export type WithChildrenResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'AnotherNodeWithAll', ParentType, ContextType>; }>; export type AnotherNodeWithChildResolvers = ResolversObject<{ id?: Resolver; unionChild?: Resolver, ParentType, ContextType>; interfaceChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type AnotherNodeWithAllResolvers = ResolversObject<{ id?: Resolver; unionChild?: Resolver, ParentType, ContextType>; unionChildren?: Resolver, ParentType, ContextType>; interfaceChild?: Resolver, ParentType, ContextType>; interfaceChildren?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type MyUnionResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }>; export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; } export type Resolvers = ResolversObject<{ MyType?: MyTypeResolvers; Child?: ChildResolvers; MyOtherType?: MyOtherTypeResolvers; ChildUnion?: ChildUnionResolvers; Query?: QueryResolvers; Subscription?: SubscriptionResolvers; Node?: NodeResolvers; SomeNode?: SomeNodeResolvers; AnotherNode?: AnotherNodeResolvers; WithChild?: WithChildResolvers; WithChildren?: WithChildrenResolvers; AnotherNodeWithChild?: AnotherNodeWithChildResolvers; AnotherNodeWithAll?: AnotherNodeWithAllResolvers; MyUnion?: MyUnionResolvers; MyScalar?: GraphQLScalarType; }>; export type DirectiveResolvers = ResolversObject<{ myDirective?: MyDirectiveDirectiveResolver; authenticated?: AuthenticatedDirectiveResolver; }>; export const myTypeResolvers: MyTypeResolvers<{}, { parentOverride: boolean }> = { foo: (parentValue) => { const a: boolean = parentValue.parentOverride; return a.toString(); } }; " `; exports[`TypeScript Resolvers Plugin > Config > namespacedImportName - should work correctly with imported namespaced type 1`] = ` "import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; export type Omit = Pick>; export type RequireFields = Omit & { [P in K]-?: NonNullable }; export type WithIndex = TObject & Record; export type ResolversObject = WithIndex; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver, TContext = Record, TArgs = Record> = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver, TContext = Record, TArgs = Record> = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Types.Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = (obj: T, context: TContext, info: GraphQLResolveInfo) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn, TParent = Record, TContext = Record, TArgs = Record> = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping of union types */ export type ResolversUnionTypes<_RefType extends Record> = ResolversObject<{ ChildUnion: | ( Omit & { parent?: Types.Maybe<_RefType['MyType']> } ) | ( Types.MyOtherType ) ; MyUnion: | ( Omit & { unionChild?: Types.Maybe<_RefType['ChildUnion']> } ) | ( Types.MyOtherType ) ; }>; /** Mapping of interface types */ export type ResolversInterfaceTypes<_RefType extends Record> = ResolversObject<{ Node: ( Types.SomeNode ); AnotherNode: | ( Omit & { unionChild?: Types.Maybe<_RefType['ChildUnion']>, interfaceChild?: Types.Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Types.Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Types.Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ) ; WithChild: | ( Omit & { unionChild?: Types.Maybe<_RefType['ChildUnion']>, interfaceChild?: Types.Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Types.Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Types.Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ) ; WithChildren: ( Omit & { unionChild?: Types.Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Types.Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }>; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = ResolversObject<{ MyType: ResolverTypeWrapper & { unionChild?: Types.Maybe }>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Types.Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Types.Maybe, interfaceChild?: Types.Maybe }>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Types.Maybe, unionChildren: Array, interfaceChild?: Types.Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }>; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = ResolversObject<{ MyType: Omit & { unionChild?: Types.Maybe }; String: Types.Scalars['String']['output']; Child: Omit & { parent?: Types.Maybe }; MyOtherType: Types.MyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Types.Scalars['ID']['output']; SomeNode: Types.SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: Omit & { unionChild?: Types.Maybe, interfaceChild?: Types.Maybe }; AnotherNodeWithAll: Omit & { unionChild?: Types.Maybe, unionChildren: Array, interfaceChild?: Types.Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Types.Scalars['MyScalar']['output']; Int: Types.Scalars['Int']['output']; Boolean: Types.Scalars['Boolean']['output']; }>; export type MyDirectiveDirectiveArgs = { arg: Types.Scalars['Int']['input']; arg2: Types.Scalars['String']['input']; arg3: Types.Scalars['Boolean']['input']; }; export type MyDirectiveDirectiveResolver = DirectiveResolverFn; export type AuthenticatedDirectiveArgs = { }; export type AuthenticatedDirectiveResolver = DirectiveResolverFn; export type MyTypeResolvers = ResolversObject<{ foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type ChildResolvers = ResolversObject<{ bar?: Resolver; parent?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type MyOtherTypeResolvers = ResolversObject<{ bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; export type ChildUnionResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'Child' | 'MyOtherType', ParentType, ContextType>; }>; export type QueryResolvers = ResolversObject<{ something?: Resolver; }>; export type SubscriptionResolvers = ResolversObject<{ somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }>; export type NodeResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }>; export type SomeNodeResolvers = ResolversObject<{ id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; export type AnotherNodeResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'AnotherNodeWithChild' | 'AnotherNodeWithAll', ParentType, ContextType>; }>; export type WithChildResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'AnotherNodeWithChild' | 'AnotherNodeWithAll', ParentType, ContextType>; }>; export type WithChildrenResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'AnotherNodeWithAll', ParentType, ContextType>; }>; export type AnotherNodeWithChildResolvers = ResolversObject<{ id?: Resolver; unionChild?: Resolver, ParentType, ContextType>; interfaceChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type AnotherNodeWithAllResolvers = ResolversObject<{ id?: Resolver; unionChild?: Resolver, ParentType, ContextType>; unionChildren?: Resolver, ParentType, ContextType>; interfaceChild?: Resolver, ParentType, ContextType>; interfaceChildren?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type MyUnionResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }>; export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; } export type Resolvers = ResolversObject<{ MyType?: MyTypeResolvers; Child?: ChildResolvers; MyOtherType?: MyOtherTypeResolvers; ChildUnion?: ChildUnionResolvers; Query?: QueryResolvers; Subscription?: SubscriptionResolvers; Node?: NodeResolvers; SomeNode?: SomeNodeResolvers; AnotherNode?: AnotherNodeResolvers; WithChild?: WithChildResolvers; WithChildren?: WithChildrenResolvers; AnotherNodeWithChild?: AnotherNodeWithChildResolvers; AnotherNodeWithAll?: AnotherNodeWithAllResolvers; MyUnion?: MyUnionResolvers; MyScalar?: GraphQLScalarType; }>; export type DirectiveResolvers = ResolversObject<{ myDirective?: MyDirectiveDirectiveResolver; authenticated?: AuthenticatedDirectiveResolver; }>; " `; exports[`TypeScript Resolvers Plugin > Config > optionalInfoArgument - should allow to have optional info argument 1`] = ` "export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; export type Omit = Pick>; export type RequireFields = Omit & { [P in K]-?: NonNullable }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } MyScalar: { input: any; output: any; } }; export type MyType = { __typename?: 'MyType'; foo: Scalars['String']['output']; otherType?: Maybe; withArgs?: Maybe; unionChild?: Maybe; }; export type MyTypeWithArgsArgs = { arg?: InputMaybe; arg2: Scalars['String']['input']; }; export type Child = { __typename?: 'Child'; bar: Scalars['String']['output']; parent?: Maybe; }; export type MyOtherType = { __typename?: 'MyOtherType'; bar: Scalars['String']['output']; }; export type ChildUnion = Child | MyOtherType; export type Query = { __typename?: 'Query'; something: MyType; }; export type Subscription = { __typename?: 'Subscription'; somethingChanged?: Maybe; }; export type Node = { id: Scalars['ID']['output']; }; export type SomeNode = Node & { __typename?: 'SomeNode'; id: Scalars['ID']['output']; }; export type AnotherNode = { id: Scalars['ID']['output']; }; export type WithChild = { unionChild?: Maybe; node?: Maybe; }; export type WithChildren = { unionChildren: Array; nodes: Array; }; export type AnotherNodeWithChild = AnotherNode & WithChild & { __typename?: 'AnotherNodeWithChild'; id: Scalars['ID']['output']; unionChild?: Maybe; interfaceChild?: Maybe; }; export type AnotherNodeWithAll = AnotherNode & WithChild & WithChildren & { __typename?: 'AnotherNodeWithAll'; id: Scalars['ID']['output']; unionChild?: Maybe; unionChildren: Array; interfaceChild?: Maybe; interfaceChildren: Array; }; export type MyUnion = MyType | MyOtherType; export type WithIndex = TObject & Record; export type ResolversObject = WithIndex; export type ResolverTypeWrapper = Promise | T; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver, TContext = Record, TArgs = Record> = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info?: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info?: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info?: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver, TContext = Record, TArgs = Record> = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info?: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = (obj: T, context: TContext, info?: GraphQLResolveInfo) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn, TParent = Record, TContext = Record, TArgs = Record> = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info?: GraphQLResolveInfo ) => TResult | Promise; /** Mapping of union types */ export type ResolversUnionTypes<_RefType extends Record> = ResolversObject<{ ChildUnion: | ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ) ; MyUnion: | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']> } ) | ( MyOtherType ) ; }>; /** Mapping of interface types */ export type ResolversInterfaceTypes<_RefType extends Record> = ResolversObject<{ Node: ( SomeNode ); AnotherNode: | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ) ; WithChild: | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ) ; WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }>; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = ResolversObject<{ MyType: ResolverTypeWrapper & { unionChild?: Maybe }>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }>; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = ResolversObject<{ MyType: Omit & { unionChild?: Maybe }; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: Omit & { unionChild?: Maybe, interfaceChild?: Maybe }; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }>; export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; export type MyDirectiveDirectiveResolver = DirectiveResolverFn; export type AuthenticatedDirectiveArgs = { }; export type AuthenticatedDirectiveResolver = DirectiveResolverFn; export type MyTypeResolvers = ResolversObject<{ foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type ChildResolvers = ResolversObject<{ bar?: Resolver; parent?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type MyOtherTypeResolvers = ResolversObject<{ bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; export type ChildUnionResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'Child' | 'MyOtherType', ParentType, ContextType>; }>; export type QueryResolvers = ResolversObject<{ something?: Resolver; }>; export type SubscriptionResolvers = ResolversObject<{ somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }>; export type NodeResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }>; export type SomeNodeResolvers = ResolversObject<{ id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; export type AnotherNodeResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'AnotherNodeWithChild' | 'AnotherNodeWithAll', ParentType, ContextType>; }>; export type WithChildResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'AnotherNodeWithChild' | 'AnotherNodeWithAll', ParentType, ContextType>; }>; export type WithChildrenResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'AnotherNodeWithAll', ParentType, ContextType>; }>; export type AnotherNodeWithChildResolvers = ResolversObject<{ id?: Resolver; unionChild?: Resolver, ParentType, ContextType>; interfaceChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type AnotherNodeWithAllResolvers = ResolversObject<{ id?: Resolver; unionChild?: Resolver, ParentType, ContextType>; unionChildren?: Resolver, ParentType, ContextType>; interfaceChild?: Resolver, ParentType, ContextType>; interfaceChildren?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }>; export type MyUnionResolvers = ResolversObject<{ __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }>; export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; } export type Resolvers = ResolversObject<{ MyType?: MyTypeResolvers; Child?: ChildResolvers; MyOtherType?: MyOtherTypeResolvers; ChildUnion?: ChildUnionResolvers; Query?: QueryResolvers; Subscription?: SubscriptionResolvers; Node?: NodeResolvers; SomeNode?: SomeNodeResolvers; AnotherNode?: AnotherNodeResolvers; WithChild?: WithChildResolvers; WithChildren?: WithChildrenResolvers; AnotherNodeWithChild?: AnotherNodeWithChildResolvers; AnotherNodeWithAll?: AnotherNodeWithAllResolvers; MyUnion?: MyUnionResolvers; MyScalar?: GraphQLScalarType; }>; export type DirectiveResolvers = ResolversObject<{ myDirective?: MyDirectiveDirectiveResolver; authenticated?: AuthenticatedDirectiveResolver; }>; " `; ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.config.avoidOptionals.spec.ts ================================================ import { resolversTestingSchema, resolversTestingValidate } from '@graphql-codegen/testing'; import { buildSchema } from 'graphql'; import type { Types } from '@graphql-codegen/plugin-helpers'; import { plugin } from '../src/index.js'; describe('TypeScript Resolvers Plugin - config.avoidOptionals', () => { it('should generate basic type resolvers if config.avoidOptionals = true', async () => { const result = (await plugin( resolversTestingSchema, [], { avoidOptionals: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; };`); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content) .toBeSimilarStringTo(`export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; }`); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo: Resolver; otherType: Resolver, ParentType, ContextType>; withArgs: Resolver, ParentType, ContextType, RequireFields>; unionChild: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('#7005 - avoidOptionals should preserve optional resolvers', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { users(filter: UserFilterInput = {}): [User!]! ping: String! } input UserFilterInput { status: String = "ACTIVE" } type User { id: ID! } `); const output = (await plugin( testSchema, [], { avoidOptionals: { defaultValue: true, field: true, inputValue: true, object: true, resolvers: false, }, } as any, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(output.content).toBeSimilarStringTo(` export type QueryResolvers = { users?: Resolver, ParentType, ContextType, RequireFields>; ping?: Resolver; }; `); }); it('#9438 - avoidOptionals should not wrap arguments with partial', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { users(filter: UserFilterInput): [User!]! } input UserFilterInput { status: String = "ACTIVE" } type User { id: ID! } `); const output = (await plugin( testSchema, [], { avoidOptionals: { defaultValue: true, field: true, inputValue: true, object: true, resolvers: false, }, } as any, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(output.content).toBeSimilarStringTo(` export type QueryResolvers = { users?: Resolver, ParentType, ContextType, QueryUsersArgs>; }; `); }); it('should keep non-optional arguments non-optional - issue #2323', async () => { const testSchema = buildSchema(/* GraphQL */ ` enum OrderBy { name id } input Filter { contain: String } type Node { id: ID! name: String! } type Connection { nodes: [Node] } type Query { list(after: String, orderBy: OrderBy = name, filter: Filter!): Connection! } `); const output = (await plugin( testSchema, [], { avoidOptionals: false, maybeValue: 'T | undefined', } as any, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; // filter should be non-optional expect(output.content).toBeSimilarStringTo(` export type QueryResolvers = { list?: Resolver>; }; `); }); }); describe('TypeScript Resolvers Plugin - config.avoidOptionals - query, mutation, subscription', () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { user: User currentAppVersion: String! } type Mutation { updateUser: User! flagUser: User! } type Subscription { userUpdates: User! appVersionUpdates: String! } type User { id: ID! } `); it('avoids non-optional Query fields if config.avoidOptionals.query = true', async () => { const output = (await plugin( testSchema, [], { avoidOptionals: { query: true } }, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(output.content).toBeSimilarStringTo(` export type QueryResolvers = { user: Resolver, ParentType, ContextType>; currentAppVersion: Resolver; }; `); expect(output.content).toBeSimilarStringTo(` export type MutationResolvers = { updateUser?: Resolver; flagUser?: Resolver; }; `); expect(output.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { userUpdates?: SubscriptionResolver; appVersionUpdates?: SubscriptionResolver; }; `); }); it('avoids non-optional Mutation fields if config.avoidOptionals.mutation = true', async () => { const output = (await plugin( testSchema, [], { avoidOptionals: { mutation: true } }, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(output.content).toBeSimilarStringTo(` export type QueryResolvers = { user?: Resolver, ParentType, ContextType>; currentAppVersion?: Resolver; }; `); expect(output.content).toBeSimilarStringTo(` export type MutationResolvers = { updateUser: Resolver; flagUser: Resolver; }; `); expect(output.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { userUpdates?: SubscriptionResolver; appVersionUpdates?: SubscriptionResolver; }; `); }); it('avoids non-optional Subscription fields if config.avoidOptionals.subscription = true', async () => { const output = (await plugin( testSchema, [], { avoidOptionals: { subscription: true } }, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(output.content).toBeSimilarStringTo(` export type QueryResolvers = { user?: Resolver, ParentType, ContextType>; currentAppVersion?: Resolver; }; `); expect(output.content).toBeSimilarStringTo(` export type MutationResolvers = { updateUser?: Resolver; flagUser?: Resolver; }; `); expect(output.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { userUpdates: SubscriptionResolver; appVersionUpdates: SubscriptionResolver; }; `); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.config.customDirectives.spec.ts ================================================ import { buildSchema } from 'graphql'; import '@graphql-codegen/testing'; import { plugin } from '../src/index.js'; describe('customDirectives.sematicNonNull', () => { it('allowSemanticNonNull - should build strict type if annotated by @semanticNonNull directive', async () => { const testingSchema = buildSchema(/* GraphQL */ ` directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION type TestingType { field: String @semanticNonNull fieldLevel0: String @semanticNonNull(levels: [0]) fieldLevel1: String @semanticNonNull(levels: [1]) fieldBothLevels: String @semanticNonNull(levels: [0, 1]) list: [String] @semanticNonNull listLevel0: [String] @semanticNonNull(levels: [0]) listLevel1: [String] @semanticNonNull(levels: [1]) listBothLevels: [String] @semanticNonNull(levels: [0, 1]) nonNullableList: [String]! @semanticNonNull nonNullableListLevel0: [String]! @semanticNonNull(levels: [0]) nonNullableListLevel1: [String]! @semanticNonNull(levels: [1]) nonNullableListBothLevels: [String]! @semanticNonNull(levels: [0, 1]) listWithNonNullableItem: [String!] @semanticNonNull listWithNonNullableItemLevel0: [String!] @semanticNonNull(levels: [0]) listWithNonNullableItemLevel1: [String!] @semanticNonNull(levels: [1]) listWithNonNullableItemBothLevels: [String!] @semanticNonNull(levels: [0, 1]) nonNullableListWithNonNullableItem: [String!]! @semanticNonNull nonNullableListWithNonNullableItemLevel0: [String!]! @semanticNonNull(levels: [0]) nonNullableListWithNonNullableItemLevel1: [String!]! @semanticNonNull(levels: [1]) nonNullableListWithNonNullableItemBothLevels: [String!]! @semanticNonNull(levels: [0, 1]) } `); const result = await plugin( testingSchema, [], { customDirectives: { semanticNonNull: true }, }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type TestingTypeResolvers = { field?: Resolver; fieldLevel0?: Resolver; fieldLevel1?: Resolver, ParentType, ContextType>; fieldBothLevels?: Resolver; list?: Resolver>, ParentType, ContextType>; listLevel0?: Resolver>, ParentType, ContextType>; listLevel1?: Resolver>, ParentType, ContextType>; listBothLevels?: Resolver, ParentType, ContextType>; nonNullableList?: Resolver>, ParentType, ContextType>; nonNullableListLevel0?: Resolver>, ParentType, ContextType>; nonNullableListLevel1?: Resolver, ParentType, ContextType>; nonNullableListBothLevels?: Resolver, ParentType, ContextType>; listWithNonNullableItem?: Resolver, ParentType, ContextType>; listWithNonNullableItemLevel0?: Resolver, ParentType, ContextType>; listWithNonNullableItemLevel1?: Resolver>, ParentType, ContextType>; listWithNonNullableItemBothLevels?: Resolver, ParentType, ContextType>; nonNullableListWithNonNullableItem?: Resolver, ParentType, ContextType>; nonNullableListWithNonNullableItemLevel0?: Resolver, ParentType, ContextType>; nonNullableListWithNonNullableItemLevel1?: Resolver, ParentType, ContextType>; nonNullableListWithNonNullableItemBothLevels?: Resolver, ParentType, ContextType>; }; `); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.config.resolversNonOptionalTypename.spec.ts ================================================ import { resolversTestingSchema } from '@graphql-codegen/testing'; import { plugin } from '../src/index.js'; describe('TypeScript Resolvers Plugin - config.resolversNonOptionalTypename', () => { it('excludes types', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { unionMember: true, interfaceImplementingType: true, excludeTypes: ['ChildUnion', 'AnotherNode', 'Node'], }, }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ); MyUnion: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']> } & { __typename: 'MyType' } ) | ( MyOtherType & { __typename: 'MyOtherType' } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } & { __typename: 'AnotherNodeWithChild' } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); }; `); }); it('adds non-optional typenames to implemented types', async () => { const result = await plugin(resolversTestingSchema, [], { resolversNonOptionalTypename: true }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } & { __typename: 'Child' } ) | ( MyOtherType & { __typename: 'MyOtherType' } ); MyUnion: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']> } & { __typename: 'MyType' } ) | ( MyOtherType & { __typename: 'MyOtherType' } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode & { __typename: 'SomeNode' } ); AnotherNode: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } & { __typename: 'AnotherNodeWithChild' } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); WithChild: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } & { __typename: 'AnotherNodeWithChild' } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); }; `); }); it('adds non-optional typenames to ResolversUnionTypes', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { unionMember: true } }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } & { __typename: 'Child' } ) | ( MyOtherType & { __typename: 'MyOtherType' } ); MyUnion: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']> } & { __typename: 'MyType' } ) | ( MyOtherType & { __typename: 'MyOtherType' } ); }; `); }); it('adds non-optional typenames to ResolversUnionTypes for mappers with no placeholder', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { unionMember: true }, mappers: { Child: 'ChildMapper', MyType: 'MyTypeMapper' }, }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( ChildMapper & { __typename: 'Child' } ) | ( MyOtherType & { __typename: 'MyOtherType' } ); MyUnion: ( MyTypeMapper & { __typename: 'MyType' } ) | ( MyOtherType & { __typename: 'MyOtherType' } ); }; `); }); it('adds non-optional typenames to ResolversUnionTypes for mappers with placeholder', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { unionMember: true }, mappers: { Child: 'Wrapper<{T}>', MyType: 'MyWrapper<{T}>' }, }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Wrapper & { parent?: Maybe<_RefType['MyType']> }> & { __typename: 'Child' } ) | ( MyOtherType & { __typename: 'MyOtherType' } ); MyUnion: ( MyWrapper & { unionChild?: Maybe<_RefType['ChildUnion']> }> & { __typename: 'MyType' } ) | ( MyOtherType & { __typename: 'MyOtherType' } ); }; `); }); it('adds non-optional typenames to ResolversUnionTypes for default mappers with placeholder', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { unionMember: true }, defaultMapper: 'Partial<{T}>', }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Partial & { parent?: Maybe<_RefType['MyType']> }> & { __typename: 'Child' } ) | ( Partial & { __typename: 'MyOtherType' } ); MyUnion: ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']> }> & { __typename: 'MyType' } ) | ( Partial & { __typename: 'MyOtherType' } ); }; `); }); it('does not create ResolversUnionTypes for default mappers with no placeholder', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { unionMember: true }, defaultMapper: '{}', }, { outputFile: '' } ); expect(result.content).not.toBeSimilarStringTo('export type ResolversUnionTypes'); expect(result.content).not.toBeSimilarStringTo('export type ResolversUnionParentTypes'); }); it('adds non-optional typenames to ResolversInterfaceTypes', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { interfaceImplementingType: true } }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode & { __typename: 'SomeNode' } ); AnotherNode: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } & { __typename: 'AnotherNodeWithChild' } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); WithChild: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } & { __typename: 'AnotherNodeWithChild' } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); }; `); }); it('adds non-optional typenames to ResolversInterfaceTypes for mappers with no placeholder', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { interfaceImplementingType: true }, mappers: { AnotherNodeWithChild: 'AnotherNodeWithChildMapper' }, }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode & { __typename: 'SomeNode' } ); AnotherNode: ( AnotherNodeWithChildMapper & { __typename: 'AnotherNodeWithChild' } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); WithChild: ( AnotherNodeWithChildMapper & { __typename: 'AnotherNodeWithChild' } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); }; `); }); it('adds non-optional typenames to ResolversInterfaceTypes for mappers with placeholder', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { interfaceImplementingType: true }, mappers: { AnotherNodeWithChild: 'Wrapper<{T}>' }, }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode & { __typename: 'SomeNode' } ); AnotherNode: ( Wrapper & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> & { __typename: 'AnotherNodeWithChild' } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); WithChild: ( Wrapper & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> & { __typename: 'AnotherNodeWithChild' } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } & { __typename: 'AnotherNodeWithAll' } ); }; `); }); it('adds non-optional typenames to ResolversInterfaceTypes for default mappers with placeholder', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { interfaceImplementingType: true }, defaultMapper: 'Partial<{T}>', }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( Partial & { __typename: 'SomeNode' } ); AnotherNode: ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> & { __typename: 'AnotherNodeWithChild' } ) | ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> & { __typename: 'AnotherNodeWithAll' } ); WithChild: ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> & { __typename: 'AnotherNodeWithChild' } ) | ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> & { __typename: 'AnotherNodeWithAll' } ); WithChildren: ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> & { __typename: 'AnotherNodeWithAll' } ); }; `); }); it('does not create ResolversInterfaceTypes for default mappers with no placeholder', async () => { const result = await plugin( resolversTestingSchema, [], { resolversNonOptionalTypename: { interfaceImplementingType: true }, defaultMapper: 'unknown', }, { outputFile: '' } ); expect(result.content).not.toBeSimilarStringTo('export type ResolversInterfaceTypes'); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.federation.interface.spec.ts ================================================ import '@graphql-codegen/testing'; import { generate } from './utils'; describe('TypeScript Resolvers Plugin + Apollo Federation - Interface', () => { it('generates __resolveReference for Interfaces with @key', async () => { const federatedSchema = /* GraphQL */ ` type Query { me: Person } interface Person @key(fields: "id") { id: ID! name: PersonName! } type User implements Person @key(fields: "id") { id: ID! name: PersonName! } type Admin implements Person @key(fields: "id") { id: ID! name: PersonName! canImpersonate: Boolean! } type PersonName { first: String! last: String! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toMatchInlineSnapshot(` "import { GraphQLResolveInfo } from 'graphql'; export type ResolverTypeWrapper = Promise | T; export type ReferenceResolver = ( reference: TReference, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; type ScalarCheck = S extends true ? T : NullableCheck; type NullableCheck = Maybe extends T ? Maybe, S>> : ListCheck; type ListCheck = T extends (infer U)[] ? NullableCheck[] : GraphQLRecursivePick; export type GraphQLRecursivePick = { [K in keyof T & keyof S]: ScalarCheck }; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver, TContext = Record, TArgs = Record> = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver, TContext = Record, TArgs = Record> = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = (obj: T, context: TContext, info: GraphQLResolveInfo) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn, TParent = Record, TContext = Record, TArgs = Record> = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping of federation types */ export type FederationTypes = { Person: Person; User: User; Admin: Admin; }; /** Mapping of federation reference types */ export type FederationReferenceTypes = { Person: ( { __typename: 'Person' } & GraphQLRecursivePick ); User: ( { __typename: 'User' } & GraphQLRecursivePick ); Admin: ( { __typename: 'Admin' } & GraphQLRecursivePick ); }; /** Mapping of interface types */ export type ResolversInterfaceTypes<_RefType extends Record> = { Person: | ( User ) | ( Admin ) ; }; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Query: ResolverTypeWrapper>; Person: ResolverTypeWrapper['Person']>; ID: ResolverTypeWrapper; User: ResolverTypeWrapper; Admin: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; PersonName: ResolverTypeWrapper; String: ResolverTypeWrapper; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Query: Record; Person: ResolversInterfaceTypes['Person']; ID: Scalars['ID']['output']; User: User | FederationReferenceTypes['User']; Admin: Admin | FederationReferenceTypes['Admin']; Boolean: Scalars['Boolean']['output']; PersonName: PersonName; String: Scalars['String']['output']; }; export type QueryResolvers = { me?: Resolver, ParentType, ContextType>; }; export type PersonResolvers = { __resolveType: TypeResolveFn<'User' | 'Admin', ParentType, ContextType>; __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; }; export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; name?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type AdminResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; name?: Resolver; canImpersonate?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type PersonNameResolvers = { first?: Resolver; last?: Resolver; }; export type Resolvers = { Query?: QueryResolvers; Person?: PersonResolvers; User?: UserResolvers; Admin?: AdminResolvers; PersonName?: PersonNameResolvers; }; " `); }); it('generates normal Interface fields with addInterfaceFieldResolverTypes:true', async () => { const federatedSchema = /* GraphQL */ ` type Query { me: Person } interface Person @key(fields: "id") { id: ID! name: PersonName! } type User implements Person @key(fields: "id") { id: ID! name: PersonName! } type Admin implements Person @key(fields: "id") { id: ID! name: PersonName! canImpersonate: Boolean! } type PersonName { first: String! last: String! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, addInterfaceFieldResolverTypes: true, }, }); expect(content).toBeSimilarStringTo(` export type PersonResolvers = { __resolveType: TypeResolveFn<'User' | 'Admin', ParentType, ContextType>; __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; name?: Resolver; }; `); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.federation.mappers.spec.ts ================================================ import '@graphql-codegen/testing'; import { generate } from './utils'; describe('TypeScript Resolvers Plugin + Apollo Federation - mappers', () => { it('generates FederationTypes and use it for reference type', async () => { const federatedSchema = /* GraphQL */ ` type Query { me: User } type User @key(fields: "id") { id: ID! name: String } type UserProfile { id: ID! user: User! } type Account @key(fields: "id") { id: ID! name: String! @external displayName: String! @requires(fields: "name") } `; const content = await generate({ schema: federatedSchema, config: { federation: true, mappers: { User: './mappers#UserMapper', Account: './mappers#AccountMapper', }, }, }); // User should have it expect(content).toMatchInlineSnapshot(` "import { GraphQLResolveInfo } from 'graphql'; import { UserMapper, AccountMapper } from './mappers'; export type Omit = Pick>; export type ResolverTypeWrapper = Promise | T; export type ReferenceResolver = ( reference: TReference, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; type ScalarCheck = S extends true ? T : NullableCheck; type NullableCheck = Maybe extends T ? Maybe, S>> : ListCheck; type ListCheck = T extends (infer U)[] ? NullableCheck[] : GraphQLRecursivePick; export type GraphQLRecursivePick = { [K in keyof T & keyof S]: ScalarCheck }; export type ResolverWithResolve = { resolve: ResolverFn; }; export type Resolver, TContext = Record, TArgs = Record> = ResolverFn | ResolverWithResolve; export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult; export type SubscriptionSubscribeFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => AsyncIterable | Promise>; export type SubscriptionResolveFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; export interface SubscriptionSubscriberObject { subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; resolve?: SubscriptionResolveFn; } export interface SubscriptionResolverObject { subscribe: SubscriptionSubscribeFn; resolve: SubscriptionResolveFn; } export type SubscriptionObject = | SubscriptionSubscriberObject | SubscriptionResolverObject; export type SubscriptionResolver, TContext = Record, TArgs = Record> = | ((...args: any[]) => SubscriptionObject) | SubscriptionObject; export type TypeResolveFn, TContext = Record> = ( parent: TParent, context: TContext, info: GraphQLResolveInfo ) => Maybe | Promise>; export type IsTypeOfResolverFn, TContext = Record> = (obj: T, context: TContext, info: GraphQLResolveInfo) => boolean | Promise; export type NextResolverFn = () => Promise; export type DirectiveResolverFn, TParent = Record, TContext = Record, TArgs = Record> = ( next: NextResolverFn, parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => TResult | Promise; /** Mapping of federation types */ export type FederationTypes = { User: User; Account: Account; }; /** Mapping of federation reference types */ export type FederationReferenceTypes = { User: ( { __typename: 'User' } & GraphQLRecursivePick ); Account: ( { __typename: 'Account' } & GraphQLRecursivePick & ( Record | GraphQLRecursivePick ) ); }; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { Query: ResolverTypeWrapper>; User: ResolverTypeWrapper; ID: ResolverTypeWrapper; String: ResolverTypeWrapper; UserProfile: ResolverTypeWrapper & { user: ResolversTypes['User'] }>; Account: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Query: Record; User: UserMapper; ID: Scalars['ID']['output']; String: Scalars['String']['output']; UserProfile: Omit & { user: ResolversParentTypes['User'] }; Account: AccountMapper; Boolean: Scalars['Boolean']['output']; }; export type QueryResolvers = { me?: Resolver, ParentType, ContextType>; }; export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; name?: Resolver, ParentType, ContextType>; }; export type UserProfileResolvers = { id?: Resolver; user?: Resolver; }; export type AccountResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; displayName?: Resolver; }; export type Resolvers = { Query?: QueryResolvers; User?: UserResolvers; UserProfile?: UserProfileResolvers; Account?: AccountResolvers; }; " `); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.federation.spec.ts ================================================ import '@graphql-codegen/testing'; import { codegen } from '@graphql-codegen/core'; import { buildSchema, parse } from 'graphql'; import { TypeScriptResolversPluginConfig } from '../src/config.js'; import { plugin } from '../src/index.js'; function generate({ schema, config }: { schema: string; config: TypeScriptResolversPluginConfig }) { return codegen({ filename: 'graphql.ts', schema: parse(schema), documents: [], plugins: [ { 'typescript-resolvers': {}, }, ], config, pluginMap: { 'typescript-resolvers': { plugin, }, }, }); } describe('TypeScript Resolvers Plugin + Apollo Federation', () => { it('generates __resolveReference for object types with resolvable @key', async () => { const federatedSchema = /* GraphQL */ ` type Query { allUsers: [User] } type User @key(fields: "id") { id: ID! name: String username: String } type Book { id: ID! } type SingleResolvable @key(fields: "id", resolvable: true) { id: ID! } type SingleNonResolvable @key(fields: "id", resolvable: false) { id: ID! } type AtLeastOneResolvable @key(fields: "id", resolvable: false) @key(fields: "id2", resolvable: true) @key(fields: "id3", resolvable: false) { id: ID! id2: ID! id3: ID! } type MixedResolvable @key(fields: "id") @key(fields: "id2", resolvable: true) @key(fields: "id3", resolvable: false) { id: ID! id2: ID! id3: ID! } type MultipleNonResolvable @key(fields: "id", resolvable: false) @key(fields: "id2", resolvable: false) @key(fields: "id3", resolvable: false) { id: ID! id2: ID! id3: ID! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type FederationTypes = { User: User; SingleResolvable: SingleResolvable; AtLeastOneResolvable: AtLeastOneResolvable; MixedResolvable: MixedResolvable; }; `); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { User: ( { __typename: 'User' } & GraphQLRecursivePick ); SingleResolvable: ( { __typename: 'SingleResolvable' } & GraphQLRecursivePick ); AtLeastOneResolvable: ( { __typename: 'AtLeastOneResolvable' } & GraphQLRecursivePick ); MixedResolvable: ( { __typename: 'MixedResolvable' } & ( GraphQLRecursivePick | GraphQLRecursivePick ) ); }; `); expect(content).toBeSimilarStringTo(` export type ResolversParentTypes = { Query: Record; User: User | FederationReferenceTypes['User']; ID: Scalars['ID']['output']; String: Scalars['String']['output']; Book: Book; SingleResolvable: SingleResolvable | FederationReferenceTypes['SingleResolvable']; SingleNonResolvable: SingleNonResolvable; AtLeastOneResolvable: AtLeastOneResolvable | FederationReferenceTypes['AtLeastOneResolvable']; MixedResolvable: MixedResolvable | FederationReferenceTypes['MixedResolvable']; MultipleNonResolvable: MultipleNonResolvable; Boolean: Scalars['Boolean']['output']; }; `); // User should have __resolveReference because it has resolvable @key (by default) expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; name?: Resolver, ParentType, ContextType>; username?: Resolver, ParentType, ContextType>; }; `); // SingleResolvable has __resolveReference because it has resolvable: true expect(content).toBeSimilarStringTo(` export type SingleResolvableResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; }; `); // SingleNonResolvable does NOT have __resolveReference because it has resolvable: false expect(content).toBeSimilarStringTo(` export type SingleNonResolvableResolvers = { id?: Resolver; }; `); // AtLeastOneResolvable has __resolveReference because it at least one resolvable expect(content).toBeSimilarStringTo(` export type AtLeastOneResolvableResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; id2?: Resolver; id3?: Resolver; }; `); // MixedResolvable has __resolveReference and references for resolvable keys expect(content).toBeSimilarStringTo(` export type MixedResolvableResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; id2?: Resolver; id3?: Resolver; }; `); // MultipleNonResolvableResolvers does NOT have __resolveReference because all keys are non-resolvable expect(content).toBeSimilarStringTo(` export type MultipleNonResolvableResolvers = { id?: Resolver; id2?: Resolver; id3?: Resolver; }; `); // Book does NOT have __resolveReference because it doesn't have @key expect(content).toBeSimilarStringTo(` export type BookResolvers = { id?: Resolver; }; `); }); it('should support extend keyword', async () => { const federatedSchema = /* GraphQL */ ` extend type Query { allUsers: [User] } extend type User @key(fields: "id") { id: ID! name: String username: String } type Book { id: ID! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { User: ( { __typename: 'User' } & GraphQLRecursivePick ); }; `); // User should have it expect(content).toBeSimilarStringTo(` __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; `); // Foo shouldn't because it doesn't have @key expect(content).not.toBeSimilarStringTo(` __resolveReference?: ReferenceResolver, FederationReferenceType, ContextType>; `); }); it('should include nested fields from @provides directive', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } type Book { author: User @provides(fields: "name { first last}") } type Name @key(fields: "id") { id: ID! @external first: String! middle: String @external last: String! } type User @key(fields: "id") { id: ID! name: Name @external username: String @external } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { Name: ( { __typename: 'Name' } & GraphQLRecursivePick ); User: ( { __typename: 'User' } & GraphQLRecursivePick ); }; `); expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; name?: Resolver, ParentType, ContextType>; }; `); expect(content).toBeSimilarStringTo(` export type NameResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; first?: Resolver; last?: Resolver; }; `); }); it('should include fields from @requires directive', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } type Account @key(fields: "id") { id: ID! key: String! } type User @key(fields: "id") { id: ID! a: String @external aRequires: String @requires(fields: "a") b: String! @external bRequires: String! @requires(fields: "b") c: String! @external cRequires: String! @requires(fields: "c") d: String! @external dRequires: String! @requires(fields: "d") } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type ResolversParentTypes = { Query: Record; Account: Account | FederationReferenceTypes['Account']; ID: Scalars['ID']['output']; String: Scalars['String']['output']; User: User | FederationReferenceTypes['User']; Boolean: Scalars['Boolean']['output']; }; `); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { Account: ( { __typename: 'Account' } & GraphQLRecursivePick ); User: ( { __typename: 'User' } & GraphQLRecursivePick & ( Record | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick ) ); }; `); // User should have it expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; aRequires?: Resolver, ParentType, ContextType>; bRequires?: Resolver; cRequires?: Resolver; dRequires?: Resolver; }; `); }); it('should handle nested fields from @requires directive', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } extend type User @key(fields: "id") { id: ID! @external favouriteColor: String! @external favouriteColorHex: String! @requires(fields: "favouriteColor") name: String @external age: Int! @external address: Address! @external username: String @requires(fields: "name age address { street }") } extend type Address { street: String! @external zip: Int! @external } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { User: ( { __typename: 'User' } & GraphQLRecursivePick & ( Record | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick ) ); }; `); expect(content).toBeSimilarStringTo(` export type ResolversParentTypes = { Query: Record; User: User | FederationReferenceTypes['User']; ID: Scalars['ID']['output']; String: Scalars['String']['output']; Int: Scalars['Int']['output']; Address: Address; Boolean: Scalars['Boolean']['output']; }; `); expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; favouriteColorHex?: Resolver; username?: Resolver, ParentType, ContextType>; }; `); }); it('should handle nested fields from @key directive', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } type User @key(fields: "name { first last }") { name: Name! @external username: String } type Name { first: String! @external last: String! @external } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { User: ( { __typename: 'User' } & GraphQLRecursivePick ); }; `); expect(content).toBeSimilarStringTo(` export type ResolversParentTypes = { Query: Record; User: User | FederationReferenceTypes['User']; String: Scalars['String']['output']; Name: Name; Boolean: Scalars['Boolean']['output']; }; `); expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; username?: Resolver, ParentType, ContextType>; }; `); }); it('handles a mix of @key and @requires directives', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } type User @key(fields: "id") @key(fields: "uuid") @key(fields: "legacyId { oldId1 oldId2 }") { id: ID! uuid: ID! legacyId: LegacyId! @external name: String! @external username: String! @requires(fields: "id name") usernameLegacy: String! @requires(fields: "legacyId { oldId1 } name") } type LegacyId { oldId1: ID! @external oldId2: ID! @external } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { User: ( { __typename: 'User' } & ( GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick ) & ( Record | GraphQLRecursivePick | GraphQLRecursivePick | GraphQLRecursivePick ) ); }; `); expect(content).toBeSimilarStringTo(` export type ResolversParentTypes = { Query: Record; User: User | FederationReferenceTypes['User']; ID: Scalars['ID']['output']; String: Scalars['String']['output']; LegacyId: LegacyId; Boolean: Scalars['Boolean']['output']; }; `); expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; uuid?: Resolver; username?: Resolver; usernameLegacy?: Resolver; }; `); }); it('should not apply key/requires fields restriction for base federated types', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } type User @key(fields: "name { first last }") { name: Name! username: String } type Name { first: String! last: String! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { User: ( { __typename: 'User' } & GraphQLRecursivePick ); }; `); expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; name?: Resolver; username?: Resolver, ParentType, ContextType>; }; `); }); it('should skip to generate resolvers of fields or object types with @external directive', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } type Book { author: User @provides(fields: "name") editor: User @provides(fields: "company { taxCode }") } type User @key(fields: "id") { id: ID! name: String @external username: String @external address: Address dateOfBirth: DateOfBirth placeOfBirth: PlaceOfBirth company: Company } type Address { street: String! @external zip: String! } type DateOfBirth { day: Int! @external month: Int! @external year: Int! @external } type PlaceOfBirth @external { city: String! country: String! } type Company @external { name: String! taxCode: String! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { User: ( { __typename: 'User' } & GraphQLRecursivePick ); }; `); // `UserResolvers` should not have `username` resolver because it is marked with `@external` // `UserResolvers` should have `name` resolver because whilst it is marked with `@external`, it is provided by `Book.author` expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; id?: Resolver; name?: Resolver, ParentType, ContextType>; address?: Resolver, ParentType, ContextType>; dateOfBirth?: Resolver, ParentType, ContextType>; placeOfBirth?: Resolver, ParentType, ContextType>; company?: Resolver, ParentType, ContextType>; }; `); // `AddressResolvers` should only have fields not marked with @external expect(content).toBeSimilarStringTo(` export type AddressResolvers = { zip?: Resolver; }; `); // `DateOfBirthResolvers` should not be generated because every field is marked with @external expect(content).not.toBeSimilarStringTo('export type DateOfBirthResolvers'); // `PlaceOfBirthResolvers` should not be generated because the type is marked with @external, even if `User.placeOfBirth` is not marked with @external expect(content).not.toBeSimilarStringTo('export type PlaceOfBirthResolvers'); // FIXME: `CompanyResolvers` should only have taxCode resolver because it is part of the `@provides` directive in `Book.editor`, even if the whole `Company` type is marked with @external // expect(content).toBeSimilarStringTo(` // export type CompanyResolvers = { // taxCode?: Resolver; // }; // `); }); it('should not include _FieldSet scalar', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } type User @key(fields: "id") { id: ID! name: String username: String } type Book { id: ID! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).not.toMatch(`_FieldSet`); }); it('should not include federation directives', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } type User @key(fields: "id") { id: ID! name: String username: String } type Book { id: ID! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).not.toMatch('ExternalDirectiveResolver'); expect(content).not.toMatch('RequiresDirectiveResolver'); expect(content).not.toMatch('ProvidesDirectiveResolver'); expect(content).not.toMatch('KeyDirectiveResolver'); }); it('should not add directive definitions and scalars if they are already there', async () => { const federatedSchema = /* GraphQL */ ` scalar _FieldSet directive @key(fields: _FieldSet!) on OBJECT | INTERFACE type Query { allUsers: [User] } type User @key(fields: "id") { id: ID! name: String username: String } type Book { id: ID! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).not.toMatch(`_FieldSet`); expect(content).not.toMatch('ExternalDirectiveResolver'); expect(content).not.toMatch('RequiresDirectiveResolver'); expect(content).not.toMatch('ProvidesDirectiveResolver'); expect(content).not.toMatch('KeyDirectiveResolver'); }); it('should allow for duplicated directives', async () => { const federatedSchema = /* GraphQL */ ` type Query { allUsers: [User] } extend type User @key(fields: "id") @key(fields: "name") { id: ID! @external name: String username: String } type Book { id: ID! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); expect(content).toBeSimilarStringTo(` export type FederationReferenceTypes = { User: ( { __typename: 'User' } & ( GraphQLRecursivePick | GraphQLRecursivePick ) ); }; `); // User should have it expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver | FederationReferenceType, FederationReferenceType, ContextType>; name?: Resolver, ParentType, ContextType>; username?: Resolver, ParentType, ContextType>; }; `); }); it.skip('should only extend an original type by a mapped type', async () => { const federatedSchema = /* GraphQL */ ` type Query { users: [User] } type User @key(fields: "id") { id: ID! name: String age: Int! username: String } `; const content = await generate({ schema: federatedSchema, config: { federation: true, mappers: { User: 'UserExtension', }, }, }); // User should have it expect(content).toBeSimilarStringTo(` export type UserResolvers = { __resolveReference?: ReferenceResolver, { __typename: 'User' } & Pick, ContextType>; id?: Resolver; username?: Resolver, UserExtension & ParentType & Pick, ContextType>; }; `); }); it('should not generate unused scalars', async () => { const federatedSchema = /* GraphQL */ ` type Query { user(id: ID!): User! } type User { id: ID! username: String! } `; const content = await generate({ schema: federatedSchema, config: { federation: true, }, }); // no GraphQLScalarTypeConfig expect(content).not.toContain('GraphQLScalarTypeConfig'); // no GraphQLScalarType expect(content).not.toContain('GraphQLScalarType'); }); describe('meta', () => { it('generates federation meta correctly', async () => { const federatedSchema = /* GraphQL */ ` scalar _FieldSet directive @key(fields: _FieldSet!, resolvable: Boolean) repeatable on OBJECT | INTERFACE type Query { user: UserPayload! allUsers: [User] } type User @key(fields: "id") { id: ID! name: String username: String } interface Node { id: ID! } type UserOk { id: ID! } type UserError { message: String! } union UserPayload = UserOk | UserError enum Country { FR US } type NotResolvable @key(fields: "id", resolvable: false) { id: ID! } type Resolvable @key(fields: "id", resolvable: true) { id: ID! } type MultipleResolvable @key(fields: "id") @key(fields: "id2", resolvable: true) @key(fields: "id3", resolvable: false) { id: ID! id2: ID! id3: ID! } type MultipleNonResolvable @key(fields: "id", resolvable: false) @key(fields: "id2", resolvable: false) @key(fields: "id3", resolvable: false) { id: ID! id2: ID! id3: ID! } `; const result = await plugin(buildSchema(federatedSchema), [], { federation: true }, { outputFile: '' }); expect(result.meta?.generatedResolverTypes).toMatchInlineSnapshot(` { "resolversMap": { "name": "Resolvers", }, "userDefined": { "MultipleNonResolvable": { "hasIsTypeOf": false, "name": "MultipleNonResolvableResolvers", }, "MultipleResolvable": { "federation": { "hasResolveReference": true, }, "hasIsTypeOf": false, "name": "MultipleResolvableResolvers", }, "Node": { "hasIsTypeOf": false, "name": "NodeResolvers", }, "NotResolvable": { "hasIsTypeOf": false, "name": "NotResolvableResolvers", }, "Query": { "hasIsTypeOf": false, "name": "QueryResolvers", }, "Resolvable": { "federation": { "hasResolveReference": true, }, "hasIsTypeOf": false, "name": "ResolvableResolvers", }, "User": { "federation": { "hasResolveReference": true, }, "hasIsTypeOf": false, "name": "UserResolvers", }, "UserError": { "hasIsTypeOf": true, "name": "UserErrorResolvers", }, "UserOk": { "hasIsTypeOf": true, "name": "UserOkResolvers", }, "UserPayload": { "hasIsTypeOf": false, "name": "UserPayloadResolvers", }, }, } `); }); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.interface.spec.ts ================================================ import { resolversTestingSchema } from '@graphql-codegen/testing'; import { buildSchema } from 'graphql'; import { plugin } from '../src/index.js'; describe('TypeScript Resolvers Plugin - Interfaces', () => { it('should generate ResolversInterfaceTypes', async () => { const content = await plugin(resolversTestingSchema, [], {}, { outputFile: 'graphql.ts' }); expect(content.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(content.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { unionChild?: Maybe }>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); expect(content.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: Omit & { unionChild?: Maybe }; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: Omit & { unionChild?: Maybe, interfaceChild?: Maybe }; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('should generate ResolversInterfaceTypes with transformed type names correctly', async () => { const content = await plugin( resolversTestingSchema, [], { typesPrefix: 'I_', typesSuffix: '_Types' }, { outputFile: 'graphql.ts' } ); expect(content.content).toBeSimilarStringTo(` export type I_ResolversInterfaceTypes_Types<_RefType extends Record> = { Node: ( I_SomeNode_Types ); AnotherNode: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(content.content).toBeSimilarStringTo(` export type I_ResolversTypes_Types = { MyType: ResolverTypeWrapper & { unionChild?: Maybe }>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); expect(content.content).toBeSimilarStringTo(` export type I_ResolversParentTypes_Types = { MyType: Omit & { unionChild?: Maybe }; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: I_MyOtherType_Types; ChildUnion: I_ResolversUnionTypes_Types['ChildUnion']; Query: Record; Subscription: Record; Node: I_ResolversInterfaceTypes_Types['Node']; ID: Scalars['ID']['output']; SomeNode: I_SomeNode_Types; AnotherNode: I_ResolversInterfaceTypes_Types['AnotherNode']; WithChild: I_ResolversInterfaceTypes_Types['WithChild']; WithChildren: I_ResolversInterfaceTypes_Types['WithChildren']; AnotherNodeWithChild: Omit & { unionChild?: Maybe, interfaceChild?: Maybe }; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: I_ResolversUnionTypes_Types['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('should NOT generate ResolversInterfaceTypes if there is no Interface', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { user(id: ID!): User } type User { id: ID! fullName: String! } `); const content = await plugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); expect(content.content).not.toBeSimilarStringTo(`export type ResolversInterfaceTypes`); }); it('Should generate valid types even when there are no implementers for an interface', async () => { const schemaWithNoImplementors = buildSchema(/* GraphQL */ ` interface Node { id: ID! } type Query { node: Node! } `); const result = await plugin(schemaWithNoImplementors, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn; }; `); }); it('generates overridden interface types for interfaces wrapped in object types', async () => { const schema = buildSchema(/* GraphQL */ ` interface I_Node { id: ID! } interface I_WithChild { node: I_Node! } interface I_WithChildren { nodes: [I_Node!]! } type T_NodeWithChild implements I_Node & I_WithChild { id: ID! node: I_Node } type T_NodeWithChildren implements I_Node & I_WithChildren { id: ID! nodes: [I_Node!]! } type T_Level1 { boolean: Boolean! string: String! i_node: I_Node! i_withChild: I_WithChild! i_withChildren: I_WithChildren! t_nodeWithChild: T_NodeWithChild! t_nodeWithChildren: T_NodeWithChildren! t_self: T_Level1! t_level2A: T_Level2A! t_level2B: T_Level2B! t_nodeWithNoAbstractFieldLevel1: T_WithNoAbstractFieldLevel1! } type T_Level2A { t_level1: T_Level1! t_level1Array: [T_Level1!]! } type T_Level2B { t_level3: T_Level3 } type T_Level3 { t_level4Array: [T_Level4!]! } type T_Level4 { node: I_Node! } type T_WithNoAbstractFieldLevel1 { id: ID! t_self: [T_WithNoAbstractFieldLevel1!]! t_withNoAbstractFieldLevel2: T_WithNoAbstractFieldLevel2! } type T_WithNoAbstractFieldLevel2 { id: ID! t_withNoAbstractFieldLevel3: T_WithNoAbstractFieldLevel3 } type T_WithNoAbstractFieldLevel3 { id: ID! } type Query { level1: T_Level1! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { I_Node: ( Omit & { node?: Maybe<_RefType['I_Node']> } ) | ( Omit & { nodes: Array<_RefType['I_Node']> } ); I_WithChild: ( Omit & { node?: Maybe<_RefType['I_Node']> } ); I_WithChildren: ( Omit & { nodes: Array<_RefType['I_Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { I_Node: ResolverTypeWrapper['I_Node']>; ID: ResolverTypeWrapper; I_WithChild: ResolverTypeWrapper['I_WithChild']>; I_WithChildren: ResolverTypeWrapper['I_WithChildren']>; T_NodeWithChild: ResolverTypeWrapper & { node?: Maybe }>; T_NodeWithChildren: ResolverTypeWrapper & { nodes: Array }>; T_Level1: ResolverTypeWrapper & { i_node: ResolversTypes['I_Node'], i_withChild: ResolversTypes['I_WithChild'], i_withChildren: ResolversTypes['I_WithChildren'], t_nodeWithChild: ResolversTypes['T_NodeWithChild'], t_nodeWithChildren: ResolversTypes['T_NodeWithChildren'], t_self: ResolversTypes['T_Level1'], t_level2A: ResolversTypes['T_Level2A'], t_level2B: ResolversTypes['T_Level2B'] }>; Boolean: ResolverTypeWrapper; String: ResolverTypeWrapper; T_Level2A: ResolverTypeWrapper & { t_level1: ResolversTypes['T_Level1'], t_level1Array: Array }>; T_Level2B: ResolverTypeWrapper & { t_level3?: Maybe }>; T_Level3: ResolverTypeWrapper & { t_level4Array: Array }>; T_Level4: ResolverTypeWrapper & { node: ResolversTypes['I_Node'] }>; T_WithNoAbstractFieldLevel1: ResolverTypeWrapper; T_WithNoAbstractFieldLevel2: ResolverTypeWrapper; T_WithNoAbstractFieldLevel3: ResolverTypeWrapper; Query: ResolverTypeWrapper>; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { I_Node: ResolversInterfaceTypes['I_Node']; ID: Scalars['ID']['output']; I_WithChild: ResolversInterfaceTypes['I_WithChild']; I_WithChildren: ResolversInterfaceTypes['I_WithChildren']; T_NodeWithChild: Omit & { node?: Maybe }; T_NodeWithChildren: Omit & { nodes: Array }; T_Level1: Omit & { i_node: ResolversParentTypes['I_Node'], i_withChild: ResolversParentTypes['I_WithChild'], i_withChildren: ResolversParentTypes['I_WithChildren'], t_nodeWithChild: ResolversParentTypes['T_NodeWithChild'], t_nodeWithChildren: ResolversParentTypes['T_NodeWithChildren'], t_self: ResolversParentTypes['T_Level1'], t_level2A: ResolversParentTypes['T_Level2A'], t_level2B: ResolversParentTypes['T_Level2B'] }; Boolean: Scalars['Boolean']['output']; String: Scalars['String']['output']; T_Level2A: Omit & { t_level1: ResolversParentTypes['T_Level1'], t_level1Array: Array }; T_Level2B: Omit & { t_level3?: Maybe }; T_Level3: Omit & { t_level4Array: Array }; T_Level4: Omit & { node: ResolversParentTypes['I_Node'] }; T_WithNoAbstractFieldLevel1: T_WithNoAbstractFieldLevel1; T_WithNoAbstractFieldLevel2: T_WithNoAbstractFieldLevel2; T_WithNoAbstractFieldLevel3: T_WithNoAbstractFieldLevel3; Query: Record; }; `); }); it('correctly handles circular reference - variant 1', async () => { const schema = buildSchema(/* GraphQL */ ` interface I_Node { id: ID! } type T_WithNode { node: I_Node! } type T_Type1 { id: ID! type2: T_Type2! withNode: T_WithNode! # abstract type is in T_Type1 } type T_Type2 { id: ID! type1: T_Type1! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { I_Node: never; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { I_Node: ResolverTypeWrapper['I_Node']>; ID: ResolverTypeWrapper; T_WithNode: ResolverTypeWrapper & { node: ResolversTypes['I_Node'] }>; T_Type1: ResolverTypeWrapper & { type2: ResolversTypes['T_Type2'], withNode: ResolversTypes['T_WithNode'] }>; T_Type2: ResolverTypeWrapper & { type1: ResolversTypes['T_Type1'] }>; Boolean: ResolverTypeWrapper; String: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { I_Node: ResolversInterfaceTypes['I_Node']; ID: Scalars['ID']['output']; T_WithNode: Omit & { node: ResolversParentTypes['I_Node'] }; T_Type1: Omit & { type2: ResolversParentTypes['T_Type2'], withNode: ResolversParentTypes['T_WithNode'] }; T_Type2: Omit & { type1: ResolversParentTypes['T_Type1'] }; Boolean: Scalars['Boolean']['output']; String: Scalars['String']['output']; }; `); }); it('correctly handles circular reference - variant 2', async () => { const schema = buildSchema(/* GraphQL */ ` interface I_Node { id: ID! } type T_WithNode { node: I_Node! } type T_Type1 { id: ID! type2: T_Type2! } type T_Type2 { id: ID! type1: T_Type1! withNode: T_WithNode! # abstract type is in T_Type2 } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { I_Node: never; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { I_Node: ResolverTypeWrapper['I_Node']>; ID: ResolverTypeWrapper; T_WithNode: ResolverTypeWrapper & { node: ResolversTypes['I_Node'] }>; T_Type1: ResolverTypeWrapper & { type2: ResolversTypes['T_Type2'] }>; T_Type2: ResolverTypeWrapper & { type1: ResolversTypes['T_Type1'], withNode: ResolversTypes['T_WithNode'] }>; Boolean: ResolverTypeWrapper; String: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { I_Node: ResolversInterfaceTypes['I_Node']; ID: Scalars['ID']['output']; T_WithNode: Omit & { node: ResolversParentTypes['I_Node'] }; T_Type1: Omit & { type2: ResolversParentTypes['T_Type2'] }; T_Type2: Omit & { type1: ResolversParentTypes['T_Type1'], withNode: ResolversParentTypes['T_WithNode'] }; Boolean: Scalars['Boolean']['output']; String: Scalars['String']['output']; }; `); }); it('does not generate nested types when avoidCheckingAbstractTypesRecursively=true', async () => { const schema = buildSchema(/* GraphQL */ ` interface I_Node { id: ID! } type T_WithNode { node: I_Node! } type T_Type1 { id: ID! type2: T_Type2! withNode: T_WithNode! # abstract type is in T_Type1 } type T_Type2 { id: ID! type1: T_Type1! } `); const result = await plugin(schema, [], { avoidCheckingAbstractTypesRecursively: true }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { I_Node: never; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { I_Node: ResolverTypeWrapper['I_Node']>; ID: ResolverTypeWrapper; T_WithNode: ResolverTypeWrapper & { node: ResolversTypes['I_Node'] }>; T_Type1: ResolverTypeWrapper; T_Type2: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; String: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { I_Node: ResolversInterfaceTypes['I_Node']; ID: Scalars['ID']['output']; T_WithNode: Omit & { node: ResolversParentTypes['I_Node'] }; T_Type1: T_Type1; T_Type2: T_Type2; Boolean: Scalars['Boolean']['output']; String: Scalars['String']['output']; }; `); }); it('generates __isTypeOf for only implementing object types', async () => { const schema = buildSchema(/* GraphQL */ ` interface Node { id: ID! } type Cat implements Node { id: ID! name: String! } type Dog implements Node { id: ID! isGoodBoy: Boolean! } type Human { _id: ID! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type CatResolvers = { id?: Resolver; name?: Resolver; __isTypeOf?: IsTypeOfResolverFn; } `); expect(result.content).toBeSimilarStringTo(` export type DogResolvers = { id?: Resolver; isGoodBoy?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); // Human does not implement Node, so it does not have __isTypeOf expect(result.content).toBeSimilarStringTo(` export type HumanResolvers = { _id?: Resolver; }; `); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.mapping.spec.ts ================================================ import { mergeOutputs, Types } from '@graphql-codegen/plugin-helpers'; import { resolversTestingSchema, resolversTestingValidate } from '@graphql-codegen/testing'; import { buildSchema } from 'graphql'; import { plugin } from '../src/index.js'; describe('TypeScript Resolvers Plugin - Mapping', () => { it('Should build ResolversTypes object when there are no mappers', async () => { const result = await plugin(resolversTestingSchema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ); MyUnion: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']> } ) | ( MyOtherType ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { unionChild?: Maybe }>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: Omit & { unionChild?: Maybe }; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: Omit & { unionChild?: Maybe, interfaceChild?: Maybe }; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('Should build ResolversTypes with simple mappers', async () => { const result = (await plugin( resolversTestingSchema, [], { mappers: { MyType: 'MyTypeDb', AnotherNodeWithChild: 'AnotherNodeWithChildMapper', String: 'number', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { bar: _RefType['String'], parent?: Maybe<_RefType['MyType']> } ) | ( Omit & { bar: _RefType['String'] } ); MyUnion: ( MyTypeDb ) | ( Omit & { bar: _RefType['String'] } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( AnotherNodeWithChildMapper ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( AnotherNodeWithChildMapper ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { bar: ResolversTypes['String'], parent?: Maybe }>; MyOtherType: ResolverTypeWrapper & { bar: ResolversTypes['String'] }>; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: MyTypeDb; String: number; Child: Omit & { bar: ResolversParentTypes['String'], parent?: Maybe }; MyOtherType: Omit & { bar: ResolversParentTypes['String'] }; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: AnotherNodeWithChildMapper; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('Should allow to map custom type that refers itself (issue #1770)', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Movie { id: ID! title: String! } type Book { id: ID! author: String! } union MovieLike = Movie | Book type NonInterfaceHasNarrative { narrative: MovieLike! movie: Movie! } `); const result = (await plugin( testSchema, [], { noSchemaStitching: true, mappers: { Movie: 'MovieEntity', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; const content = mergeOutputs([result]); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { MovieLike: ( MovieEntity ) | ( Book ); }; `); expect(content).toBeSimilarStringTo(` export type ResolversTypes = { Movie: ResolverTypeWrapper; ID: ResolverTypeWrapper; String: ResolverTypeWrapper; Book: ResolverTypeWrapper; MovieLike: ResolverTypeWrapper['MovieLike']>; NonInterfaceHasNarrative: ResolverTypeWrapper & { narrative: ResolversTypes['MovieLike'], movie: ResolversTypes['Movie'] }>; Boolean: ResolverTypeWrapper; }; `); expect(content).toBeSimilarStringTo(` export type ResolversParentTypes = { Movie: MovieEntity; ID: Scalars['ID']['output']; String: Scalars['String']['output']; Book: Book; MovieLike: ResolversUnionTypes['MovieLike']; NonInterfaceHasNarrative: Omit & { narrative: ResolversParentTypes['MovieLike'], movie: ResolversParentTypes['Movie'] }; Boolean: Scalars['Boolean']['output']; }; `); }); it('Should allow to map custom type that refers itself (issue #1770, attempt #2)', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Movie { id: ID! title: String! } type Book { id: ID! author: String! } union MovieLike = Movie | Book type NonInterfaceHasNarrative { narrative: MovieLike! movie: Movie! } type LayerOfIndirection { id: ID! movies: [NonInterfaceHasNarrative!]! } type AnotherLayerOfIndirection { inner: LayerOfIndirection! } `); const result = (await plugin( testSchema, [], { noSchemaStitching: true, mappers: { Movie: 'MovieEntity', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; const content = mergeOutputs([result]); expect(content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { MovieLike: ( MovieEntity ) | ( Book ); }; `); expect(content).toBeSimilarStringTo(`export type ResolversTypes = { Movie: ResolverTypeWrapper; ID: ResolverTypeWrapper; String: ResolverTypeWrapper; Book: ResolverTypeWrapper; MovieLike: ResolverTypeWrapper['MovieLike']>; NonInterfaceHasNarrative: ResolverTypeWrapper & { narrative: ResolversTypes['MovieLike'], movie: ResolversTypes['Movie'] }>; LayerOfIndirection: ResolverTypeWrapper & { movies: Array }>; AnotherLayerOfIndirection: ResolverTypeWrapper & { inner: ResolversTypes['LayerOfIndirection'] }>; Boolean: ResolverTypeWrapper; };`); expect(content).toBeSimilarStringTo(` export type ResolversParentTypes = { Movie: MovieEntity; ID: Scalars['ID']['output']; String: Scalars['String']['output']; Book: Book; MovieLike: ResolversUnionTypes['MovieLike']; NonInterfaceHasNarrative: Omit & { narrative: ResolversParentTypes['MovieLike'], movie: ResolversParentTypes['Movie'] }; LayerOfIndirection: Omit & { movies: Array }; AnotherLayerOfIndirection: Omit & { inner: ResolversParentTypes['LayerOfIndirection'] }; Boolean: Scalars['Boolean']['output']; }; `); }); it('Should allow to map custom type that refers itself (issue #1770, attempt #3 - circular)', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Account { id: ID! name: String! programs: [Program!]! } type Program { id: ID! name: String! account: Account! } `); const result = (await plugin( testSchema, [], { typesPrefix: 'Gql', defaultMapper: 'Partial<{T}>', namingConvention: { typeNames: 'change-case-all#pascalCase', enumValues: 'change-case-all#upperCase', }, noSchemaStitching: true, }, { outputFile: '' } )) as Types.ComplexPluginOutput; const content = mergeOutputs([result]); expect(content).toBeSimilarStringTo(`export type GqlResolversTypes = { Account: ResolverTypeWrapper>; ID: ResolverTypeWrapper>; String: ResolverTypeWrapper>; Program: ResolverTypeWrapper>; Boolean: ResolverTypeWrapper>; };`); }); it('should map to a custom type on every level (+ actual usage in code)', async () => { const testSchema = buildSchema(/* GraphQL */ ` type User { id: ID! name: String! chats: [Chat!] } type Chat { id: ID! owner: User! members: [User!] } type Query { me: User } `); const result = (await plugin( testSchema, [], { noSchemaStitching: true, mappers: { ID: 'number', Chat: 'number', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; const usage = ` const resolvers: Resolvers = { Query: { me() { return { id: 1, name: 'Foo', chats: [0,1,2], }; } }, Chat: { id(parent) { const id: number = parent; return id; } } } `; await resolversTestingValidate( mergeOutputs([usage, result]), { scalars: { ID: 'number', }, }, testSchema ); }); it('Should build ResolversTypes with defaultMapper set using {T}', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, defaultMapper: 'Partial<{T}>', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Partial & { parent?: Maybe<_RefType['MyType']> }> ) | ( Partial ); MyUnion: ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']> }> ) | ( Partial ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( Partial ); AnotherNode: ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> ); WithChild: ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> ); WithChildren: ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { unionChild?: Maybe }>>; String: ResolverTypeWrapper>; Child: ResolverTypeWrapper & { parent?: Maybe }>>; MyOtherType: ResolverTypeWrapper>; ChildUnion: Partial['ChildUnion']>>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper>; SomeNode: ResolverTypeWrapper>; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>>; MyUnion: Partial['MyUnion']>>; MyScalar: ResolverTypeWrapper>; Int: ResolverTypeWrapper>; Boolean: ResolverTypeWrapper>; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: Partial & { unionChild?: Maybe }>; String: Partial; Child: Partial & { parent?: Maybe }>; MyOtherType: Partial; ChildUnion: Partial['ChildUnion']>; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Partial; SomeNode: Partial; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: Partial & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: Partial & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: Partial['MyUnion']>; MyScalar: Partial; Int: Partial; Boolean: Partial; }; `); }); it('Should build ResolversTypes with defaultMapper set using {T} with external identifier', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, defaultMapper: './my-wrapper#CustomPartial<{T}>', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { CustomPartial } from './my-wrapper';`); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( CustomPartial & { parent?: Maybe<_RefType['MyType']> }> ) | ( CustomPartial ); MyUnion: ( CustomPartial & { unionChild?: Maybe<_RefType['ChildUnion']> }> ) | ( CustomPartial ); } `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( CustomPartial ); AnotherNode: ( CustomPartial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( CustomPartial & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> ); WithChild: ( CustomPartial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( CustomPartial & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> ); WithChildren: ( CustomPartial & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { unionChild?: Maybe }>>; String: ResolverTypeWrapper>; Child: ResolverTypeWrapper & { parent?: Maybe }>>; MyOtherType: ResolverTypeWrapper>; ChildUnion: CustomPartial['ChildUnion']>>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper>; SomeNode: ResolverTypeWrapper>; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>>; MyUnion: CustomPartial['MyUnion']>>; MyScalar: ResolverTypeWrapper>; Int: ResolverTypeWrapper>; Boolean: ResolverTypeWrapper>; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: CustomPartial & { unionChild?: Maybe }>; String: CustomPartial; Child: CustomPartial & { parent?: Maybe }>; MyOtherType: CustomPartial; ChildUnion: CustomPartial['ChildUnion']>; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: CustomPartial; SomeNode: CustomPartial; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: CustomPartial & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: CustomPartial & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: CustomPartial['MyUnion']>; MyScalar: CustomPartial; Int: CustomPartial; Boolean: CustomPartial; }; `); }); it('Should build ResolversTypes with mapper set for concrete type using {T} with external identifier', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyType: './my-wrapper#CustomPartial<{T}>', AnotherNodeWithChild: './my-wrapper#CustomPartial<{T}>', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { CustomPartial } from './my-wrapper';`); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ); MyUnion: ( CustomPartial & { unionChild?: Maybe<_RefType['ChildUnion']> }> ) | ( MyOtherType ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( CustomPartial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( CustomPartial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { unionChild?: Maybe }>>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: CustomPartial & { unionChild?: Maybe }>; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: CustomPartial & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('Should map to a custom type on every level when {T} is used as default mapper', async () => { const config = { scalars: { ID: 'number', }, noSchemaStitching: true, defaultMapper: 'Partial<{T}>', mappers: { User: 'number', }, }; const testSchema = buildSchema(/* GraphQL */ ` type User { id: ID! name: String! chats: [Chat!] } type Chat { id: ID! owner: User! members: [User!] } type Query { me: User } `); const result = await plugin(testSchema, [], config, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { User: ResolverTypeWrapper; ID: ResolverTypeWrapper>; String: ResolverTypeWrapper>; Chat: ResolverTypeWrapper & { owner: ResolversTypes['User'], members?: Maybe> }>>; Query: ResolverTypeWrapper>; Boolean: ResolverTypeWrapper>; }; `); const usage = ` const resolvers: Resolvers = { Query: { me() { return 1; } }, Chat: { id(chat) { return chat.id; }, owner(chat) { const id: number = chat.owner; return id; }, members(chat) { const ids: number[] = chat.members; return ids; } }, User: { id(parent) { const id: number = parent; return id; } } } `; await resolversTestingValidate(mergeOutputs([result, usage]), config, testSchema); }); it('Should build ResolversTypes with mapper set for concrete type using renamed external identifier', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyType: './my-type#MyType as DatabaseMyType', AnotherNodeWithChild: './my-interface#AnotherNodeWithChild as AnotherNodeWithChildMapper', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyType as DatabaseMyType } from './my-type';`); expect(result.prepend).toContain( `import { AnotherNodeWithChild as AnotherNodeWithChildMapper } from './my-interface';` ); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ); MyUnion: ( DatabaseMyType ) | ( MyOtherType ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( AnotherNodeWithChildMapper ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( AnotherNodeWithChildMapper ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: DatabaseMyType; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: AnotherNodeWithChildMapper; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('Should build ResolversTypes with mapper set for concrete type using renamed external identifier (with default)', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyOtherType: './my-type#default as DatabaseMyOtherType', MyType: './my-type#MyType as DatabaseMyType', AnotherNodeWithChild: './my-interface#default as AnotherNodeWithChildMapper', AnotherNodeWithAll: './my-interface#AnotherNodeWithAll as AnotherNodeWithAllMapper', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import DatabaseMyOtherType, { MyType as DatabaseMyType } from './my-type';`); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( DatabaseMyOtherType ); MyUnion: ( DatabaseMyType ) | ( DatabaseMyOtherType ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( AnotherNodeWithChildMapper ) | ( AnotherNodeWithAllMapper ); WithChild: ( AnotherNodeWithChildMapper ) | ( AnotherNodeWithAllMapper ); WithChildren: ( AnotherNodeWithAllMapper ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper; AnotherNodeWithAll: ResolverTypeWrapper; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: DatabaseMyType; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: DatabaseMyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: AnotherNodeWithChildMapper; AnotherNodeWithAll: AnotherNodeWithAllMapper; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('Should build ResolversTypes with mapper set for concrete type using renamed external identifier (with default) and type import', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyOtherType: './my-type#default as DatabaseMyOtherType', MyType: './my-type#MyType as DatabaseMyType', AnotherNodeWithChild: './my-interface#default as AnotherNodeWithChildMapper', AnotherNodeWithAll: './my-interface#AnotherNodeWithAll as AnotherNodeWithAllMapper', }, useTypeImports: true, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain( `import type { default as DatabaseMyOtherType, MyType as DatabaseMyType } from './my-type';` ); expect(result.prepend).toContain( `import type { default as AnotherNodeWithChildMapper, AnotherNodeWithAll as AnotherNodeWithAllMapper } from './my-interface';` ); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( DatabaseMyOtherType ); MyUnion: ( DatabaseMyType ) | ( DatabaseMyOtherType ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( AnotherNodeWithChildMapper ) | ( AnotherNodeWithAllMapper ); WithChild: ( AnotherNodeWithChildMapper ) | ( AnotherNodeWithAllMapper ); WithChildren: ( AnotherNodeWithAllMapper ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper; AnotherNodeWithAll: ResolverTypeWrapper; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: DatabaseMyType; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: DatabaseMyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: AnotherNodeWithChildMapper; AnotherNodeWithAll: AnotherNodeWithAllMapper; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('Should build ResolversTypes with defaultMapper set', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyType: 'MyTypeDb', String: 'string', }, defaultMapper: 'any', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).not.toBeSimilarStringTo(`export type ResolversUnionTypes`); expect(result.content).not.toBeSimilarStringTo(`export type ResolversInterfaceTypes`); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper; String: ResolverTypeWrapper; Child: ResolverTypeWrapper; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper; WithChild: ResolverTypeWrapper; WithChildren: ResolverTypeWrapper; AnotherNodeWithChild: ResolverTypeWrapper; AnotherNodeWithAll: ResolverTypeWrapper; MyUnion: ResolverTypeWrapper; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: MyTypeDb; String: string; Child: any; MyOtherType: any; ChildUnion: any; Query: Record; Subscription: Record; Node: any; ID: any; SomeNode: any; AnotherNode: any; WithChild: any; WithChildren: any; AnotherNodeWithChild: any; AnotherNodeWithAll: any; MyUnion: any; MyScalar: any; Int: any; Boolean: any; };`); }); it('Should build ResolversTypes with external mappers', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyOtherType: './my-module#CustomMyOtherType', MyType: 'MyTypeDb', AnotherNodeWithChild: './my-interface#AnotherNodeWithChildMapper', AnotherNodeWithAll: 'AnotherNodeWithAllMapper', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( CustomMyOtherType ); MyUnion: ( MyTypeDb ) | ( CustomMyOtherType ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( AnotherNodeWithChildMapper ) | ( AnotherNodeWithAllMapper ); WithChild: ( AnotherNodeWithChildMapper ) | ( AnotherNodeWithAllMapper ); WithChildren: ( AnotherNodeWithAllMapper ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper; AnotherNodeWithAll: ResolverTypeWrapper; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: MyTypeDb; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: CustomMyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: AnotherNodeWithChildMapper; AnotherNodeWithAll: AnotherNodeWithAllMapper; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('Should handle {T} in a mapper', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyType: 'Partial<{T}>', AnotherNodeWithChild: 'ExtraPartial<{T}>', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ); MyUnion: ( Partial & { unionChild?: Maybe<_RefType['ChildUnion']> }> ) | ( MyOtherType ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( ExtraPartial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( ExtraPartial & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { unionChild?: Maybe }>>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: Partial & { unionChild?: Maybe }>; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: ExtraPartial & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('should warn about unused mappers by default', async () => { const spy = vi.spyOn(console, 'warn').mockImplementation(() => {}); const testSchema = buildSchema(/* GraphQL */ ` type Query { comments: [Comment!]! } type User { id: ID! name: String! } type Comment { id: ID! text: String! author: User! } `); await plugin( testSchema, [], { noSchemaStitching: true, mappers: { Comment: 'number', Post: 'string', }, }, { outputFile: 'graphql.ts', } ); expect(spy).toHaveBeenCalledWith('Unused mappers: Post'); spy.mockRestore(); }); it('should be able not to warn about unused mappers', async () => { const spy = vi.spyOn(console, 'warn').mockImplementation(() => {}); const testSchema = buildSchema(/* GraphQL */ ` type Query { comments: [Comment!]! } type User { id: ID! name: String! } type Comment { id: ID! text: String! author: User! } `); await plugin( testSchema, [], { noSchemaStitching: true, mappers: { Comment: 'number', Post: 'string', }, showUnusedMappers: false, }, { outputFile: 'graphql.ts', } ); expect(spy).not.toHaveBeenCalled(); spy.mockRestore(); }); it('Should generate basic type resolvers with external mappers', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyOtherType: './my-file#MyCustomOtherType', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyCustomOtherType } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content) .toBeSimilarStringTo(`export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; } `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('Should generate basic type resolvers with external mappers using same imported type', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyType: './my-file#MyCustomOtherType', MyOtherType: './my-file#MyCustomOtherType', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyCustomOtherType } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content) .toBeSimilarStringTo(`export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; } `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('Should generate the correct resolvers when used with mappers with interfaces', async () => { const spy = vi.spyOn(console, 'warn').mockImplementation(() => {}); const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { Node: 'MyNodeType', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; } `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(mergeOutputs([result, `type MyNodeType = {};`])); spy.mockRestore(); }); it('Should generate basic type resolvers with defaultMapper set to any', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, defaultMapper: 'any', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; } `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('Should generate basic type resolvers with defaultMapper set to external identifier', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, defaultMapper: './my-file#MyBaseType', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyBaseType } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; } `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('Should replace using Omit when non-mapped type is pointing to mapped type', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyOtherType: 'MyOtherTypeCustom', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherTypeCustom ); MyUnion: ( Omit & { otherType?: Maybe<_RefType['MyOtherType']>, unionChild?: Maybe<_RefType['ChildUnion']> } ) | ( MyOtherTypeCustom ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { otherType?: Maybe, unionChild?: Maybe }>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: Omit & { otherType?: Maybe, unionChild?: Maybe }; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherTypeCustom; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: Omit & { unionChild?: Maybe, interfaceChild?: Maybe }; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); await resolversTestingValidate(mergeOutputs([result, 'type MyOtherTypeCustom = {};'])); }); it('Should not replace using Omit when non-mapped type is pointing to mapped type', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyOtherType: 'MyOtherTypeCustom', MyType: 'MyTypeCustom', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherTypeCustom ); MyUnion: ( MyTypeCustom ) | ( MyOtherTypeCustom ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; };`); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: MyTypeCustom; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherTypeCustom; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: Omit & { unionChild?: Maybe, interfaceChild?: Maybe }; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); await resolversTestingValidate(mergeOutputs([result, `type MyTypeCustom = {}; type MyOtherTypeCustom = {};`])); }); it('should support namespaces', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, mappers: { MyOtherType: './my-file#MyNamespace#MyCustomOtherType', AnotherNodeWithChild: './my-interface#InterfaceNamespace#AnotherNodeWithChildMapper', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyNamespace } from './my-file';`); expect(result.prepend).toContain(`import { InterfaceNamespace } from './my-interface';`); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyNamespace.MyCustomOtherType ); MyUnion: ( Omit & { otherType?: Maybe<_RefType['MyOtherType']>, unionChild?: Maybe<_RefType['ChildUnion']> } ) | ( MyNamespace.MyCustomOtherType ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( InterfaceNamespace.AnotherNodeWithChildMapper ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( InterfaceNamespace.AnotherNodeWithChildMapper ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { otherType?: Maybe, unionChild?: Maybe }>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: Omit & { otherType?: Maybe, unionChild?: Maybe }; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyNamespace.MyCustomOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: InterfaceNamespace.AnotherNodeWithChildMapper; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('should support namespaces in contextType', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, contextType: './my-file#MyNamespace#MyContextType', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyNamespace } from './my-file';`); expect(result.content).toContain(``); expect(result.content).not.toContain(``); expect(result.content).not.toContain(``); }); it('should support namespaces in defaultMapper', async () => { const result = (await plugin( resolversTestingSchema, [], { defaultMapper: './my-file#MyNamespace#MyDefaultMapper', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyNamespace } from './my-file';`); expect(result.content).not.toBeSimilarStringTo(`export type ResolversUnionTypes`); expect(result.content).not.toBeSimilarStringTo(`export type ResolversParentUnionTypes`); expect(result.content).not.toBeSimilarStringTo(`export type ResolversInterfaceTypes`); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper; String: ResolverTypeWrapper; Child: ResolverTypeWrapper; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper; WithChild: ResolverTypeWrapper; WithChildren: ResolverTypeWrapper; AnotherNodeWithChild: ResolverTypeWrapper; AnotherNodeWithAll: ResolverTypeWrapper; MyUnion: ResolverTypeWrapper; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: MyNamespace.MyDefaultMapper; String: MyNamespace.MyDefaultMapper; Child: MyNamespace.MyDefaultMapper; MyOtherType: MyNamespace.MyDefaultMapper; ChildUnion: MyNamespace.MyDefaultMapper; Query: Record; Subscription: Record; Node: MyNamespace.MyDefaultMapper; ID: MyNamespace.MyDefaultMapper; SomeNode: MyNamespace.MyDefaultMapper; AnotherNode: MyNamespace.MyDefaultMapper; WithChild: MyNamespace.MyDefaultMapper; WithChildren: MyNamespace.MyDefaultMapper; AnotherNodeWithChild: MyNamespace.MyDefaultMapper; AnotherNodeWithAll: MyNamespace.MyDefaultMapper; MyUnion: MyNamespace.MyDefaultMapper; MyScalar: MyNamespace.MyDefaultMapper; Int: MyNamespace.MyDefaultMapper; Boolean: MyNamespace.MyDefaultMapper; }; `); }); it('should support namespaces in rootValueType', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, rootValueType: './my-file#MyNamespace#MyRootType', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyNamespace } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ); MyUnion: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']> } ) | ( MyOtherType ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( SomeNode ); AnotherNode: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChild: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> } ) | ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); WithChildren: ( Omit & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> } ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { unionChild?: Maybe }>; String: ResolverTypeWrapper; Child: ResolverTypeWrapper & { parent?: Maybe }>; MyOtherType: ResolverTypeWrapper; ChildUnion: ResolverTypeWrapper['ChildUnion']>; Query: ResolverTypeWrapper; Subscription: ResolverTypeWrapper; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper; SomeNode: ResolverTypeWrapper; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: ResolverTypeWrapper['MyUnion']>; MyScalar: ResolverTypeWrapper; Int: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: Omit & { unionChild?: Maybe }; String: Scalars['String']['output']; Child: Omit & { parent?: Maybe }; MyOtherType: MyOtherType; ChildUnion: ResolversUnionTypes['ChildUnion']; Query: MyNamespace.MyRootType; Subscription: MyNamespace.MyRootType; Node: ResolversInterfaceTypes['Node']; ID: Scalars['ID']['output']; SomeNode: SomeNode; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: Omit & { unionChild?: Maybe, interfaceChild?: Maybe }; AnotherNodeWithAll: Omit & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }; MyUnion: ResolversUnionTypes['MyUnion']; MyScalar: Scalars['MyScalar']['output']; Int: Scalars['Int']['output']; Boolean: Scalars['Boolean']['output']; }; `); }); it('should support namespaces and {T} placeholder', async () => { const result = (await plugin( resolversTestingSchema, [], { defaultMapper: './my-file#MyNamespace#MyDefaultMapper<{T}>', mappers: { MyType: './my-file#MyNamespace#MyType<{T}>', AnotherNodeWithChild: './my-inteface#InterfaceNamespace#MyInterface<{T}>', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyNamespace } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { ChildUnion: ( MyNamespace.MyDefaultMapper & { parent?: Maybe<_RefType['MyType']> }> ) | ( MyNamespace.MyDefaultMapper ); MyUnion: ( MyNamespace.MyType & { unionChild?: Maybe<_RefType['ChildUnion']> }> ) | ( MyNamespace.MyDefaultMapper ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversInterfaceTypes<_RefType extends Record> = { Node: ( MyNamespace.MyDefaultMapper ); AnotherNode: ( InterfaceNamespace.MyInterface & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( MyNamespace.MyDefaultMapper & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> ); WithChild: ( InterfaceNamespace.MyInterface & { unionChild?: Maybe<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']> }> ) | ( MyNamespace.MyDefaultMapper & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> ); WithChildren: ( MyNamespace.MyDefaultMapper & { unionChild?: Maybe<_RefType['ChildUnion']>, unionChildren: Array<_RefType['ChildUnion']>, interfaceChild?: Maybe<_RefType['Node']>, interfaceChildren: Array<_RefType['Node']> }> ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { MyType: ResolverTypeWrapper & { unionChild?: Maybe }>>; String: ResolverTypeWrapper>; Child: ResolverTypeWrapper & { parent?: Maybe }>>; MyOtherType: ResolverTypeWrapper>; ChildUnion: MyNamespace.MyDefaultMapper['ChildUnion']>>; Query: ResolverTypeWrapper>; Subscription: ResolverTypeWrapper>; Node: ResolverTypeWrapper['Node']>; ID: ResolverTypeWrapper>; SomeNode: ResolverTypeWrapper>; AnotherNode: ResolverTypeWrapper['AnotherNode']>; WithChild: ResolverTypeWrapper['WithChild']>; WithChildren: ResolverTypeWrapper['WithChildren']>; AnotherNodeWithChild: ResolverTypeWrapper & { unionChild?: Maybe, interfaceChild?: Maybe }>>; AnotherNodeWithAll: ResolverTypeWrapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>>; MyUnion: MyNamespace.MyDefaultMapper['MyUnion']>>; MyScalar: ResolverTypeWrapper>; Int: ResolverTypeWrapper>; Boolean: ResolverTypeWrapper>; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { MyType: MyNamespace.MyType & { unionChild?: Maybe }>; String: MyNamespace.MyDefaultMapper; Child: MyNamespace.MyDefaultMapper & { parent?: Maybe }>; MyOtherType: MyNamespace.MyDefaultMapper; ChildUnion: MyNamespace.MyDefaultMapper['ChildUnion']>; Query: Record; Subscription: Record; Node: ResolversInterfaceTypes['Node']; ID: MyNamespace.MyDefaultMapper; SomeNode: MyNamespace.MyDefaultMapper; AnotherNode: ResolversInterfaceTypes['AnotherNode']; WithChild: ResolversInterfaceTypes['WithChild']; WithChildren: ResolversInterfaceTypes['WithChildren']; AnotherNodeWithChild: InterfaceNamespace.MyInterface & { unionChild?: Maybe, interfaceChild?: Maybe }>; AnotherNodeWithAll: MyNamespace.MyDefaultMapper & { unionChild?: Maybe, unionChildren: Array, interfaceChild?: Maybe, interfaceChildren: Array }>; MyUnion: MyNamespace.MyDefaultMapper['MyUnion']>; MyScalar: MyNamespace.MyDefaultMapper; Int: MyNamespace.MyDefaultMapper; Boolean: MyNamespace.MyDefaultMapper; }; `); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.meta.spec.ts ================================================ import '@graphql-codegen/testing'; import { plugin } from '../src/index.js'; import { buildSchema } from 'graphql'; describe('TypeScript Resolvers Plugin - Meta', () => { it('generates meta correctly', async () => { const result = await plugin( buildSchema(/* GraphQL */ ` type Query { user(id: ID!): User post(id: ID!): Post } type Mutation { createUser(name: String!): CreateUserPayload! } interface Node { id: ID! } type Post implements Node { id: ID! author: User } type User implements Node { id: ID! name: String } type CreateUserOk { user: User! } type CreateUserError { error: ErrorType! } union CreateUserPayload = CreateUserOk | CreateUserError enum ErrorType { FORBIDDEN_ERROR INTERNAL_ERROR } type TypeWithoutInterfaceOrUnion { id: ID! } `), [], { namingConvention: 'change-case-all#snakeCase', enumValues: { ErrorType: { FORBIDDEN_ERROR: '403', INTERNAL_ERROR: '500', }, }, }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type resolvers = { Query?: query_resolvers; Mutation?: mutation_resolvers; Node?: node_resolvers; Post?: post_resolvers; User?: user_resolvers; CreateUserOk?: create_user_ok_resolvers; CreateUserError?: create_user_error_resolvers; CreateUserPayload?: create_user_payload_resolvers; ErrorType?: error_type_resolvers; TypeWithoutInterfaceOrUnion?: type_without_interface_or_union_resolvers; };`); expect(result.content).toContain(`export type create_user_error_resolvers`); expect(result.content).toContain(`export type create_user_ok_resolvers`); expect(result.content).toContain(`export type create_user_payload_resolvers`); expect(result.content).toContain(`export type error_type_resolvers`); expect(result.content).toContain(`export type mutation_resolvers`); expect(result.content).toContain(`export type node_resolvers`); expect(result.content).toContain(`export type post_resolvers`); expect(result.content).toContain(`export type query_resolvers`); expect(result.content).toContain(`export type user_resolvers`); expect(result.meta).toMatchInlineSnapshot(` { "generatedResolverTypes": { "resolversMap": { "name": "resolvers", }, "userDefined": { "CreateUserError": { "hasIsTypeOf": true, "name": "create_user_error_resolvers", }, "CreateUserOk": { "hasIsTypeOf": true, "name": "create_user_ok_resolvers", }, "CreateUserPayload": { "hasIsTypeOf": false, "name": "create_user_payload_resolvers", }, "ErrorType": { "hasIsTypeOf": false, "name": "error_type_resolvers", }, "Mutation": { "hasIsTypeOf": false, "name": "mutation_resolvers", }, "Node": { "hasIsTypeOf": false, "name": "node_resolvers", }, "Post": { "hasIsTypeOf": true, "name": "post_resolvers", }, "Query": { "hasIsTypeOf": false, "name": "query_resolvers", }, "TypeWithoutInterfaceOrUnion": { "hasIsTypeOf": false, "name": "type_without_interface_or_union_resolvers", }, "User": { "hasIsTypeOf": true, "name": "user_resolvers", }, }, }, } `); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.spec.ts ================================================ import { mergeOutputs, Types } from '@graphql-codegen/plugin-helpers'; import { resolversTestingSchema, resolversTestingValidate, validateTs } from '@graphql-codegen/testing'; import { buildSchema } from 'graphql'; import { plugin as tsPlugin } from '../../typescript/src/index.js'; import { plugin } from '../src/index.js'; import { ENUM_RESOLVERS_SIGNATURE } from '../src/visitor.js'; describe('TypeScript Resolvers Plugin', () => { describe('Backward Compatability', () => { it('should produce IResolvers compatible with graphql-tools', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { users: [User!]! } type User { id: ID! name: String! } `); const tsContent = await tsPlugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); const resolversContent = (await plugin( testSchema, [], { contextType: 'Context', useIndexSignature: true, }, { outputFile: 'graphql.ts', } )) as Types.ComplexPluginOutput; const content = mergeOutputs([ tsContent, resolversContent, ` import { makeExecutableSchema } from '@graphql-tools/schema'; interface Context { users: Array<{ id: string; name: string; }>; } const resolvers: IResolvers = { Query: { users(parent, args, ctx, info) { return ctx.users; } } } makeExecutableSchema({ typeDefs: '', resolvers }) `, ]); expect(content).toBeSimilarStringTo(` export type Resolvers = ResolversObject<{ Query?: QueryResolvers; User?: UserResolvers; }>; `); validateTs(content); }); }); it('Should use StitchingResolver when its active on config', async () => { const result = await plugin(resolversTestingSchema, [], { noSchemaStitching: false }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(`export type StitchingResolver`); expect(result.content).toBeSimilarStringTo(` export type Resolver, TContext = Record, TArgs = Record> = | ResolverFn | ResolverWithResolve | StitchingResolver; `); await resolversTestingValidate(result); }); describe('Config', () => { it('addInterfaceFieldResolverTypes - should allow to have only resolveType for interfaces', async () => { const config = { addInterfaceFieldResolverTypes: true, }; const result = await plugin(resolversTestingSchema, [], config, { outputFile: '' }); const content = await resolversTestingValidate(result, config, resolversTestingSchema); expect(content).toBeSimilarStringTo(` export type WithChildrenResolvers = { __resolveType: TypeResolveFn<'AnotherNodeWithAll', ParentType, ContextType>; unionChildren?: Resolver, ParentType, ContextType>; nodes?: Resolver, ParentType, ContextType>; }; `); }); it('optionalInfoArgument - should allow to have optional info argument', async () => { const config = { noSchemaStitching: true, useIndexSignature: true, optionalInfoArgument: true, }; const result = await plugin(resolversTestingSchema, [], config, { outputFile: '' }); const content = await resolversTestingValidate(result, config, resolversTestingSchema); expect(content).not.toContain(`info: `); expect(content).toContain(`info?: `); expect(content).toMatchSnapshot(); }); it('allowParentTypeOverride - should allow to have less strict resolvers by overrding parent type', async () => { const config = { noSchemaStitching: true, useIndexSignature: true, allowParentTypeOverride: true, }; const result = await plugin(resolversTestingSchema, [], config, { outputFile: '' }); const content = await resolversTestingValidate( result, config, resolversTestingSchema, ` export const myTypeResolvers: MyTypeResolvers<{}, { parentOverride: boolean }> = { foo: (parentValue) => { const a: boolean = parentValue.parentOverride; return a.toString(); } }; ` ); expect(content).not.toContain(`ParentType extends `); expect(content).toContain(`ParentType = `); expect(content).toMatchSnapshot(); }); it('namespacedImportName - should work correctly with imported namespaced type', async () => { const config = { noSchemaStitching: true, useIndexSignature: true, namespacedImportName: 'Types', }; const result = await plugin(resolversTestingSchema, [], config, { outputFile: '' }); const content = mergeOutputs([result]); expect(content).toMatchSnapshot(); }); it('directiveResolverMappings - should generate correct types (inline definition)', async () => { const config = { noSchemaStitching: true, directiveResolverMappings: { authenticated: ` ( parent: TParent, args: TArgs, context: AuthenticatedContext, info: GraphQLResolveInfo ) => Promise | TResult;`, }, }; const result = await plugin(resolversTestingSchema, [], config, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolverFnAuthenticated = ( parent: TParent, args: TArgs, context: AuthenticatedContext, info: GraphQLResolveInfo ) => Promise | TResult; export type ResolverAuthenticatedWithResolve = { resolve: ResolverFnAuthenticated; }; export type ResolverAuthenticated, TContext = Record, TArgs = Record> = ResolverFnAuthenticated | ResolverAuthenticatedWithResolve; `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: ResolverAuthenticated; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); }); it('makeResolverTypeCallable - should remove ResolverWithResolve type from resolver union', async () => { const result = await plugin(resolversTestingSchema, [], { makeResolverTypeCallable: true }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type Resolver, TContext = Record, TArgs = Record> = ResolverFn; `); expect(result.content).not.toBeSimilarStringTo(` export type Resolver, TContext = Record, TArgs = Record> = ResolverFn | ResolverWithResolve; `); await resolversTestingValidate(result); }); it('makeResolverTypeCallable - adds ResolverWithResolve type to resolver union when set to false', async () => { const result = await plugin(resolversTestingSchema, [], { makeResolverTypeCallable: false }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo(` export type Resolver, TContext = Record, TArgs = Record> = ResolverFn; `); expect(result.content).toBeSimilarStringTo(` export type Resolver, TContext = Record, TArgs = Record> = ResolverFn | ResolverWithResolve; `); await resolversTestingValidate(result); }); }); it('directiveResolverMappings - should generate correct types (import definition)', async () => { const config = { noSchemaStitching: true, directiveResolverMappings: { authenticated: `../resolver-types.ts#AuthenticatedResolver`, }, }; const result = await plugin(resolversTestingSchema, [], config, { outputFile: '' }); expect(result.prepend).toContain( "import { AuthenticatedResolver as ResolverFnAuthenticated } from '../resolver-types.ts';" ); expect(result.prepend).toContain('export { ResolverFnAuthenticated };'); expect(result.content).toBeSimilarStringTo(` export type ResolverAuthenticatedWithResolve = { resolve: ResolverFnAuthenticated; }; export type ResolverAuthenticated, TContext = Record, TArgs = Record> = ResolverFnAuthenticated | ResolverAuthenticatedWithResolve; `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: ResolverAuthenticated; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); }); describe('Enums', () => { it('Should not generate enum internal values resolvers when enum doesnt have enumValues set', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { v: MyEnum } enum MyEnum { A B C } `); const config = { noSchemaStitching: true, }; const result = await plugin(testSchema, [], config, { outputFile: '' }); const mergedOutput = await resolversTestingValidate( result, config, testSchema, ` export const resolvers: Resolvers = { Query: { v: () => 'A', } }; ` ); expect(mergedOutput).not.toContain(ENUM_RESOLVERS_SIGNATURE); expect(mergedOutput).not.toContain('EnumResolverSignature'); }); it('Should generate enum internal values resolvers when enum has enumValues set as object with explicit values', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { v: MyEnum } enum MyEnum { A B C } `); const config = { noSchemaStitching: true, enumValues: { MyEnum: { A: 'val_1', B: 'val_2', C: 'val_3', }, }, }; const result = await plugin(testSchema, [], config, { outputFile: '' }); const mergedOutput = await resolversTestingValidate( result, config, testSchema, ` export const resolvers: Resolvers = { MyEnum: { A: 'val_1', B: 'val_2', C: 'val_3', }, Query: { v: () => 'val_1', } }; ` ); expect(mergedOutput).not.toContain(ENUM_RESOLVERS_SIGNATURE); expect(mergedOutput).not.toContain('EnumResolverSignature'); expect(mergedOutput).toContain(`export type MyEnumResolvers = { A: 'val_1', B: 'val_2', C: 'val_3' };`); }); it('#10418 - Should generate enum internal values resolvers when enum has enumValues set as object with partially explicit values', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { v: MyEnum w: MyEnum x: MyEnum } enum MyEnum { A B C } `); const config = { noSchemaStitching: true, enumValues: { MyEnum: { A: 'val_1', }, }, }; const result = await plugin(testSchema, [], config, { outputFile: '' }); const mergedOutput = await resolversTestingValidate( result, config, testSchema, ` export const resolvers: Resolvers = { MyEnum: { A: 'val_1', B: 'B' }, Query: { v: () => 'val_1', w: () => 'B', z: () => 'C', } }; ` ); expect(mergedOutput).not.toContain(ENUM_RESOLVERS_SIGNATURE); expect(mergedOutput).not.toContain('EnumResolverSignature'); expect(mergedOutput).toContain(`export type MyEnumResolvers = { A: 'val_1', B?: 'B', C?: 'C' };`); }); it('Should generate enum internal values resolvers when enum has enumValues set as external enum', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { v: MyEnum } enum MyEnum { A B C } `); const config = { noSchemaStitching: true, enumValues: { MyEnum: 'MyCustomEnum', }, }; const result = await plugin(testSchema, [], config, { outputFile: '' }); const mergedOutput = await resolversTestingValidate( result, config, testSchema, ` enum MyCustomEnum { CUSTOM_A, CUSTOM_B, CUSTOM_C } export const resolvers: Resolvers = { MyEnum: { A: MyCustomEnum.CUSTOM_A, B: MyCustomEnum.CUSTOM_B, C: MyCustomEnum.CUSTOM_C, }, Query: { v: () => MyCustomEnum.CUSTOM_A, } }; ` ); expect(mergedOutput).toContain(ENUM_RESOLVERS_SIGNATURE); expect(mergedOutput).toContain('EnumResolverSignature'); expect(mergedOutput).toContain( `export type MyEnumResolvers = EnumResolverSignature<{ A?: any, B?: any, C?: any }, ResolversTypes['MyEnum']>;` ); }); it('Should generate enum internal values resolvers when enum has mappers pointing to external enum', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { v: MyEnum } enum MyEnum { A B C } `); const config = { noSchemaStitching: true, mappers: { MyEnum: 'MyCustomEnum', }, }; const result = await plugin(testSchema, [], config, { outputFile: '' }); const mergedOutput = await resolversTestingValidate( result, config, testSchema, ` enum MyCustomEnum { CUSTOM_A, CUSTOM_B, CUSTOM_C } export const resolvers: Resolvers = { MyEnum: { A: MyCustomEnum.CUSTOM_A, B: MyCustomEnum.CUSTOM_B, C: MyCustomEnum.CUSTOM_C, }, Query: { v: () => MyCustomEnum.CUSTOM_A, } }; ` ); expect(mergedOutput).toContain(ENUM_RESOLVERS_SIGNATURE); expect(mergedOutput).toContain('EnumResolverSignature'); expect(mergedOutput).toContain( `export type MyEnumResolvers = EnumResolverSignature<{ A?: any, B?: any, C?: any }, ResolversTypes['MyEnum']>;` ); }); it('Should generate enum internal values resolvers when enum has enumValues set on a global level of all enums', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { v: MyEnum } enum MyEnum { A B C } `); const config = { noSchemaStitching: true, enumValues: './enums', }; const result = await plugin(testSchema, [], config, { outputFile: '' }); const mergedOutput = await resolversTestingValidate( result, config, testSchema, ` enum MyCustomEnum { CUSTOM_A, CUSTOM_B, CUSTOM_C } export const resolvers: Resolvers = { MyEnum: { A: MyCustomEnum.CUSTOM_A, B: MyCustomEnum.CUSTOM_B, C: MyCustomEnum.CUSTOM_C, }, Query: { v: () => MyCustomEnum.CUSTOM_A, } }; ` ); expect(mergedOutput).toContain(`import { MyEnum } from './enums'`); expect(mergedOutput).toContain(`export { MyEnum }`); expect(mergedOutput).toContain(ENUM_RESOLVERS_SIGNATURE); expect(mergedOutput).toContain('EnumResolverSignature'); expect(mergedOutput).toContain( `export type MyEnumResolvers = EnumResolverSignature<{ A?: any, B?: any, C?: any }, ResolversTypes['MyEnum']>;` ); }); }); it('Should allow to override ResolverTypeWrapper signature', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, resolverTypeWrapperSignature: 'Promise> | DeepPartial', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toContain(`export type ResolverTypeWrapper = Promise> | DeepPartial;`); }); it('Should have default value for ResolverTypeWrapper signature', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toContain(`export type ResolverTypeWrapper = Promise | T;`); }); it('Should not warn when noSchemaStitching is not defined', async () => { const spy = vi.spyOn(console, 'warn').mockImplementation(() => {}); const result = await plugin(resolversTestingSchema, [], {}, { outputFile: '' }); expect(spy).not.toHaveBeenCalled(); spy.mockRestore(); await resolversTestingValidate(result); }); it('Should disable StitchingResolver on demand', async () => { const result = (await plugin( resolversTestingSchema, [], { noSchemaStitching: true, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).not.toBeSimilarStringTo(` export type StitchingResolver = { fragment: string; resolve: ResolverFn; }; `); expect(result.content).not.toBeSimilarStringTo(` export type Resolver, TContext = Record, TArgs = Record> = | ResolverFn | ResolverWithResolve | StitchingResolver; `); expect(result.content).toBeSimilarStringTo(` export type Resolver, TContext = Record, TArgs = Record> = ResolverFn | ResolverWithResolve; `); await resolversTestingValidate(result); }); it('Default values of args and compatibility with typescript plugin', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { something(arg: String = "default_value"): String } `); const config: any = { noSchemaStitching: true }; const result = await plugin(testSchema, [], config, { outputFile: '' }); const mergedOutputs = mergeOutputs([ result, { content: ` const resolvers: QueryResolvers = { something: (root, args, context, info) => { return args.arg; // This should work becuase "args.arg" is now forced } };`, }, ]); expect(mergedOutputs).toContain(`export type RequireFields`); expect(mergedOutputs).toContain( `something?: Resolver, ParentType, ContextType, RequireFields>;` ); }); it('Test for enum usage in resolvers (to verify compatibility with enumValues)', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { a: A c: C } enum A { X Y Z } enum NotMapped { X Y } type B { a: String } enum C { Y Z } `); const config = { enumValues: { A: 'MyA', C: '../enums.js#MyC', }, typesPrefix: 'GQL_', }; const result = await plugin(testSchema, [], config, { outputFile: '' }); const tsContent = (await tsPlugin(testSchema, [], config, { outputFile: 'graphql.ts', })) as Types.ComplexPluginOutput; const mergedOutputs = mergeOutputs([result, tsContent]); expect(mergedOutputs).not.toContain(`A: A;`); expect(mergedOutputs).not.toContain(`A: GQL_A;`); expect(mergedOutputs).not.toContain(`C: GQL_MyC;`); expect(mergedOutputs).toContain(`NotMapped: GQL_NotMapped;`); expect(mergedOutputs).not.toContain(`NotMapped: NotMapped;`); expect(mergedOutputs).toContain(`A: MyA;`); expect(mergedOutputs).toContain(`B: GQL_B;`); expect(mergedOutputs).toContain(`C: C;`); expect(mergedOutputs).toContain(`import { MyC as C } from '../enums.js';`); }); it('Should allow to generate optional __resolveType', async () => { const result = (await plugin( resolversTestingSchema, [], { optionalResolveType: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType?: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType?: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); }); it('Should generate basic type resolvers', async () => { const result = await plugin(resolversTestingSchema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content) .toBeSimilarStringTo(`export interface MyScalarScalarConfig extends GraphQLScalarTypeConfig { name: 'MyScalar'; }`); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('Should allow to override context with simple identifier', async () => { const result = (await plugin( resolversTestingSchema, [], { contextType: 'MyCustomCtx', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(mergeOutputs([result, `type MyCustomCtx = {};`])); }); it('Should with correctly with addUnderscoreToArgsType set to true', async () => { const result = (await plugin( resolversTestingSchema, [], { addUnderscoreToArgsType: true, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toContain('MyType_WithArgsArgs'); expect(result.content).not.toContain('MyTypeWithArgsArgs'); await resolversTestingValidate(mergeOutputs([result])); }); it('Should allow to override context with mapped context type', async () => { const result = (await plugin( resolversTestingSchema, [], { contextType: './my-file#MyCustomCtx', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyCustomCtx } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('Should allow to override context with mapped context type', async () => { const result = (await plugin( resolversTestingSchema, [], { contextType: './my-file#MyCustomCtx', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyCustomCtx } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('Should allow to override context with mapped context type as default export', async () => { const result = (await plugin( resolversTestingSchema, [], { contextType: './my-file#default', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import ContextType from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('Should allow to override context with mapped context type as default export with type import', async () => { const result = (await plugin( resolversTestingSchema, [], { contextType: './my-file#default', useTypeImports: true, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import type { default as ContextType } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveArgs = { arg: Scalars['Int']['input']; arg2: Scalars['String']['input']; arg3: Scalars['Boolean']['input']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyDirectiveDirectiveResolver = DirectiveResolverFn;`); expect(result.content).toBeSimilarStringTo(` export type MyOtherTypeResolvers = { bar?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { __resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { __resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); expect(result.content).toBeSimilarStringTo(` export type SomeNodeResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type SubscriptionResolvers = { somethingChanged?: SubscriptionResolver, "somethingChanged", ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); it('should generate named custom field level context type', async () => { const result = (await plugin( resolversTestingSchema, [], { fieldContextTypes: [ 'MyType.foo#./my-file#ContextTypeOne', 'Query.something#./my-file#ContextTypeTwo', 'MyType.otherType#SpecialContextType', ], }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { ContextTypeOne, ContextTypeTwo } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; otherType?: Resolver, ParentType, SpecialContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type QueryResolvers = { something?: Resolver; }; `); }); it('should generate named custom field level context type for field with directive', async () => { const result = (await plugin( resolversTestingSchema, [], { directiveContextTypes: ['authenticated#./my-file#AuthenticatedContext'], }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { AuthenticatedContext } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver>; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); }); it('should generate named custom field level context type for field with directive and context type', async () => { const result = (await plugin( resolversTestingSchema, [], { directiveContextTypes: ['authenticated#./my-file#AuthenticatedContext'], contextType: './my-file#MyCustomCtx', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyCustomCtx, AuthenticatedContext } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver>; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); }); it('should generate named custom field level context type for field with directive and field context type', async () => { const result = (await plugin( resolversTestingSchema, [], { directiveContextTypes: ['authenticated#./my-file#AuthenticatedContext'], fieldContextTypes: ['MyType.foo#./my-file#ContextTypeOne'], }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { ContextTypeOne, AuthenticatedContext } from './my-file';`); expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver>; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); }); it('Should generate the correct imports when schema has scalars', async () => { const testSchema = buildSchema(`scalar MyScalar`); const result = await plugin(testSchema, [], {}, { outputFile: '' }); expect(result.prepend).toContain( `import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql';` ); await resolversTestingValidate(result, {}, resolversTestingSchema); }); it('Should generate the correct imports when schema has no scalars', async () => { const testSchema = buildSchema(`type MyType { f: String }`); const result = await plugin(testSchema, [], {}, { outputFile: '' }); expect(result.prepend).not.toContain(`import { GraphQLResolveInfo, GraphQLScalarTypeConfig } from 'graphql';`); await resolversTestingValidate(result, {}, testSchema); }); it('Should generate the correct imports when customResolveInfo defined in config', async () => { const testSchema = buildSchema(`scalar MyScalar`); const result = (await plugin( testSchema, [], { customResolveInfo: './my-type#MyGraphQLResolveInfo', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql';`); expect(result.prepend).toContain(`import { MyGraphQLResolveInfo as GraphQLResolveInfo } from './my-type';`); await resolversTestingValidate(result, {}, testSchema); }); it('#8852 - should generate the correct imports when customResolveInfo defined in config with type import', async () => { const testSchema = buildSchema(`scalar MyScalar`); const result = (await plugin( testSchema, [], { customResolveInfo: './my-type#MyGraphQLResolveInfo', useTypeImports: true, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import type { GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql';`); expect(result.prepend).toContain(`import type { MyGraphQLResolveInfo as GraphQLResolveInfo } from './my-type';`); await resolversTestingValidate(result, {}, testSchema); }); describe('Should generate the correct imports when customResolverFn defined in config', () => { it('./my-type#MyResolverFn', async () => { const testSchema = buildSchema(`scalar MyScalar`); const result = (await plugin( testSchema, [], { customResolverFn: './my-type#MyResolverFn', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyResolverFn as ResolverFn } from './my-type';`); expect(result.prepend).toContain(`export { ResolverFn };`); await resolversTestingValidate(result, {}, testSchema); }); it('./my-type#ResolverFn', async () => { const testSchema = buildSchema(`scalar MyScalar`); const result = (await plugin( testSchema, [], { customResolverFn: './my-type#ResolverFn', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { ResolverFn } from './my-type';`); expect(result.prepend).toContain(`export { ResolverFn };`); await resolversTestingValidate(result, {}, testSchema); }); it(`definition directly`, async () => { const testSchema = buildSchema(`scalar MyScalar`); const fnDefinition = `( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo & { nestedStuff: GraphQLResolveInfo } ) => Promise | TResult; `; const result = (await plugin( testSchema, [], { customResolverFn: fnDefinition, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`export type ResolverFn = ${fnDefinition}`); await resolversTestingValidate(result, {}, testSchema); }); it(`ok with default`, async () => { const testSchema = buildSchema(`scalar MyScalar`); const defaultResolverFn = ` export type ResolverFn = ( parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo ) => Promise | TResult;`; const result = await plugin(testSchema, [], {}, { outputFile: '' }); expect(result.content).toContain(defaultResolverFn); await resolversTestingValidate(result, {}, testSchema); }); }); it('Should not convert type names in unions', async () => { const testSchema = buildSchema(/* GraphQL */ ` type CCCFoo { foo: String! } type CCCBar { bar: String! } type Query { something: CCCUnion! } union CCCUnion = CCCFoo | CCCBar `); const tsContent = await tsPlugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); const content = await plugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); expect(tsContent.content).toBeSimilarStringTo(` export type CccFoo = { __typename?: 'CCCFoo'; foo: Scalars['String']['output']; }; `); expect(tsContent.content).toBeSimilarStringTo(` export type CccBar = { __typename?: 'CCCBar'; bar: Scalars['String']['output']; }; `); expect(content.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { CCCUnion: ( CccFoo ) | ( CccBar ); }; `); expect(content.content).toBeSimilarStringTo(` /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { CCCFoo: ResolverTypeWrapper; String: ResolverTypeWrapper; CCCBar: ResolverTypeWrapper; Query: ResolverTypeWrapper>; CCCUnion: ResolverTypeWrapper['CCCUnion']>; Boolean: ResolverTypeWrapper; }; `); expect(content.content).toBeSimilarStringTo(` export type ResolversParentTypes = { CCCFoo: CccFoo; String: Scalars['String']['output']; CCCBar: CccBar; Query: Record; CCCUnion: ResolversUnionTypes['CCCUnion']; Boolean: Scalars['Boolean']['output']; }; `); expect(content.content).toBeSimilarStringTo(` export type CccUnionResolvers = { __resolveType: TypeResolveFn<'CCCFoo' | 'CCCBar', ParentType, ContextType>; }; `); await validateTs(mergeOutputs([tsContent, content])); }); it('Should generate the correct resolver args type names when typesPrefix is specified', async () => { const testSchema = buildSchema(`type MyType { f(a: String): String }`); const config = { typesPrefix: 'T' }; const result = await plugin(testSchema, [], config, { outputFile: '' }); const o = await resolversTestingValidate(result, config, testSchema); expect(o).toContain( `f?: Resolver, ParentType, ContextType, Partial>;` ); }); // dotansimha/graphql-code-generator#3322 it('should make list of all-optional arguments include undefined types', async () => { const testSchema = buildSchema(`type MyType { f(a: String, b: Int): String }`); const result = await plugin(testSchema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo( `f?: Resolver, ParentType, ContextType, Partial>;` ); await resolversTestingValidate(result, {}, testSchema); }); // dotansimha/graphql-code-generator#3322 it('should include generic wrapper type only when necessary', async () => { const testSchema = buildSchema(`type MyType { f: String }`); const result = await plugin(testSchema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo( `f?: Resolver, ParentType, ContextType>;` ); await resolversTestingValidate(result, {}, testSchema); }); it('should generate Resolvers interface', async () => { const testSchema = buildSchema(/* GraphQL */ ` directive @modify(limit: Int) on FIELD_DEFINITION scalar Date type Query { post: Post entity: PostOrUser } interface Node { id: String } union PostOrUser = Post | User type Post implements Node { author: User } type User implements Node { id: String name: String } schema { query: Query } `); const content = (await plugin( testSchema, [], { scalars: { Date: 'Date' } }, { outputFile: 'graphql.ts', } )) as Types.ComplexPluginOutput; expect(content.content).toBeSimilarStringTo(` export type Resolvers = { Date?: GraphQLScalarType; Query?: QueryResolvers; Node?: NodeResolvers; PostOrUser?: PostOrUserResolvers; Post?: PostResolvers; User?: UserResolvers; }; `); expect(content.content).toBeSimilarStringTo(` export type DirectiveResolvers = { modify?: ModifyDirectiveResolver; }; `); }); it('should not create DirectiveResolvers if there is no directive defined in the schema', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { foo: String } `); const content = (await plugin( testSchema, [], { scalars: { Date: 'Date' } }, { outputFile: 'graphql.ts', } )) as Types.ComplexPluginOutput; expect(content.content).not.toBeSimilarStringTo(` export type DirectiveResolvers = {}; `); }); it('should produce Resolvers compatible with graphql-tools', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { users: [User!]! } type User { id: ID! name: String! } `); const tsContent = (await tsPlugin(testSchema, [], {}, { outputFile: 'graphql.ts' })) as Types.ComplexPluginOutput; const resolversContent = (await plugin( testSchema, [], { contextType: 'AppContext', useIndexSignature: true, }, { outputFile: 'graphql.ts', } )) as Types.ComplexPluginOutput; const content = mergeOutputs([ tsContent, resolversContent, ` import { makeExecutableSchema } from '@graphql-tools/schema'; interface AppContext { users: Array<{ id: string; name: string; }>; } const resolvers: Resolvers = { Query: { users(parent, args, ctx, info) { return ctx.users; } } } makeExecutableSchema({ typeDefs: '', resolvers }) `, ]); validateTs(content); }); it('should produce resolvers compatible with graphql-tools', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { users: [User!]! } type User { id: ID! name: String! } `); const tsContent = await tsPlugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); const resolversContent = await plugin( testSchema, [], { contextType: 'AppContext', useIndexSignature: true, }, { outputFile: 'graphql.ts', } ); const content = mergeOutputs([ tsContent, resolversContent, ` import { makeExecutableSchema } from '@graphql-tools/schema'; interface AppContext { users: Array<{ id: string; name: string; }>; } const query: QueryResolvers = { users(parent, args, ctx, info) { return ctx.users; } } makeExecutableSchema({ typeDefs: '', resolvers: { Query: query } }) `, ]); validateTs(content); }); it('should use {} as default of rootValueType', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Subscription { postAdded: Post } type Query { posts: [Post] } type Mutation { addPost(author: String, comment: String): Post } type Post { author: String comment: String } `); const content = await plugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); expect(content.content).toBeSimilarStringTo(` export type ResolversTypes = { Subscription: ResolverTypeWrapper>; Query: ResolverTypeWrapper>; Mutation: ResolverTypeWrapper>; String: ResolverTypeWrapper; Post: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); }); it('should generate ResolversParentTypes', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Subscription { postAdded: Post } type Query { posts: [Post] } type Mutation { addPost(author: String, comment: String): Post } type Post { author: String comment: String } `); const content = await plugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); expect(content.content).toBeSimilarStringTo(` export type ResolversParentTypes = { Subscription: Record; Query: Record; Mutation: Record; String: Scalars['String']['output']; Post: Post; Boolean: Scalars['Boolean']['output']; }; `); }); it('should use correct value when rootValueType mapped as default', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Subscription { postAdded: Post } type Query { posts: [Post] } type Mutation { addPost(author: String, comment: String): Post } type Post { author: String comment: String } `); const content = (await plugin( testSchema, [], { rootValueType: 'my-file#default', }, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(content.content).toBeSimilarStringTo(` export type ResolversTypes = { Subscription: ResolverTypeWrapper; Query: ResolverTypeWrapper; Mutation: ResolverTypeWrapper; String: ResolverTypeWrapper; Post: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); expect(content.prepend).toContain(`import RootValueType from 'my-file';`); }); it('should use correct value when rootValueType mapped as default with type import', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Subscription { postAdded: Post } type Query { posts: [Post] } type Mutation { addPost(author: String, comment: String): Post } type Post { author: String comment: String } `); const content = (await plugin( testSchema, [], { rootValueType: 'my-file#default', useTypeImports: true, }, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(content.prepend).toContain(`import type { default as RootValueType } from 'my-file';`); }); it('should use rootValueType in Query, Mutation and Subscription', async () => { const testSchema = buildSchema(/* GraphQL */ ` type MySubscription { postAdded: Post } type MyQuery { posts: [Post] } type MyMutation { addPost(author: String, comment: String): Post } type Post { author: String comment: String } schema { query: MyQuery mutation: MyMutation subscription: MySubscription } `); const content = (await plugin( testSchema, [], { rootValueType: 'MyRoot', }, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(content.content).toBeSimilarStringTo(` export type ResolversTypes = { MySubscription: ResolverTypeWrapper; MyQuery: ResolverTypeWrapper; MyMutation: ResolverTypeWrapper; String: ResolverTypeWrapper; Post: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; }; `); }); it('should generate subscription types correctly', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Subscription { postAdded: Post } type Query { posts: [Post] } type Mutation { addPost(author: String, comment: String): Post } type Post { author: String comment: String } `); const tsContent = await tsPlugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); const resolversContent = await plugin( testSchema, [], { rootValueType: '{version: 1}', }, { outputFile: 'graphql.ts' } ); const content = mergeOutputs([ tsContent, resolversContent, ` import { PubSub } from 'graphql-subscriptions'; const pubsub = new PubSub(); const POST_ADDED = 'POST_ADDED'; const resolvers: Resolvers = { Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator([POST_ADDED]), } }, Mutation: { addPost: (root, { author, comment }) => { const post = { author, comment, }; // RootValue should be accessible console.log(root.version); // Pass correct data pubsub.publish(POST_ADDED, post); // Return correct data return post; } }, }; `, ]); validateTs(content); }); it('should use MaybePromise in ResolverTypeWrapper', async () => { const testSchema = buildSchema(/* GraphQL */ ` type MySubscription { postAdded: Post } type MyQuery { posts: [Post] } type MyMutation { addPost(author: String, comment: String): Post } type Post { author: String comment: String } schema { query: MyQuery mutation: MyMutation subscription: MySubscription } `); const content = (await plugin( testSchema, [], { rootValueType: 'MyRoot', asyncResolverTypes: true, } as any, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(content.content).toBeSimilarStringTo(` export type ResolverTypeWrapper = Promise | T; `); }); it.skip('should support all use-cases of subscription resolvers', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Subscription { postAdded: Post } type Query { posts: [Post] } type Post { author: String comment: String } `); const tsContent = await tsPlugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); const resolversContent = (await plugin( testSchema, [], {}, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; const validateResolvers = (code: string) => { validateTs( mergeOutputs([ tsContent, resolversContent, ` import { PubSub } from 'graphql-subscriptions'; const pubsub = new PubSub(); const POST_ADDED = 'POST_ADDED'; `, code, ]) ); }; // if `subscribe` returns anything // `resolve` should be defined // and `parent` should be any expect(() => { validateResolvers(` type PubSubEvent = { text: string; user: string; }; const resolvers: Resolvers = { Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator(POST_ADDED), resolve: parent => { return { comment: parent.text, author: parent.user }; } } } }; `); }).not.toThrow(); // if `subscribe` returns anything // `resolve` should be defined // and `parent` should be any // but resolver is missing... expect(() => { validateResolvers(` import { PubSub } from 'graphql-subscriptions'; const pubsub = new PubSub(); const POST_ADDED = 'POST_ADDED'; type PubSubEvent = { text: string; user: string; }; const resolvers: Resolvers = { Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator(POST_ADDED) // resolvers is missing! } } }; `); }).toThrow(); // if `subscribe` returns { postAdded: PostAdded } // `resolve` should be optional expect(() => { validateResolvers(` import { PubSub } from 'graphql-subscriptions'; const pubsub = new PubSub(); const POST_ADDED = 'POST_ADDED'; type PubSubEvent = { postAdded: { comment: string; author: string; } }; const resolvers: Resolvers = { Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator(POST_ADDED), }, } }; `); }).not.toThrow(); // if `subscribe` returns { postAdded: PostAdded } // and `parent` should be { postAdded: PostAdded } expect(() => { validateResolvers(` import { PubSub } from 'graphql-subscriptions'; const pubsub = new PubSub(); const POST_ADDED = 'POST_ADDED'; type PubSubEvent = { postAdded: { comment: string; author: string; } }; const resolvers: Resolvers = { Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator(POST_ADDED), resolve: event => event.postAdded }, } }; `); }).not.toThrow(); // if `subscribe` returns { postAdded: Foo } // `resolve` shouldn't be optional expect(() => { validateResolvers(` import { PubSub } from 'graphql-subscriptions'; const pubsub = new PubSub(); const POST_ADDED = 'POST_ADDED'; type PubSubEvent = { postAdded: { text: string; user: string; } }; const resolvers: Resolvers = { Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator(POST_ADDED), }, } }; `); }).toThrow(); // if `subscribe` returns { postAdded: Foo } // and `parent` should be { postAdded: Foo } expect(() => { validateResolvers(` import { PubSub } from 'graphql-subscriptions'; const pubsub = new PubSub(); const POST_ADDED = 'POST_ADDED'; type PubSubEvent = { postAdded: { text: string; user: string; } }; const resolvers: Resolvers = { Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator(POST_ADDED), resolve: (event) => { return { comment: event.text, author: event.user }; } }, } }; `); }).not.toThrow(); // if `subscribe` returns PostAdded // `resolve` should be optional expect(() => { validateResolvers(` import { PubSub } from 'graphql-subscriptions'; const pubsub = new PubSub(); const POST_ADDED = 'POST_ADDED'; type PubSubEvent = { comment: string; author: string; }; const resolvers: Resolvers = { Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator(POST_ADDED), }, } }; `); }).not.toThrow(); // if `subscribe` returns PostAdded // `parent` should be of type PostAdded expect(() => { validateResolvers(` import { PubSub } from 'graphql-subscriptions'; const pubsub = new PubSub(); const POST_ADDED = 'POST_ADDED'; type PubSubEvent = { comment: string; author: string; }; const resolvers: Resolvers = { Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator(POST_ADDED), resolve: event => event }, } }; `); }).not.toThrow(); }); describe('issues', () => { it('#4687 - incorrect suffix when used with typesSuffix', async () => { const testSchema = buildSchema(/* GraphQL */ ` type User { _id: ID! } type Query { user(_id: ID!): User user2(_id: ID): User me: User } `); const config = { typesSuffix: 'QL', }; const output = await plugin(testSchema, [], config, { outputFile: 'graphql.ts' }); const o = await resolversTestingValidate(output, config, testSchema); expect(o).not.toContain( `user?: Resolver, ParentType, ContextType, RequireFields>;` ); expect(o).toContain( `user?: Resolver, ParentType, ContextType, RequireFields>;` ); expect(o).toContain(`me?: Resolver, ParentType, ContextType>;`); expect(o).toContain( `user2?: Resolver, ParentType, ContextType, Partial>;` ); }); it('should work correctly with enumPrefix: false - issue #2679', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { t: Test } enum Test { A B C } `); const config = { typesPrefix: 'I', enumPrefix: false, namingConvention: 'keep', constEnums: true, }; const output = await plugin(testSchema, [], config, { outputFile: 'graphql.ts' }); const o = await resolversTestingValidate(output, config, testSchema); expect(o).toBeSimilarStringTo(` export const enum Test { A = 'A', B = 'B', C = 'C' };`); expect(o).toBeSimilarStringTo(` export type IResolversTypes = { Query: ResolverTypeWrapper>; Test: Test; Boolean: ResolverTypeWrapper; String: ResolverTypeWrapper; };`); }); it('#3257 - should not import mapper when its already imported because of enumValues', async () => { const testSchema = buildSchema(/* GraphQL */ ` schema { query: Query } type Query { role: [ProjectRoleDetail!]! } enum ProjectRole { PROJECT_MANAGER ETC } type ProjectRoleDetail { code: ProjectRole! name: String! } `); const config = { noSchemaStitching: true, contextType: '@src/context#Context', useIndexSignature: true, avoidOptionals: true, mappers: { ProjectRoleDetail: '../entities#ProjectRole', }, enumValues: { ProjectRole: '../entities#AnotherProjectRole', }, }; const tsContent = (await tsPlugin(testSchema, [], config, { outputFile: 'graphql.ts', })) as Types.ComplexPluginOutput; const output = await plugin(testSchema, [], config, { outputFile: 'graphql.ts' }); expect(output.prepend.filter(t => t.includes('import')).length).toBe(2); expect(output.prepend.filter(t => t.includes('ProjectRole')).length).toBe(0); expect(tsContent.prepend.filter(t => t.includes('ProjectRole')).length).toBe(1); expect(output.content.includes('AnotherProjectRole')).toBeFalsy(); expect( tsContent.prepend.includes(`import { AnotherProjectRole as ProjectRole } from '../entities';`) ).toBeTruthy(); expect(output.prepend.includes(`import { AnotherProjectRole as ProjectRole } from '../entities';`)).toBeFalsy(); }); it('#3264 - enumValues is not being applied to directive resolver', async () => { const testSchema = buildSchema(/* GraphQL */ ` directive @auth( role: UserRole = ADMIN ) on OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION enum UserRole { ADMIN USER } schema { query: Query } type Query { me: User! } type User { id: ID! username: String! email: String! role: UserRole! } `); const output = (await plugin( testSchema, [], { noSchemaStitching: true, typesPrefix: 'Gql', maybeValue: 'T | undefined', enumValues: { UserRole: '@org/package#UserRole', }, } as any, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(output.content).toContain(`export type GqlAuthDirectiveArgs = {\n role?: Maybe;\n};`); expect(output.content).toContain( `export type GqlAuthDirectiveResolver = DirectiveResolverFn;` ); }); }); it('Should generate resolvers with replaced internalResolversPrefix if specified', async () => { const result = (await plugin( resolversTestingSchema, [], { internalResolversPrefix: '' }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).not.toContain('__resolveType'); expect(result.content).toContain('resolveType'); expect(result.content).not.toContain('__isTypeOf'); expect(result.content).toContain('isTypeOf'); expect(result.content).toBeSimilarStringTo(` export type MyUnionResolvers = { resolveType: TypeResolveFn<'MyType' | 'MyOtherType', ParentType, ContextType>; }; `); expect(result.content).toBeSimilarStringTo(` export type NodeResolvers = { resolveType: TypeResolveFn<'SomeNode', ParentType, ContextType>; }; `); await resolversTestingValidate(result); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/ts-resolvers.union.spec.ts ================================================ import '@graphql-codegen/testing'; import { buildSchema } from 'graphql'; import { plugin } from '../src/index.js'; describe('TypeScript Resolvers Plugin - Union', () => { it('should generate ResolversUnionTypes', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { user(id: ID!): UserPayload! posts: PostsPayload! } type StandardError { error: String! } type User { id: ID! fullName: String! } type UserResult { result: User } union UserPayload = UserResult | StandardError type Post { author: String comment: String } type PostsResult { results: [Post!]! } union PostsPayload = PostsResult | StandardError `); const content = await plugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); expect(content.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { UserPayload: ( UserResult ) | ( StandardError ); PostsPayload: ( PostsResult ) | ( StandardError ); }; `); expect(content.content).toBeSimilarStringTo(` export type ResolversTypes = { Query: ResolverTypeWrapper>; ID: ResolverTypeWrapper; StandardError: ResolverTypeWrapper; String: ResolverTypeWrapper; User: ResolverTypeWrapper; UserResult: ResolverTypeWrapper; UserPayload: ResolverTypeWrapper['UserPayload']>; Post: ResolverTypeWrapper; PostsResult: ResolverTypeWrapper; PostsPayload: ResolverTypeWrapper['PostsPayload']>; Boolean: ResolverTypeWrapper; }; `); expect(content.content).toBeSimilarStringTo(` export type ResolversParentTypes = { Query: Record; ID: Scalars['ID']['output']; StandardError: StandardError; String: Scalars['String']['output']; User: User; UserResult: UserResult; UserPayload: ResolversUnionTypes['UserPayload']; Post: Post; PostsResult: PostsResult; PostsPayload: ResolversUnionTypes['PostsPayload']; Boolean: Scalars['Boolean']['output']; }; `); }); it('should NOT generate ResolversUnionTypes if there is no Union', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { user(id: ID!): User } type User { id: ID! fullName: String! } `); const content = await plugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); expect(content.content).not.toBeSimilarStringTo(`export type ResolversUnionTypes`); expect(content.content).not.toBeSimilarStringTo(`export type ResolversUnionParentTypes`); }); it('generates nested types when avoidCheckingAbstractTypesRecursively=false (default)', async () => { const schema = buildSchema(/* GraphQL */ ` type StandardError { error: String! } type User { id: ID! fullName: String! posts: PostsPayload! } type UserResult { result: User recommendedPosts: PostsPayload! } union UserPayload = UserResult | StandardError type Post { author: String comment: String } type PostsResult { results: [Post!]! } union PostsPayload = PostsResult | StandardError `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { UserPayload: ( Omit & { result?: Maybe<_RefType['User']>, recommendedPosts: _RefType['PostsPayload'] } ) | ( StandardError ); PostsPayload: ( PostsResult ) | ( StandardError ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { StandardError: ResolverTypeWrapper; String: ResolverTypeWrapper; User: ResolverTypeWrapper & { posts: ResolversTypes['PostsPayload'] }>; ID: ResolverTypeWrapper; UserResult: ResolverTypeWrapper & { result?: Maybe, recommendedPosts: ResolversTypes['PostsPayload'] }>; UserPayload: ResolverTypeWrapper['UserPayload']>; Post: ResolverTypeWrapper; PostsResult: ResolverTypeWrapper; PostsPayload: ResolverTypeWrapper['PostsPayload']>; Boolean: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { StandardError: StandardError; String: Scalars['String']['output']; User: Omit & { posts: ResolversParentTypes['PostsPayload'] }; ID: Scalars['ID']['output']; UserResult: Omit & { result?: Maybe, recommendedPosts: ResolversParentTypes['PostsPayload'] }; UserPayload: ResolversUnionTypes['UserPayload']; Post: Post; PostsResult: PostsResult; PostsPayload: ResolversUnionTypes['PostsPayload']; Boolean: Scalars['Boolean']['output']; }; `); }); it('does not generate nested types when avoidCheckingAbstractTypesRecursively=true', async () => { const schema = buildSchema(/* GraphQL */ ` type StandardError { error: String! } type User { id: ID! fullName: String! posts: PostsPayload! } type UserResult { result: User recommendedPosts: PostsPayload! } union UserPayload = UserResult | StandardError type Post { author: String comment: String } type PostsResult { results: [Post!]! } union PostsPayload = PostsResult | StandardError `); const result = await plugin(schema, [], { avoidCheckingAbstractTypesRecursively: true }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type ResolversUnionTypes<_RefType extends Record> = { UserPayload: ( Omit & { recommendedPosts: _RefType['PostsPayload'] } ) | ( StandardError ); PostsPayload: ( PostsResult ) | ( StandardError ); }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversTypes = { StandardError: ResolverTypeWrapper; String: ResolverTypeWrapper; User: ResolverTypeWrapper & { posts: ResolversTypes['PostsPayload'] }>; ID: ResolverTypeWrapper; UserResult: ResolverTypeWrapper & { recommendedPosts: ResolversTypes['PostsPayload'] }>; UserPayload: ResolverTypeWrapper['UserPayload']>; Post: ResolverTypeWrapper; PostsResult: ResolverTypeWrapper; PostsPayload: ResolverTypeWrapper['PostsPayload']>; Boolean: ResolverTypeWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type ResolversParentTypes = { StandardError: StandardError; String: Scalars['String']['output']; User: Omit & { posts: ResolversParentTypes['PostsPayload'] }; ID: Scalars['ID']['output']; UserResult: Omit & { recommendedPosts: ResolversParentTypes['PostsPayload'] }; UserPayload: ResolversUnionTypes['UserPayload']; Post: Post; PostsResult: PostsResult; PostsPayload: ResolversUnionTypes['PostsPayload']; Boolean: Scalars['Boolean']['output']; }; `); }); it('generates __isTypeOf for only union members', async () => { const schema = buildSchema(/* GraphQL */ ` type MemberOne { id: ID! } type MemberTwo { id: ID! name: String! } type MemberThree { id: ID! isMember: Boolean! } union Union = MemberOne | MemberTwo | MemberThree type Normal { id: ID! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MemberOneResolvers = { id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; } `); expect(result.content).toBeSimilarStringTo(` export type MemberTwoResolvers = { id?: Resolver; name?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(result.content).toBeSimilarStringTo(` export type MemberThreeResolvers = { id?: Resolver; isMember?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); // Normal type is not a union member, so it does not have __isTypeOf expect(result.content).toBeSimilarStringTo(` export type NormalResolvers = { id?: Resolver; }; `); }); }); ================================================ FILE: packages/plugins/typescript/resolvers/tests/utils.ts ================================================ import { codegen } from '@graphql-codegen/core'; import { parse } from 'graphql'; import { TypeScriptResolversPluginConfig } from '../src/config.js'; import { plugin } from '../src/index.js'; export function generate({ schema, config }: { schema: string; config: TypeScriptResolversPluginConfig }) { return codegen({ filename: 'graphql.ts', schema: parse(schema), documents: [], plugins: [{ 'typescript-resolvers': {} }], config, pluginMap: { 'typescript-resolvers': { plugin } }, }); } ================================================ FILE: packages/plugins/typescript/resolvers/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'typescript-resolvers', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/typescript/typed-document-node/CHANGELOG.md ================================================ # @graphql-codegen/typed-document-node ## 6.1.7 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-codegen/visitor-plugin-common@^6.2.3` ↗︎](https://www.npmjs.com/package/@graphql-codegen/visitor-plugin-common/v/6.2.3) (from `6.2.3`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 - @graphql-codegen/visitor-plugin-common@6.2.4 ## 6.1.6 ### Patch Changes - Updated dependencies [[`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf)]: - @graphql-codegen/visitor-plugin-common@6.2.3 ## 6.1.5 ### Patch Changes - Updated dependencies [[`f588d91`](https://github.com/dotansimha/graphql-code-generator/commit/f588d91ac43ea0aa5931915ce980d2e6876bb59c)]: - @graphql-codegen/visitor-plugin-common@6.2.2 ## 6.1.4 ### Patch Changes - Updated dependencies [[`b995ed1`](https://github.com/dotansimha/graphql-code-generator/commit/b995ed13a49379ea05e0e313fac68b557527523a)]: - @graphql-codegen/visitor-plugin-common@6.2.1 ## 6.1.3 ### Patch Changes - Updated dependencies [[`f821e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f821e8ab9351f23a9f7e5d5e6fc69c8e8868cad8), [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/visitor-plugin-common@6.2.0 - @graphql-codegen/plugin-helpers@6.1.0 ## 6.1.2 ### Patch Changes - Updated dependencies [[`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d)]: - @graphql-codegen/visitor-plugin-common@6.1.2 ## 6.1.1 ### Patch Changes - Updated dependencies [[`6715330`](https://github.com/dotansimha/graphql-code-generator/commit/67153304646694d75aee24afd70c3fce12e9f1f2)]: - @graphql-codegen/visitor-plugin-common@6.1.1 ## 6.1.0 ### Minor Changes - [#10456](https://github.com/dotansimha/graphql-code-generator/pull/10456) [`655b91d`](https://github.com/dotansimha/graphql-code-generator/commit/655b91dd6d8b5f90eb26cd59d6a3d12c3dccc529) Thanks [@aovens-quantifi](https://github.com/aovens-quantifi)! - feat(typed-document-node): Allow importing operation types Adds the `importOperationTypesFrom` option, similar to many other codegen plugins. This allows importing the operation types rather than needing to generate them within this plugin config. ## 6.0.2 ### Patch Changes - Updated dependencies [[`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26)]: - @graphql-codegen/visitor-plugin-common@6.1.0 ## 6.0.1 ### Patch Changes - Updated dependencies [[`accdab6`](https://github.com/dotansimha/graphql-code-generator/commit/accdab69106605241933e9d66d64dc7077656f30)]: - @graphql-codegen/visitor-plugin-common@6.0.1 ## 6.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/visitor-plugin-common@6.0.0 - @graphql-codegen/plugin-helpers@6.0.0 ## 5.1.2 ### Patch Changes - [#10362](https://github.com/dotansimha/graphql-code-generator/pull/10362) [`3188b8c`](https://github.com/dotansimha/graphql-code-generator/commit/3188b8c39e9fd24e3dbbd0bcc8767052153eb399) Thanks [@Brookke](https://github.com/Brookke)! - Make generated type compatible with noImplicitOverride=true - [#10373](https://github.com/dotansimha/graphql-code-generator/pull/10373) [`c3295f9`](https://github.com/dotansimha/graphql-code-generator/commit/c3295f9c60383e5631ccc4080bc28e7c00a4d61b) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix client preset not working with exactOptionalPropertyTypes=true when documentMode=string ## 5.1.1 ### Patch Changes - Updated dependencies [[`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc)]: - @graphql-codegen/visitor-plugin-common@5.8.0 ## 5.1.0 ### Minor Changes - [#10307](https://github.com/dotansimha/graphql-code-generator/pull/10307) [`bfe3c75`](https://github.com/dotansimha/graphql-code-generator/commit/bfe3c7575e0b5f3a252fe9d72416f7829e44c885) Thanks [@mvantellingen](https://github.com/mvantellingen)! - Update generated code to be compatible with TypeScript 5.8 `erasableSyntaxOnly` flag ## 5.0.15 ### Patch Changes - Updated dependencies [[`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a)]: - @graphql-codegen/visitor-plugin-common@5.7.1 ## 5.0.14 ### Patch Changes - Updated dependencies [[`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c)]: - @graphql-codegen/visitor-plugin-common@5.7.0 ## 5.0.13 ### Patch Changes - Updated dependencies [[`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517)]: - @graphql-codegen/visitor-plugin-common@5.6.1 ## 5.0.12 ### Patch Changes - Updated dependencies [[`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a), [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba)]: - @graphql-codegen/visitor-plugin-common@5.6.0 ## 5.0.11 ### Patch Changes - [#10160](https://github.com/dotansimha/graphql-code-generator/pull/10160) [`c7af639`](https://github.com/dotansimha/graphql-code-generator/commit/c7af63964089938150402db69d49f11f93bb5175) Thanks [@jyasskin](https://github.com/jyasskin)! - Allow explicit `undefined` in additional to optional arguments - Updated dependencies [[`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc), [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03)]: - @graphql-codegen/visitor-plugin-common@5.5.0 - @graphql-codegen/plugin-helpers@5.1.0 ## 5.0.10 ### Patch Changes - Updated dependencies [[`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4)]: - @graphql-codegen/visitor-plugin-common@5.4.0 ## 5.0.9 ### Patch Changes - Updated dependencies [[`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2)]: - @graphql-codegen/visitor-plugin-common@5.3.1 ## 5.0.8 ### Patch Changes - Updated dependencies [[`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3), [`14ce39e`](https://github.com/dotansimha/graphql-code-generator/commit/14ce39e41dfee38c652be736664177fa2b1df421)]: - @graphql-codegen/visitor-plugin-common@5.3.0 ## 5.0.7 ### Patch Changes - Updated dependencies [[`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431), [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e)]: - @graphql-codegen/plugin-helpers@5.0.4 - @graphql-codegen/visitor-plugin-common@5.2.0 ## 5.0.6 ### Patch Changes - Updated dependencies [[`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53), [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d)]: - @graphql-codegen/visitor-plugin-common@5.1.0 ## 5.0.5 ### Patch Changes - Updated dependencies [[`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5)]: - @graphql-codegen/visitor-plugin-common@5.0.0 ## 5.0.4 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/visitor-plugin-common@4.1.2 - @graphql-codegen/plugin-helpers@5.0.3 ## 5.0.3 ### Patch Changes - Updated dependencies [[`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f)]: - @graphql-codegen/visitor-plugin-common@4.1.1 ## 5.0.2 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 - @graphql-codegen/visitor-plugin-common@4.1.0 ## 5.0.1 ### Patch Changes - Updated dependencies [[`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a)]: - @graphql-codegen/visitor-plugin-common@4.0.1 ## 5.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Minor Changes - [#9196](https://github.com/dotansimha/graphql-code-generator/pull/9196) [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96) Thanks [@beerose](https://github.com/beerose)! - Add `@defer` directive support When a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved. Once start using the `@defer` directive in your queries, the generated code will automatically include support for the directive. ```jsx // src/index.tsx import { graphql } from './gql' const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `) const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `) ``` The generated type for `GetUserQuery` will have information that the fragment is _incremental,_ meaning it may not be available right away. ```tsx // gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query' } & { ' $fragmentRefs'?: { OrdersFragment: Incremental } }) ``` Apart from generating code that includes support for the `@defer` directive, the Codegen also exports a utility function called `isFragmentReady`. You can use it to conditionally render components based on whether the data for a deferred fragment is available: ```jsx const OrdersList = (props: { data: FragmentType }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && } )} ); } export default App; ``` ### Patch Changes - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96), [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c), [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d), [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0), [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c)]: - @graphql-codegen/plugin-helpers@5.0.0 - @graphql-codegen/visitor-plugin-common@4.0.0 ## 4.0.1 ### Patch Changes - Updated dependencies [[`386cf9044`](https://github.com/dotansimha/graphql-code-generator/commit/386cf9044a41d87ed45069b22d26b30f4b262a85), [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00)]: - @graphql-codegen/visitor-plugin-common@3.1.1 ## 4.0.0 ### Major Changes - [#9137](https://github.com/dotansimha/graphql-code-generator/pull/9137) [`2256c8b5d`](https://github.com/dotansimha/graphql-code-generator/commit/2256c8b5d0e13057d35692bbeba3b7b8f94d8712) Thanks [@beerose](https://github.com/beerose)! - Add `TypedDocumentNode` string alternative that doesn't require GraphQL AST on the client. This change requires `@graphql-typed-document-node/core` in version `3.2.0` or higher. ### Patch Changes - Updated dependencies [[`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835), [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087), [`acb647e4e`](https://github.com/dotansimha/graphql-code-generator/commit/acb647e4efbddecf732b6e55dc47ac40c9bdaf08), [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd)]: - @graphql-codegen/visitor-plugin-common@3.1.0 - @graphql-codegen/plugin-helpers@4.2.0 ## 3.0.2 ### Patch Changes - Updated dependencies [[`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a), [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc), [`b343626c9`](https://github.com/dotansimha/graphql-code-generator/commit/b343626c978b9ee0f14e314cea6c01ae3dad057c)]: - @graphql-codegen/visitor-plugin-common@3.0.2 ## 3.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - [#8971](https://github.com/dotansimha/graphql-code-generator/pull/8971) [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Allow passing fragment documents to APIs like Apollos `readFragment` - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 - @graphql-codegen/visitor-plugin-common@3.0.1 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/visitor-plugin-common@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 ## 2.3.13 ### Patch Changes - Updated dependencies [[`a98198524`](https://github.com/dotansimha/graphql-code-generator/commit/a9819852443884b43de7c15040ccffc205f9177a)]: - @graphql-codegen/visitor-plugin-common@2.13.8 ## 2.3.12 ### Patch Changes - Updated dependencies [[`eb454d06c`](https://github.com/dotansimha/graphql-code-generator/commit/eb454d06c977f11f7d4a7b0b07eb80f8fd590560)]: - @graphql-codegen/visitor-plugin-common@2.13.7 ## 2.3.11 ### Patch Changes - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 - @graphql-codegen/visitor-plugin-common@2.13.6 ## 2.3.10 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/visitor-plugin-common@2.13.5 ## 2.3.9 ### Patch Changes - [#8686](https://github.com/dotansimha/graphql-code-generator/pull/8686) [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`change-case-all@1.0.15` ↗︎](https://www.npmjs.com/package/change-case-all/v/1.0.15) (from `1.0.14`, in `dependencies`) - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/visitor-plugin-common@2.13.4 ## 2.3.8 ### Patch Changes - Updated dependencies [[`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe)]: - @graphql-codegen/visitor-plugin-common@2.13.3 ## 2.3.7 ### Patch Changes - Updated dependencies [[`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122)]: - @graphql-codegen/visitor-plugin-common@2.13.2 ## 2.3.6 ### Patch Changes - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/visitor-plugin-common@2.13.1 - @graphql-codegen/plugin-helpers@2.7.2 ## 2.3.5 ### Patch Changes - Updated dependencies [[`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b)]: - @graphql-codegen/visitor-plugin-common@2.13.0 ## 2.3.4 ### Patch Changes - Updated dependencies [[`1bd7f771c`](https://github.com/dotansimha/graphql-code-generator/commit/1bd7f771ccb949a5a37395c7c57cb41c19340714)]: - @graphql-codegen/visitor-plugin-common@2.12.2 ## 2.3.3 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f), [`47d0a57e2`](https://github.com/dotansimha/graphql-code-generator/commit/47d0a57e27dd0d2334670bfc6c81c45e00ff4e74)]: - @graphql-codegen/visitor-plugin-common@2.12.1 - @graphql-codegen/plugin-helpers@2.6.2 ## 2.3.2 ### Patch Changes - Updated dependencies [2cbcbb371] - @graphql-codegen/visitor-plugin-common@2.12.0 - @graphql-codegen/plugin-helpers@2.6.0 ## 2.3.1 ### Patch Changes - Updated dependencies [525ad580b] - @graphql-codegen/visitor-plugin-common@2.11.1 ## 2.3.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [68bb30e19] - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/visitor-plugin-common@2.11.0 - @graphql-codegen/plugin-helpers@2.5.0 ## 2.2.14 ### Patch Changes - Updated dependencies [aa1e6eafd] - Updated dependencies [a42fcbfe4] - Updated dependencies [8b10f22be] - @graphql-codegen/visitor-plugin-common@2.10.0 ## 2.2.13 ### Patch Changes - Updated dependencies [d16bebacb] - @graphql-codegen/visitor-plugin-common@2.9.1 ## 2.2.12 ### Patch Changes - Updated dependencies [c3d7b7226] - @graphql-codegen/visitor-plugin-common@2.9.0 ## 2.2.11 ### Patch Changes - Updated dependencies [f1fb77bd4] - @graphql-codegen/visitor-plugin-common@2.8.0 ## 2.2.10 ### Patch Changes - Updated dependencies [9a5f31cb6] - @graphql-codegen/visitor-plugin-common@2.7.6 ## 2.2.9 ### Patch Changes - Updated dependencies [2966686e9] - @graphql-codegen/visitor-plugin-common@2.7.5 ## 2.2.8 ### Patch Changes - Updated dependencies [337fd4f77] - @graphql-codegen/visitor-plugin-common@2.7.4 ## 2.2.7 ### Patch Changes - Updated dependencies [54718c039] - @graphql-codegen/visitor-plugin-common@2.7.3 ## 2.2.6 ### Patch Changes - Updated dependencies [11d05e361] - @graphql-codegen/visitor-plugin-common@2.7.2 ## 2.2.5 ### Patch Changes - Updated dependencies [fd55e2039] - @graphql-codegen/visitor-plugin-common@2.7.1 ## 2.2.4 ### Patch Changes - Updated dependencies [1479233df] - @graphql-codegen/visitor-plugin-common@2.7.0 ## 2.2.3 ### Patch Changes - Updated dependencies [c8ef37ae0] - Updated dependencies [754a33715] - Updated dependencies [bef4376d5] - Updated dependencies [be7cb3a82] - @graphql-codegen/visitor-plugin-common@2.6.0 - @graphql-codegen/plugin-helpers@2.4.0 ## 2.2.2 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/visitor-plugin-common@2.5.2 - @graphql-codegen/plugin-helpers@2.3.2 ## 2.2.1 ### Patch Changes - Updated dependencies [a9f1f1594] - Updated dependencies [9ea6621ec] - @graphql-codegen/visitor-plugin-common@2.5.1 ## 2.2.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/visitor-plugin-common@2.5.0 - @graphql-codegen/plugin-helpers@2.3.0 ## 2.1.6 ### Patch Changes - Updated dependencies [ad02cb9b8] - @graphql-codegen/visitor-plugin-common@2.4.0 ## 2.1.5 ### Patch Changes - Updated dependencies [b9e85adae] - Updated dependencies [7c60e5acc] - Updated dependencies [3c2c847be] - @graphql-codegen/visitor-plugin-common@2.3.0 - @graphql-codegen/plugin-helpers@2.2.0 ## 2.1.4 ### Patch Changes - Updated dependencies [0b090e31a] - @graphql-codegen/visitor-plugin-common@2.2.1 ## 2.1.3 ### Patch Changes - Updated dependencies [d6c2d4c09] - Updated dependencies [feeae1c66] - Updated dependencies [5086791ac] - @graphql-codegen/visitor-plugin-common@2.2.0 ## 2.1.2 ### Patch Changes - Updated dependencies [6470e6cc9] - Updated dependencies [263570e50] - Updated dependencies [35199dedf] - @graphql-codegen/visitor-plugin-common@2.1.2 - @graphql-codegen/plugin-helpers@2.1.1 ## 2.1.1 ### Patch Changes - Updated dependencies [aabeff181] - @graphql-codegen/visitor-plugin-common@2.1.1 ## 2.1.0 ### Minor Changes - 440172cfe: support ESM ### Patch Changes - 440172cfe: export config types - Updated dependencies [290170262] - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/visitor-plugin-common@2.1.0 - @graphql-codegen/plugin-helpers@2.1.0 ## 2.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Minor Changes - bbdad95fd: Generation of `__typename` for SelectionSet by `addTypenameToSelectionSets` parameter ### Patch Changes - Updated dependencies [d80efdec4] - Updated dependencies [d80efdec4] - Updated dependencies [b0cb13df4] - @graphql-codegen/visitor-plugin-common@2.0.0 - @graphql-codegen/plugin-helpers@2.0.0 ## 1.18.10 ### Patch Changes - Updated dependencies [df19a4ed] - Updated dependencies [470336a1] - Updated dependencies [9005cc17] - @graphql-codegen/visitor-plugin-common@1.22.0 - @graphql-codegen/plugin-helpers@1.18.8 ## 1.18.9 ### Patch Changes - Updated dependencies [6762aff5] - @graphql-codegen/visitor-plugin-common@1.21.3 ## 1.18.8 ### Patch Changes - Updated dependencies [6aaecf1c] - @graphql-codegen/visitor-plugin-common@1.21.2 ## 1.18.7 ### Patch Changes - cf1e5abc: Introduce new feature for removing duplicated fragments - Updated dependencies [cf1e5abc] - @graphql-codegen/visitor-plugin-common@1.21.1 ## 1.18.6 ### Patch Changes - Updated dependencies [dfd25caf] - Updated dependencies [8da7dff6] - @graphql-codegen/visitor-plugin-common@1.21.0 - @graphql-codegen/plugin-helpers@1.18.7 ## 1.18.5 ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - Updated dependencies [f0b5ea53] - Updated dependencies [097bea2f] - @graphql-codegen/visitor-plugin-common@1.20.0 - @graphql-codegen/plugin-helpers@1.18.5 ## 1.18.4 ### Patch Changes - 23862e7e: fix(naming-convention): revert and pin change-case-all dependency for workaround #3256 - Updated dependencies [23862e7e] - @graphql-codegen/visitor-plugin-common@1.19.1 - @graphql-codegen/plugin-helpers@1.18.4 ## 1.18.3 ### Patch Changes - 29b75b1e: enhance(namingConvention): use change-case-all instead of individual packages for naming convention - Updated dependencies [e947f8e3] - Updated dependencies [29b75b1e] - Updated dependencies [d4942d04] - Updated dependencies [1f6f3db6] - Updated dependencies [29b75b1e] - @graphql-codegen/visitor-plugin-common@1.19.0 - @graphql-codegen/plugin-helpers@1.18.3 ## 1.18.2 ### Patch Changes - 99533389: Enable flattening typed document nodes - Updated dependencies [64293437] - Updated dependencies [fd5843a7] - Updated dependencies [d75051f5] - @graphql-codegen/visitor-plugin-common@1.17.22 ## 1.18.1 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/visitor-plugin-common@1.17.20 - @graphql-codegen/plugin-helpers@1.18.2 ## 1.18.0 ### Minor Changes - bd3bd296: Improve DocumentNode optimizations, to reduce bundle size when consumed as pre-compiled ### Patch Changes - Updated dependencies [99819bf1] - Updated dependencies [c3b59e81] - @graphql-codegen/visitor-plugin-common@1.17.19 ## 1.17.10 ### Patch Changes - 3e3941b9: Avoid printing imports when there are no operations - Updated dependencies [612e5e52] - Updated dependencies [9f2a4e2f] - Updated dependencies [0f35e775] - Updated dependencies [eaf45d1f] - @graphql-codegen/visitor-plugin-common@1.17.17 - @graphql-codegen/plugin-helpers@1.18.1 ## 1.17.9 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/visitor-plugin-common@1.17.13 - @graphql-codegen/plugin-helpers@1.17.8 ## 1.17.8 ### Patch Changes - 4266a15f: Allow this plugin to work with `documentMode: graphqlTag` correctly. Added validation for preventing `documentMode: string` because it's not supported in this plugin. - Updated dependencies [4266a15f] - @graphql-codegen/visitor-plugin-common@1.17.12 ================================================ FILE: packages/plugins/typescript/typed-document-node/package.json ================================================ { "name": "@graphql-codegen/typed-document-node", "version": "6.1.7", "description": "GraphQL Code Generator plugin for generating ready-to-use TypedDocumentNode based on GraphQL operations", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/typescript/typed-document-node" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "dependencies": { "change-case-all": "1.0.15", "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-codegen/visitor-plugin-common": "^6.2.4", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/typescript/typed-document-node/src/config.ts ================================================ import { RawClientSideBasePluginConfig } from '@graphql-codegen/visitor-plugin-common'; export interface TypeScriptTypedDocumentNodesConfig extends RawClientSideBasePluginConfig { /** * @description Flatten fragment spread and inline fragments into a simple selection set before generating. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-operations'], * config: { * flattenGeneratedTypes: true * }, * }, * }, * }; * export default config; * ``` */ flattenGeneratedTypes?: boolean; /** * @description Add __typename to selection set * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-operations'], * config: { * addTypenameToSelectionSets: true * }, * }, * }, * }; * export default config; * ``` */ addTypenameToSelectionSets?: boolean; /** * @description Allows you to import the operation types from a different file. * @default "" * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-operations'] * }, * 'path/to/file2.ts': { * plugins: ['typed-document-node'], * config: { * importOperationTypesFrom: 'path/to/file.ts' * }, * }, * }, * }; * export default config; * ``` */ importOperationTypesFrom?: string; } ================================================ FILE: packages/plugins/typescript/typed-document-node/src/index.ts ================================================ import { extname } from 'path'; import { oldVisit, PluginFunction, PluginValidateFn, Types } from '@graphql-codegen/plugin-helpers'; import { DocumentMode, LoadedFragment, optimizeOperations, RawClientSideBasePluginConfig, } from '@graphql-codegen/visitor-plugin-common'; import { concatAST, FragmentDefinitionNode, GraphQLSchema, Kind } from 'graphql'; import { TypeScriptTypedDocumentNodesConfig } from './config.js'; import { TypeScriptDocumentNodesVisitor } from './visitor.js'; export const plugin: PluginFunction = ( schema: GraphQLSchema, rawDocuments: Types.DocumentFile[], config: TypeScriptTypedDocumentNodesConfig ) => { const documents = config.flattenGeneratedTypes ? optimizeOperations(schema, rawDocuments) : rawDocuments; const allAst = concatAST(documents.map(v => v.document)); const allFragments: LoadedFragment[] = [ ...(allAst.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION) as FragmentDefinitionNode[]).map( fragmentDef => ({ node: fragmentDef, name: fragmentDef.name.value, onType: fragmentDef.typeCondition.name.value, isExternal: false, }) ), ...(config.externalFragments || []), ]; const visitor = new TypeScriptDocumentNodesVisitor(schema, allFragments, config, documents); const visitorResult = oldVisit(allAst, { leave: visitor }); let content: string[] = []; if (config.documentMode === DocumentMode.string) { content = [ `\ export class TypedDocumentString extends String implements DocumentTypeDecoration { __apiType?: NonNullable['__apiType']>; private value: string; public __meta__?: Record | undefined; constructor(value: string, __meta__?: Record | undefined) { super(value); this.value = value; this.__meta__ = __meta__; } override toString(): string & DocumentTypeDecoration { return this.value; } }`, ]; } return { prepend: allAst.definitions.length === 0 ? [] : visitor.getImports(), content: [...content, visitor.fragments, ...visitorResult.definitions.filter(t => typeof t === 'string')].join( '\n' ), }; }; export const validate: PluginValidateFn = async ( _schema: GraphQLSchema, _documents: Types.DocumentFile[], _config, outputFile: string ) => { if (extname(outputFile) !== '.ts' && extname(outputFile) !== '.tsx') { throw new Error(`Plugin "typed-document-node" requires extension to be ".ts" or ".tsx"!`); } }; export { TypeScriptTypedDocumentNodesConfig }; ================================================ FILE: packages/plugins/typescript/typed-document-node/src/visitor.ts ================================================ import { Types } from '@graphql-codegen/plugin-helpers'; import { ClientSideBasePluginConfig, ClientSideBaseVisitor, DocumentMode, LoadedFragment, RawClientSideBasePluginConfig, } from '@graphql-codegen/visitor-plugin-common'; import autoBind from 'auto-bind'; import { GraphQLSchema } from 'graphql'; interface TypeScriptDocumentNodesVisitorPluginConfig extends RawClientSideBasePluginConfig { addTypenameToSelectionSets?: boolean; } export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor< TypeScriptDocumentNodesVisitorPluginConfig, ClientSideBasePluginConfig > { private pluginConfig: TypeScriptDocumentNodesVisitorPluginConfig; constructor( schema: GraphQLSchema, fragments: LoadedFragment[], config: TypeScriptDocumentNodesVisitorPluginConfig, documents: Types.DocumentFile[] ) { super( schema, fragments, { documentNodeImport: '@graphql-typed-document-node/core#TypedDocumentNode', ...config, documentMode: config.documentMode || DocumentMode.documentNodeImportFragments, }, {}, documents ); this.pluginConfig = config; autoBind(this); // We need to make sure it's there because in this mode, the base plugin doesn't add the import if (this.config.documentMode === DocumentMode.graphQLTag) { const documentNodeImport = this._parseImport(this.config.documentNodeImport || 'graphql#DocumentNode'); const tagImport = this._generateImport(documentNodeImport, 'DocumentNode', true); this._imports.add(tagImport); } else if (this.config.documentMode === DocumentMode.string) { const tagImport = this._generateImport( { moduleName: '@graphql-typed-document-node/core', propName: 'DocumentTypeDecoration' }, 'DocumentTypeDecoration', true ); this._imports.add(tagImport); } } public SelectionSet(node, _, parent) { if (!this.pluginConfig.addTypenameToSelectionSets) { return; } // Don't add __typename to OperationDefinitions. if (parent && parent.kind === 'OperationDefinition') { return; } // No changes if no selections. const { selections } = node; if (!selections) { return; } // If selections already have a __typename or is introspection do nothing. const hasTypename = selections.some( selection => selection.kind === 'Field' && (selection.name.value === '__typename' || selection.name.value.lastIndexOf('__', 0) === 0) ); if (hasTypename) { return; } return { ...node, selections: [ ...selections, { kind: 'Field', name: { kind: 'Name', value: '__typename', }, }, ], }; } protected getDocumentNodeSignature(resultType: string, variablesTypes: string, node) { const shouldUseImportPrefix = !!this.config.importOperationTypesFrom; const resultImportPrefix = shouldUseImportPrefix && resultType !== 'unknown' ? 'Types.' : ''; const variablesImportPrefix = shouldUseImportPrefix && variablesTypes !== 'unknown' ? 'Types.' : ''; if ( this.config.documentMode === DocumentMode.documentNode || this.config.documentMode === DocumentMode.documentNodeImportFragments || this.config.documentMode === DocumentMode.graphQLTag ) { return ` as unknown as DocumentNode<${resultImportPrefix}${resultType}, ${variablesImportPrefix}${variablesTypes}>`; } if (this.config.documentMode === DocumentMode.string) { return ` as unknown as TypedDocumentString<${resultImportPrefix}${resultType}, ${variablesImportPrefix}${variablesTypes}>`; } return super.getDocumentNodeSignature(resultType, variablesTypes, node); } } ================================================ FILE: packages/plugins/typescript/typed-document-node/tests/typed-document-node.spec.ts ================================================ import { Types } from '@graphql-codegen/plugin-helpers'; import { buildSchema, parse } from 'graphql'; import { plugin } from '../src/index.js'; describe('TypedDocumentNode', () => { it('Should not output imports when there are no operations at all', async () => { const result = (await plugin(null as any, [], {})) as Types.ComplexPluginOutput; expect(result.content).toBe(''); expect(result.prepend.length).toBe(0); }); describe('addTypenameToSelectionSets', () => { it('Check is add __typename to typed document', async () => { const schema = buildSchema(/* GraphQL */ ` schema { query: Query } type Query { job: Job } type Job { id: ID! } `); const ast = parse(/* GraphQL */ ` query { job { id } } `); const res = (await plugin( schema, [{ location: '', document: ast }], { addTypenameToSelectionSets: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect((res.content.match(/__typename/g) || []).length).toBe(1); }); it('Check with __typename in selection set', async () => { const schema = buildSchema(/* GraphQL */ ` schema { query: Query } type Query { job: Job } type Job { id: ID! } `); const ast = parse(/* GraphQL */ ` query { job { id __typename } } `); const res = (await plugin( schema, [{ location: '', document: ast }], { addTypenameToSelectionSets: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect((res.content.match(/__typename/g) || []).length).toBe(1); }); }); describe('addTypenameToSelectionSets', () => { it('Should import Types from the given file', async () => { const schema = buildSchema(/* GraphQL */ ` schema { query: Query } type Query { job: Job } type Job { id: ID! } `); const ast = parse(/* GraphQL */ ` query { job { ...JobFragment } } fragment JobFragment on Job { id } `); const res = (await plugin( schema, [{ location: '', document: ast }], { importOperationTypesFrom: 'file.ts' }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect((res.content.match(//g) || []).length).toBe(1); expect((res.content.match(//g) || []).length).toBe(1); }); }); }); ================================================ FILE: packages/plugins/typescript/typed-document-node/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'typed-document-node', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/plugins/typescript/typescript/CHANGELOG.md ================================================ # @graphql-codegen/typescript ## 5.0.9 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-codegen/visitor-plugin-common@^6.2.3` ↗︎](https://www.npmjs.com/package/@graphql-codegen/visitor-plugin-common/v/6.2.3) (from `6.2.3`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 - @graphql-codegen/schema-ast@5.0.1 - @graphql-codegen/visitor-plugin-common@6.2.4 ## 5.0.8 ### Patch Changes - Updated dependencies [[`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf)]: - @graphql-codegen/visitor-plugin-common@6.2.3 ## 5.0.7 ### Patch Changes - Updated dependencies [[`f588d91`](https://github.com/dotansimha/graphql-code-generator/commit/f588d91ac43ea0aa5931915ce980d2e6876bb59c)]: - @graphql-codegen/visitor-plugin-common@6.2.2 ## 5.0.6 ### Patch Changes - Updated dependencies [[`b995ed1`](https://github.com/dotansimha/graphql-code-generator/commit/b995ed13a49379ea05e0e313fac68b557527523a)]: - @graphql-codegen/visitor-plugin-common@6.2.1 ## 5.0.5 ### Patch Changes - Updated dependencies [[`f821e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f821e8ab9351f23a9f7e5d5e6fc69c8e8868cad8), [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/visitor-plugin-common@6.2.0 - @graphql-codegen/plugin-helpers@6.1.0 ## 5.0.4 ### Patch Changes - Updated dependencies [[`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d)]: - @graphql-codegen/visitor-plugin-common@6.1.2 ## 5.0.3 ### Patch Changes - Updated dependencies [[`6715330`](https://github.com/dotansimha/graphql-code-generator/commit/67153304646694d75aee24afd70c3fce12e9f1f2)]: - @graphql-codegen/visitor-plugin-common@6.1.1 ## 5.0.2 ### Patch Changes - Updated dependencies [[`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26)]: - @graphql-codegen/visitor-plugin-common@6.1.0 ## 5.0.1 ### Patch Changes - Updated dependencies [[`accdab6`](https://github.com/dotansimha/graphql-code-generator/commit/accdab69106605241933e9d66d64dc7077656f30)]: - @graphql-codegen/visitor-plugin-common@6.0.1 ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Remove NameNode override - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/visitor-plugin-common@6.0.0 - @graphql-codegen/plugin-helpers@6.0.0 - @graphql-codegen/schema-ast@5.0.0 ## 4.1.6 ### Patch Changes - Updated dependencies [[`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc)]: - @graphql-codegen/visitor-plugin-common@5.8.0 ## 4.1.5 ### Patch Changes - Updated dependencies [[`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a)]: - @graphql-codegen/visitor-plugin-common@5.7.1 ## 4.1.4 ### Patch Changes - Updated dependencies [[`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c)]: - @graphql-codegen/visitor-plugin-common@5.7.0 ## 4.1.3 ### Patch Changes - Updated dependencies [[`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517)]: - @graphql-codegen/visitor-plugin-common@5.6.1 ## 4.1.2 ### Patch Changes - Updated dependencies [[`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a), [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba)]: - @graphql-codegen/visitor-plugin-common@5.6.0 ## 4.1.1 ### Patch Changes - Updated dependencies [[`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc), [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03)]: - @graphql-codegen/visitor-plugin-common@5.5.0 - @graphql-codegen/plugin-helpers@5.1.0 ## 4.1.0 ### Minor Changes - [#10077](https://github.com/dotansimha/graphql-code-generator/pull/10077) [`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4) Thanks [@eddeee888](https://github.com/eddeee888)! - Extend `config.avoidOptions` to support query, mutation and subscription Previously, `config.avoidOptions.resolvers` was being used to make query, mutation and subscription fields non-optional. Now, `config.avoidOptions.query`, `config.avoidOptions.mutation` and `config.avoidOptions.subscription` can be used to target the respective types. ### Patch Changes - Updated dependencies [[`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4)]: - @graphql-codegen/visitor-plugin-common@5.4.0 ## 4.0.9 ### Patch Changes - Updated dependencies [[`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2)]: - @graphql-codegen/visitor-plugin-common@5.3.1 ## 4.0.8 ### Patch Changes - Updated dependencies [[`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3), [`14ce39e`](https://github.com/dotansimha/graphql-code-generator/commit/14ce39e41dfee38c652be736664177fa2b1df421)]: - @graphql-codegen/visitor-plugin-common@5.3.0 ## 4.0.7 ### Patch Changes - Updated dependencies [[`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431), [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e)]: - @graphql-codegen/plugin-helpers@5.0.4 - @graphql-codegen/visitor-plugin-common@5.2.0 ## 4.0.6 ### Patch Changes - Updated dependencies [[`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53), [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d)]: - @graphql-codegen/visitor-plugin-common@5.1.0 ## 4.0.5 ### Patch Changes - Updated dependencies [[`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5)]: - @graphql-codegen/visitor-plugin-common@5.0.0 ## 4.0.4 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/visitor-plugin-common@4.1.2 - @graphql-codegen/schema-ast@4.0.2 - @graphql-codegen/plugin-helpers@5.0.3 ## 4.0.3 ### Patch Changes - Updated dependencies [[`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f)]: - @graphql-codegen/visitor-plugin-common@4.1.1 ## 4.0.2 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 - @graphql-codegen/schema-ast@4.0.1 - @graphql-codegen/visitor-plugin-common@4.1.0 ## 4.0.1 ### Patch Changes - [#9497](https://github.com/dotansimha/graphql-code-generator/pull/9497) [`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a) Thanks [@eddeee888](https://github.com/eddeee888)! - Revert default ID scalar input type to string We changed the ID Scalar input type from `string` to `string | number` in the latest major version of `typescript` plugin. This causes issues for server plugins (e.g. typescript-resolvers) that depends on `typescript` plugin. This is because the scalar type needs to be manually inverted on setup which is confusing. - Updated dependencies [[`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a)]: - @graphql-codegen/visitor-plugin-common@4.0.1 ## 4.0.0 ### Major Changes - [#9375](https://github.com/dotansimha/graphql-code-generator/pull/9375) [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929) Thanks [@eddeee888](https://github.com/eddeee888)! - Implement Scalars with input/output types In GraphQL, Scalar types can be different for client and server. For example, given the native GraphQL ID: - A client may send `string` or `number` in the input - A client receives `string` in its selection set (i.e output) - A server receives `string` in the resolver (GraphQL parses `string` or `number` received from the client to `string`) - A server may return `string` or `number` (GraphQL serializes the value to `string` before sending it to the client ) Currently, we represent every Scalar with only one type. This is what codegen generates as base type: ```ts export type Scalars = { ID: string } ``` Then, this is used in both input and output type e.g. ```ts export type Book = { __typename?: 'Book' id: Scalars['ID'] // Output's ID can be `string` 👍 } export type QueryBookArgs = { id: Scalars['ID'] // Input's ID can be `string` or `number`. However, the type is only `string` here 👎 } ``` This PR extends each Scalar to have input and output: ```ts export type Scalars = { ID: { input: string | number output: string } } ``` Then, each input/output GraphQL type can correctly refer to the correct input/output scalar type: ```ts export type Book = { __typename?: 'Book' id: Scalars['ID']['output'] // Output's ID can be `string` 👍 } export type QueryBookArgs = { id: Scalars['ID']['input'] // Input's ID can be `string` or `number` 👍 } ``` Note that for `typescript-resolvers`, the type of ID needs to be inverted. However, the referenced types in GraphQL input/output types should still work correctly: ```ts export type Scalars = { ID: { input: string; output: string | number; } } export type Book = { __typename?: "Book"; id: Scalars["ID"]['output']; // Resolvers can return `string` or `number` in ID fields 👍 }; export type QueryBookArgs = { id: Scalars["ID"]['input']; // Resolvers receive `string` in ID fields 👍 }; export type ResolversTypes = { ID: ID: ResolverTypeWrapper; // Resolvers can return `string` or `number` in ID fields 👍 } export type ResolversParentTypes = { ID: Scalars['ID']['output']; // Resolvers receive `string` or `number` from parents 👍 }; ``` *** Config changes: 1. Scalars option can now take input/output types: ```ts config: { scalars: { ID: { input: 'string', output: 'string | number' } } } ``` 2. If a string is given (instead of an object with input/output fields), it will be used as both input and output types: ```ts config: { scalars: { ID: 'string' // This means `string` will be used for both ID's input and output types } } ``` 3. BREAKING CHANGE: External module Scalar types need to be an object with input/output fields ```ts config: { scalars: { ID: './path/to/scalar-module' } } ``` If correctly, wired up, the following will be generated: ```ts // Previously, imported `ID` type can be a primitive type, now it must be an object with input/output fields import { ID } from './path/to/scalar-module' export type Scalars = { ID: { input: ID['input']; output: ID['output'] } } ``` *** BREAKING CHANGE: This changes Scalar types which could be referenced in other plugins. If you are a plugin maintainer and reference Scalar, please update your plugin to use the correct input/output types. - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Minor Changes - [#9196](https://github.com/dotansimha/graphql-code-generator/pull/9196) [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96) Thanks [@beerose](https://github.com/beerose)! - Add `@defer` directive support When a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved. Once start using the `@defer` directive in your queries, the generated code will automatically include support for the directive. ```jsx // src/index.tsx import { graphql } from './gql' const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `) const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `) ``` The generated type for `GetUserQuery` will have information that the fragment is _incremental,_ meaning it may not be available right away. ```tsx // gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query' } & { ' $fragmentRefs'?: { OrdersFragment: Incremental } }) ``` Apart from generating code that includes support for the `@defer` directive, the Codegen also exports a utility function called `isFragmentReady`. You can use it to conditionally render components based on whether the data for a deferred fragment is available: ```jsx const OrdersList = (props: { data: FragmentType }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && } )} ); } export default App; ``` - [#9304](https://github.com/dotansimha/graphql-code-generator/pull/9304) [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823) Thanks [@esfomeado](https://github.com/esfomeado)! - Added support for disabling suffixes on Enums. ### Patch Changes - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96), [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c), [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d), [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0), [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c)]: - @graphql-codegen/plugin-helpers@5.0.0 - @graphql-codegen/schema-ast@4.0.0 - @graphql-codegen/visitor-plugin-common@4.0.0 ## 3.0.4 ### Patch Changes - Updated dependencies [[`386cf9044`](https://github.com/dotansimha/graphql-code-generator/commit/386cf9044a41d87ed45069b22d26b30f4b262a85), [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00)]: - @graphql-codegen/visitor-plugin-common@3.1.1 ## 3.0.3 ### Patch Changes - [#9150](https://github.com/dotansimha/graphql-code-generator/pull/9150) [`92d86b009`](https://github.com/dotansimha/graphql-code-generator/commit/92d86b009579edf70f60b0b8e28658af93ff9fd1) Thanks [@rliljest](https://github.com/rliljest)! - Properly escape enum identifiers when enumsAsConst is used - Updated dependencies [[`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835), [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087), [`acb647e4e`](https://github.com/dotansimha/graphql-code-generator/commit/acb647e4efbddecf732b6e55dc47ac40c9bdaf08), [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd)]: - @graphql-codegen/visitor-plugin-common@3.1.0 - @graphql-codegen/plugin-helpers@4.2.0 ## 3.0.2 ### Patch Changes - Updated dependencies [[`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a), [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc), [`b343626c9`](https://github.com/dotansimha/graphql-code-generator/commit/b343626c978b9ee0f14e314cea6c01ae3dad057c)]: - @graphql-codegen/visitor-plugin-common@3.0.2 ## 3.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 - @graphql-codegen/schema-ast@3.0.1 - @graphql-codegen/visitor-plugin-common@3.0.1 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/visitor-plugin-common@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 - @graphql-codegen/schema-ast@3.0.0 ## 2.8.8 ### Patch Changes - Updated dependencies [[`a98198524`](https://github.com/dotansimha/graphql-code-generator/commit/a9819852443884b43de7c15040ccffc205f9177a)]: - @graphql-codegen/visitor-plugin-common@2.13.8 ## 2.8.7 ### Patch Changes - Updated dependencies [[`eb454d06c`](https://github.com/dotansimha/graphql-code-generator/commit/eb454d06c977f11f7d4a7b0b07eb80f8fd590560)]: - @graphql-codegen/visitor-plugin-common@2.13.7 ## 2.8.6 ### Patch Changes - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 - @graphql-codegen/schema-ast@2.6.1 - @graphql-codegen/visitor-plugin-common@2.13.6 ## 2.8.5 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`fedd71cbb`](https://github.com/dotansimha/graphql-code-generator/commit/fedd71cbb7f37440a59032d942cb228df78d52e5), [`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/schema-ast@2.6.0 - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/visitor-plugin-common@2.13.5 ## 2.8.4 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/visitor-plugin-common@2.13.4 - @graphql-codegen/schema-ast@2.5.2 ## 2.8.3 ### Patch Changes - Updated dependencies [[`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe)]: - @graphql-codegen/visitor-plugin-common@2.13.3 ## 2.8.2 ### Patch Changes - [#8586](https://github.com/dotansimha/graphql-code-generator/pull/8586) [`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122) Thanks [@levrik](https://github.com/levrik)! - Fix incompatibility between `@oneOf` input types and declaration kind other than `type` - Updated dependencies [[`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122)]: - @graphql-codegen/visitor-plugin-common@2.13.2 ## 2.8.1 ### Patch Changes - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/visitor-plugin-common@2.13.1 - @graphql-codegen/plugin-helpers@2.7.2 ## 2.8.0 ### Minor Changes - [#8390](https://github.com/dotansimha/graphql-code-generator/pull/8390) [`12ecbe067`](https://github.com/dotansimha/graphql-code-generator/commit/12ecbe067b37c340ffef99b96d487931be260f69) Thanks [@Diizzayy](https://github.com/Diizzayy)! - handle undefined namedType when including introspection type definitions ## 2.7.5 ### Patch Changes - Updated dependencies [[`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b)]: - @graphql-codegen/visitor-plugin-common@2.13.0 ## 2.7.4 ### Patch Changes - Updated dependencies [[`1bd7f771c`](https://github.com/dotansimha/graphql-code-generator/commit/1bd7f771ccb949a5a37395c7c57cb41c19340714)]: - @graphql-codegen/visitor-plugin-common@2.12.2 ## 2.7.3 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f), [`47d0a57e2`](https://github.com/dotansimha/graphql-code-generator/commit/47d0a57e27dd0d2334670bfc6c81c45e00ff4e74)]: - @graphql-codegen/schema-ast@2.5.1 - @graphql-codegen/visitor-plugin-common@2.12.1 - @graphql-codegen/plugin-helpers@2.6.2 ## 2.7.2 ### Patch Changes - Updated dependencies [2cbcbb371] - @graphql-codegen/visitor-plugin-common@2.12.0 - @graphql-codegen/plugin-helpers@2.6.0 ## 2.7.1 ### Patch Changes - Updated dependencies [525ad580b] - @graphql-codegen/visitor-plugin-common@2.11.1 ## 2.7.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [68bb30e19] - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/visitor-plugin-common@2.11.0 - @graphql-codegen/schema-ast@2.5.0 - @graphql-codegen/plugin-helpers@2.5.0 ## 2.6.0 ### Minor Changes - aa1e6eafd: Add @Deprecated support for input ### Patch Changes - 8b10f22be: Ensure falsy enum values are still mapped - Updated dependencies [aa1e6eafd] - Updated dependencies [a42fcbfe4] - Updated dependencies [8b10f22be] - @graphql-codegen/visitor-plugin-common@2.10.0 ## 2.5.1 ### Patch Changes - Updated dependencies [d16bebacb] - @graphql-codegen/visitor-plugin-common@2.9.1 ## 2.5.0 ### Minor Changes - c3d7b7226: support the `@oneOf` directive on input types. ### Patch Changes - Updated dependencies [c3d7b7226] - @graphql-codegen/visitor-plugin-common@2.9.0 ## 2.4.11 ### Patch Changes - Updated dependencies [f1fb77bd4] - @graphql-codegen/visitor-plugin-common@2.8.0 ## 2.4.10 ### Patch Changes - 9a5f31cb6: New option `onlyEnums` for Typescript - Updated dependencies [9a5f31cb6] - @graphql-codegen/visitor-plugin-common@2.7.6 ## 2.4.9 ### Patch Changes - Updated dependencies [2966686e9] - @graphql-codegen/visitor-plugin-common@2.7.5 ## 2.4.8 ### Patch Changes - Updated dependencies [337fd4f77] - @graphql-codegen/visitor-plugin-common@2.7.4 ## 2.4.7 ### Patch Changes - 54718c039: Improve @Deprecated Enum Type developer experience - Updated dependencies [54718c039] - @graphql-codegen/visitor-plugin-common@2.7.3 ## 2.4.6 ### Patch Changes - Updated dependencies [11d05e361] - @graphql-codegen/visitor-plugin-common@2.7.2 ## 2.4.5 ### Patch Changes - Updated dependencies [fd55e2039] - @graphql-codegen/visitor-plugin-common@2.7.1 ## 2.4.4 ### Patch Changes - Updated dependencies [1479233df] - @graphql-codegen/visitor-plugin-common@2.7.0 ## 2.4.3 ### Patch Changes - Updated dependencies [c8ef37ae0] - Updated dependencies [754a33715] - Updated dependencies [bef4376d5] - Updated dependencies [be7cb3a82] - @graphql-codegen/visitor-plugin-common@2.6.0 - @graphql-codegen/plugin-helpers@2.4.0 ## 2.4.2 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/schema-ast@2.4.1 - @graphql-codegen/visitor-plugin-common@2.5.2 - @graphql-codegen/plugin-helpers@2.3.2 ## 2.4.1 ### Patch Changes - Updated dependencies [a9f1f1594] - Updated dependencies [9ea6621ec] - @graphql-codegen/visitor-plugin-common@2.5.1 ## 2.4.0 ### Minor Changes - 4c5c84c1b: Added InputMaybe, a different type of Maybe type for input/arguments ## 2.3.1 ### Patch Changes - 6c898efe5: list all dependencies used by the package in the package.json - Updated dependencies [f3833243d] - Updated dependencies [6c898efe5] - @graphql-codegen/schema-ast@2.4.0 ## 2.3.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/visitor-plugin-common@2.5.0 - @graphql-codegen/plugin-helpers@2.3.0 ## 2.2.4 ### Patch Changes - Updated dependencies [ad02cb9b8] - @graphql-codegen/visitor-plugin-common@2.4.0 ## 2.2.3 ### Patch Changes - Updated dependencies [b9e85adae] - Updated dependencies [7c60e5acc] - Updated dependencies [3c2c847be] - @graphql-codegen/visitor-plugin-common@2.3.0 - @graphql-codegen/plugin-helpers@2.2.0 ## 2.2.2 ### Patch Changes - Updated dependencies [0b090e31a] - @graphql-codegen/visitor-plugin-common@2.2.1 ## 2.2.1 ### Patch Changes - cfa0a8f80: Apply missing namingConvention when numericEnums is used ## 2.2.0 ### Minor Changes - d6c2d4c09: Allow declaring Argument and InputType field mappings based on directive annotations. **WARNING:** Using this option does only change the type definitions. For actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://www.graphql-tools.com/docs/schema-directives)) that apply those rules! Otherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors. Please use this configuration option with care! ```yaml plugins: config: directiveArgumentAndInputFieldMappings: asNumber: number ``` ```graphql directive @asNumber on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION input MyInput { id: ID! @asNumber } type User { id: ID! } type Query { user(id: ID! @asNumber): User } ``` Usage e.g. with `typescript-resolvers` ```ts const Query: QueryResolvers = { user(_, args) { // args.id is of type 'number' } } ``` - 8261e4161: Make futureProofEnums option work for all enum output types, (it worked only with enumsAsTypes) ### Patch Changes - Updated dependencies [d6c2d4c09] - Updated dependencies [feeae1c66] - Updated dependencies [5086791ac] - @graphql-codegen/visitor-plugin-common@2.2.0 ## 2.1.2 ### Patch Changes - Updated dependencies [6470e6cc9] - Updated dependencies [263570e50] - Updated dependencies [35199dedf] - @graphql-codegen/visitor-plugin-common@2.1.2 - @graphql-codegen/plugin-helpers@2.1.1 ## 2.1.1 ### Patch Changes - Updated dependencies [aabeff181] - @graphql-codegen/visitor-plugin-common@2.1.1 ## 2.1.0 ### Minor Changes - 440172cfe: support ESM ### Patch Changes - Updated dependencies [290170262] - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/visitor-plugin-common@2.1.0 - @graphql-codegen/plugin-helpers@2.1.0 ## 2.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [d80efdec4] - Updated dependencies [d80efdec4] - Updated dependencies [b0cb13df4] - @graphql-codegen/visitor-plugin-common@2.0.0 - @graphql-codegen/plugin-helpers@2.0.0 ## 1.23.0 ### Minor Changes - 9005cc17: add `allowEnumStringTypes` option for allowing string literals as valid return types from resolvers in addition to enum values.\_ ### Patch Changes - Updated dependencies [df19a4ed] - Updated dependencies [470336a1] - Updated dependencies [9005cc17] - @graphql-codegen/visitor-plugin-common@1.22.0 - @graphql-codegen/plugin-helpers@1.18.8 ## 1.22.4 ### Patch Changes - Updated dependencies [6762aff5] - @graphql-codegen/visitor-plugin-common@1.21.3 ## 1.22.3 ### Patch Changes - Updated dependencies [6aaecf1c] - @graphql-codegen/visitor-plugin-common@1.21.2 ## 1.22.2 ### Patch Changes - Updated dependencies [cf1e5abc] - @graphql-codegen/visitor-plugin-common@1.21.1 ## 1.22.1 ### Patch Changes - Updated dependencies [dfd25caf] - Updated dependencies [8da7dff6] - @graphql-codegen/visitor-plugin-common@1.21.0 - @graphql-codegen/plugin-helpers@1.18.7 ## 1.22.0 ### Minor Changes - f0b5ea53: Add entireFieldWrapperValue configuration option, to wrap arrays - 097bea2f: Added new configuration settings for scalars: `strictScalars` and `defaultScalarType` ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - Updated dependencies [f0b5ea53] - Updated dependencies [097bea2f] - @graphql-codegen/visitor-plugin-common@1.20.0 - @graphql-codegen/plugin-helpers@1.18.5 ## 1.21.1 ### Patch Changes - e947f8e3: Allow to have declarationKind of type: class, interface: interface - 29b75b1e: enhance(namingConvention): use change-case-all instead of individual packages for naming convention - Updated dependencies [e947f8e3] - Updated dependencies [29b75b1e] - Updated dependencies [d4942d04] - Updated dependencies [1f6f3db6] - Updated dependencies [29b75b1e] - @graphql-codegen/visitor-plugin-common@1.19.0 - @graphql-codegen/plugin-helpers@1.18.3 ## 1.21.0 ### Minor Changes - 34b8087e: Adds futureProofUnion option to account for a possible unknown new type added to union types ### Patch Changes - Updated dependencies [5749cb8a] - Updated dependencies [5a12fe58] - @graphql-codegen/visitor-plugin-common@1.18.3 ## 1.20.2 ### Patch Changes - ca66569f: Fix issues with undefined calls for str.replace - Updated dependencies [ca66569f] - @graphql-codegen/visitor-plugin-common@1.18.2 ## 1.20.1 ### Patch Changes - 4444348d: Correctly escape enum values defined in the GraphQLSchema object - Updated dependencies [63be0f40] - Updated dependencies [190482a1] - Updated dependencies [4444348d] - Updated dependencies [142b32b3] - Updated dependencies [42213fa0] - @graphql-codegen/visitor-plugin-common@1.18.1 ## 1.20.0 ### Minor Changes - d95db95b: feat(typescript): bump visitor-plugin-common ## 1.19.0 ### Minor Changes - 1d6a593f: Added `useImplementingTypes` flag for generating code that uses implementing types instead of interfaces ### Patch Changes - Updated dependencies [8356f8a2] - @graphql-codegen/visitor-plugin-common@1.17.21 ## 1.18.1 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/visitor-plugin-common@1.17.20 - @graphql-codegen/plugin-helpers@1.18.2 ## 1.18.0 ### Minor Changes - 49242c20: Added a "defaultValue" option in the "avoidOptionals" config See https://github.com/dotansimha/graphql-code-generator/issues/5112 ### Patch Changes - Updated dependencies [99819bf1] - Updated dependencies [c3b59e81] - @graphql-codegen/visitor-plugin-common@1.17.19 ## 1.17.11 ### Patch Changes - 077cf064: Fixed reading of enumValues config values - 92d8f876: Fixed unquoted numeric enum identifiers - Updated dependencies [92d8f876] - @graphql-codegen/visitor-plugin-common@1.17.16 ## 1.17.10 ### Patch Changes - 7ad7a1ae: Make non nullable input field with default value optional - Updated dependencies [d2cde3d5] - Updated dependencies [89a6aa80] - Updated dependencies [f603b8f8] - Updated dependencies [da8bdd17] - @graphql-codegen/visitor-plugin-common@1.17.15 - @graphql-codegen/plugin-helpers@1.17.9 ## 1.17.9 ### Patch Changes - 07f9b1b2: Fix a bug caused numeric enum values defined in the GraphQLSchema to be printed incorrectly - Updated dependencies [07f9b1b2] - Updated dependencies [35f67120] - @graphql-codegen/visitor-plugin-common@1.17.14 ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments - Updated dependencies [1d7c6432] - Updated dependencies [1d7c6432] - @graphql-codegen/visitor-plugin-common@1.17.13 - @graphql-codegen/plugin-helpers@1.17.8 ================================================ FILE: packages/plugins/typescript/typescript/package.json ================================================ { "name": "@graphql-codegen/typescript", "version": "5.0.9", "description": "GraphQL Code Generator plugin for generating TypeScript types", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/plugins/typescript/typescript" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-codegen/schema-ast": "^5.0.1", "@graphql-codegen/visitor-plugin-common": "^6.2.4", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/plugins/typescript/typescript/src/config.ts ================================================ import { AvoidOptionalsConfig, RawTypesConfig } from '@graphql-codegen/visitor-plugin-common'; /** * @description This plugin generates the base TypeScript types, based on your GraphQL schema. * * The types generated by this plugin are simple, and refers to the exact structure of your schema, and it's used as the base types for other plugins (such as `typescript-operations` / `typescript-resolvers`) */ export interface TypeScriptPluginConfig extends RawTypesConfig { /** * @description This will cause the generator to avoid using TypeScript optionals (`?`) on types, * so the following definition: `type A { myField: String }` will output `myField: Maybe` * instead of `myField?: Maybe`. * @default false * * @exampleMarkdown * ## Override all definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * avoidOptionals: true * } * } * } * } * export default config * ``` * * ## Override only specific definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * avoidOptionals: { * field: true * inputValue: true * object: true * defaultValue: true * } * } * } * } * } * export default config * ``` */ avoidOptionals?: boolean | AvoidOptionalsConfig; /** * @description Will prefix every generated `enum` with `const`, you can read more about const enums here: https://www.typescriptlang.org/docs/handbook/enums.html. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * constEnums: true * } * } * } * } * export default config * ``` */ constEnums?: boolean; /** * @description Generates enum as TypeScript string union `type` instead of an `enum`. Useful if you wish to generate `.d.ts` declaration file instead of `.ts`, or if you want to avoid using TypeScript enums due to bundle size concerns * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * enumsAsTypes: true * } * } * } * } * export default config * ``` */ enumsAsTypes?: boolean; /** * @description Controls whether to preserve typescript enum values as numbers * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * numericEnums: true * } * } * } * } * export default config * ``` */ numericEnums?: boolean; /** * @description This option controls whether or not a catch-all entry is added to enum type definitions for values that may be added in the future. * This is useful if you are using `relay`. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * enumsAsTypes: true, * futureProofEnums: true * } * } * } * } * export default config * ``` */ futureProofEnums?: boolean; /** * @description This option controls whether or not a catch-all entry is added to union type definitions for values that may be added in the future. * This is useful if you are using `relay`. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * futureProofUnions: true * } * } * } * } * export default config * ``` */ futureProofUnions?: boolean; /** * @description Generates enum as TypeScript `const assertions` instead of `enum`. This can even be used to enable enum-like patterns in plain JavaScript code if you choose not to use TypeScript’s enum construct. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * enumsAsConst: true * } * } * } * } * export default config * ``` */ enumsAsConst?: boolean; /** * @description This will cause the generator to emit types for enums only. * @default false * * @exampleMarkdown * Override all definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * onlyEnums: true * } * } * } * } * export default config * ``` */ onlyEnums?: boolean; /** * @description This will cause the generator to emit types for operations only (basically only enums and scalars). * Interacts well with `preResolveTypes: true` * @default false * * @exampleMarkdown * Override all definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * onlyOperationTypes: true * } * } * } * } * export default config * ``` */ onlyOperationTypes?: boolean; /** * @description Generates immutable types by adding `readonly` to properties and uses `ReadonlyArray`. * @default false * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * immutableTypes: true * } * } * } * } * export default config * ``` */ immutableTypes?: boolean; /** * @description Allow to override the type value of `Maybe`. * @default T | null * * @exampleMarkdown * ## Allow undefined * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * maybeValue: 'T | null | undefined' * } * } * } * } * export default config * ``` * * ## Allow `null` in resolvers: * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript', 'typescript-resolvers'], * config: { * maybeValue: 'T extends PromiseLike ? Promise : T | null' * } * } * } * } * export default config * ``` */ maybeValue?: string; /** * @description Allow to override the type value of `Maybe` for input types and arguments. * This is useful in case you want to differentiate between the wrapper of input and output types. * By default, this type just refers to `Maybe` type, but you can override its definition. * * @default Maybe * * @exampleMarkdown * ## Allow undefined * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * inputMaybeValue: 'T | null | undefined' * } * } * } * } * export default config * ``` * * ## Allow `null` in resolvers: * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * inputMaybeValue: 'T extends PromiseLike ? Promise : T | null' * } * } * } * } * export default config * ``` */ inputMaybeValue?: string; /** * @description Set to `true` in order to generate output without `export` modifier. * This is useful if you are generating `.d.ts` file and want it to be globally available. * @default false * * @exampleMarkdown * ## Disable all export from a file * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * noExport: true * } * } * } * } * export default config * ``` */ noExport?: boolean; /** * @description Set the value to `true` in order to disable all description generation. * @default false * * @exampleMarkdown * ## Disable description generation * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * disableDescriptions: true * } * } * } * } * export default config * ``` */ disableDescriptions?: boolean; /** * @description When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself. * @default false * * @exampleMarkdown * ## Override all definition types * * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * useImplementingTypes: true * } * } * } * } * export default config * ``` */ useImplementingTypes?: boolean; /** * @name wrapEntireFieldDefinitions * @type boolean * @description Set to `true` in order to wrap field definitions with `EntireFieldWrapper`. * This is useful to allow return types such as Promises and functions for fields. * Differs from `wrapFieldDefinitions` in that this wraps the entire field definition if i.e. the field is an Array, while * `wrapFieldDefinitions` will wrap every single value inside the array. * @default false * * @example Enable wrapping entire fields * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * wrapEntireFieldDefinitions: true * } * } * } * } * export default config * ``` */ wrapEntireFieldDefinitions?: boolean; /** * @name entireFieldWrapperValue * @type string * @description Allow to override the type value of `EntireFieldWrapper`. This wrapper applies outside of Array and Maybe * unlike `fieldWrapperValue`, that will wrap the inner type. * @default T | Promise | (() => T | Promise) * * @example Only allow values * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * entireFieldWrapperValue: 'T' * } * } * } * } * export default config * ``` */ entireFieldWrapperValue?: string; /** * @description Allow using enum string values directly. * * @exampleMarkdown * ```ts filename="codegen.ts" * import type { CodegenConfig } from '@graphql-codegen/cli' * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * plugins: ['typescript'], * config: { * allowEnumStringTypes: true * } * } * } * } * export default config * ``` */ allowEnumStringTypes?: boolean; } ================================================ FILE: packages/plugins/typescript/typescript/src/index.ts ================================================ import { oldVisit, PluginFunction, Types } from '@graphql-codegen/plugin-helpers'; import { transformSchemaAST } from '@graphql-codegen/schema-ast'; import { DocumentNode, getNamedType, GraphQLNamedType, GraphQLSchema, isIntrospectionType, isObjectType, parse, printIntrospectionSchema, TypeInfo, visit, visitWithTypeInfo, } from 'graphql'; import { TypeScriptPluginConfig } from './config.js'; import { TsIntrospectionVisitor } from './introspection-visitor.js'; import { TsVisitor } from './visitor.js'; export * from './config.js'; export * from './introspection-visitor.js'; export * from './typescript-variables-to-object.js'; export * from './visitor.js'; export const plugin: PluginFunction = ( schema: GraphQLSchema, documents: Types.DocumentFile[], config: TypeScriptPluginConfig ) => { const { schema: _schema, ast } = transformSchemaAST(schema, config); const visitor = new TsVisitor(_schema, config); const visitorResult = oldVisit(ast, { leave: visitor }); const introspectionDefinitions = includeIntrospectionTypesDefinitions(_schema, documents, config); const scalars = visitor.scalarsDefinition; const directiveArgumentAndInputFieldMappings = visitor.directiveArgumentAndInputFieldMappingsDefinition; return { prepend: [ ...visitor.getEnumsImports(), ...visitor.getDirectiveArgumentAndInputFieldMappingsImports(), ...visitor.getScalarsImports(), ...visitor.getWrapperDefinitions(), ].filter(Boolean), content: [ scalars, directiveArgumentAndInputFieldMappings, ...visitorResult.definitions, ...introspectionDefinitions, ] .filter(Boolean) .join('\n'), }; }; export function includeIntrospectionTypesDefinitions( schema: GraphQLSchema, documents: Types.DocumentFile[], config: TypeScriptPluginConfig ): string[] { const typeInfo = new TypeInfo(schema); const usedTypes: GraphQLNamedType[] = []; const documentsVisitor = visitWithTypeInfo(typeInfo, { Field() { const type = getNamedType(typeInfo.getType()); if (type && isIntrospectionType(type) && !usedTypes.includes(type)) { usedTypes.push(type); } }, }); for (const doc of documents) { visit(doc.document, documentsVisitor); } const typesToInclude: GraphQLNamedType[] = []; for (const type of usedTypes) { collectTypes(type); } const visitor = new TsIntrospectionVisitor(schema, config, typesToInclude); const result: DocumentNode = oldVisit(parse(printIntrospectionSchema(schema)), { leave: visitor }); // recursively go through each `usedTypes` and their children and collect all used types // we don't care about Interfaces, Unions and others, but Objects and Enums function collectTypes(type: GraphQLNamedType): void { if (typesToInclude.includes(type)) { return; } typesToInclude.push(type); if (isObjectType(type)) { const fields = type.getFields(); for (const key of Object.keys(fields)) { const field = fields[key]; const type = getNamedType(field.type); collectTypes(type); } } } return result.definitions as any[]; } ================================================ FILE: packages/plugins/typescript/typescript/src/introspection-visitor.ts ================================================ import autoBind from 'auto-bind'; import { EnumTypeDefinitionNode, GraphQLNamedType, GraphQLSchema, ObjectTypeDefinitionNode } from 'graphql'; import { TypeScriptPluginConfig } from './config.js'; import { TsVisitor } from './visitor.js'; export class TsIntrospectionVisitor extends TsVisitor { private typesToInclude: GraphQLNamedType[] = []; constructor(schema: GraphQLSchema, pluginConfig: TypeScriptPluginConfig = {}, typesToInclude: GraphQLNamedType[]) { super(schema, pluginConfig); this.typesToInclude = typesToInclude; autoBind(this); } DirectiveDefinition() { return null; } ObjectTypeDefinition(node: ObjectTypeDefinitionNode, key: string | number, parent: any) { const name: string = node.name.value; if (this.typesToInclude.some(type => type.name === name)) { return super.ObjectTypeDefinition(node, key, parent); } return null; } EnumTypeDefinition(node: EnumTypeDefinitionNode): string { const name: string = node.name.value; if (this.typesToInclude.some(type => type.name === name)) { return super.EnumTypeDefinition(node); } return null; } } ================================================ FILE: packages/plugins/typescript/typescript/src/typescript-variables-to-object.ts ================================================ import { ConvertNameFn, NormalizedAvoidOptionalsConfig, NormalizedScalarsMap, OperationVariablesToObject, ParsedDirectiveArgumentAndInputFieldMappings, ParsedEnumValuesMap, } from '@graphql-codegen/visitor-plugin-common'; import { Kind, TypeNode } from 'graphql'; export class TypeScriptOperationVariablesToObject extends OperationVariablesToObject { constructor( _scalars: NormalizedScalarsMap, _convertName: ConvertNameFn, private _avoidOptionals: NormalizedAvoidOptionalsConfig, private _immutableTypes: boolean, _namespacedImportName: string | null = null, _enumNames: string[] = [], _enumPrefix = true, _enumSuffix = true, _enumValues: ParsedEnumValuesMap = {}, _applyCoercion: boolean = false, _directiveArgumentAndInputFieldMappings: ParsedDirectiveArgumentAndInputFieldMappings = {}, private _maybeType = 'Maybe' ) { super( _scalars, _convertName, _namespacedImportName, _enumNames, _enumPrefix, _enumSuffix, _enumValues, _applyCoercion, _directiveArgumentAndInputFieldMappings ); } private clearOptional(str: string): string { const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : ''; const rgx = new RegExp(`^${this.wrapMaybe(`(.*?)`)}$`, 'i'); if (str.startsWith(`${prefix}${this._maybeType}`)) { return str.replace(rgx, '$1'); } return str; } public wrapAstTypeWithModifiers(baseType: string, typeNode: TypeNode, applyCoercion = false): string { if (typeNode.kind === Kind.NON_NULL_TYPE) { const type = this.wrapAstTypeWithModifiers(baseType, typeNode.type, applyCoercion); return this.clearOptional(type); } if (typeNode.kind === Kind.LIST_TYPE) { const innerType = this.wrapAstTypeWithModifiers(baseType, typeNode.type, applyCoercion); const listInputCoercionExtension = applyCoercion ? ` | ${innerType}` : ''; return this.wrapMaybe( `${this._immutableTypes ? 'ReadonlyArray' : 'Array'}<${innerType}>${listInputCoercionExtension}` ); } return this.wrapMaybe(baseType); } protected formatFieldString(fieldName: string, isNonNullType: boolean, hasDefaultValue: boolean): string { return `${fieldName}${this.getAvoidOption(isNonNullType, hasDefaultValue) ? '?' : ''}`; } protected formatTypeString(fieldType: string, isNonNullType: boolean, hasDefaultValue: boolean): string { if (!hasDefaultValue && isNonNullType) { return this.clearOptional(fieldType); } return fieldType; } protected wrapMaybe(type?: string) { const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : ''; return `${prefix}${this._maybeType}${type ? `<${type}>` : ''}`; } protected getAvoidOption(isNonNullType: boolean, hasDefaultValue: boolean) { const options = this._avoidOptionals; return ((options.object || !options.defaultValue) && hasDefaultValue) || (!options.object && !isNonNullType); } protected getPunctuation(): string { return ';'; } } ================================================ FILE: packages/plugins/typescript/typescript/src/visitor.ts ================================================ import { BaseTypesVisitor, DeclarationBlock, DeclarationKind, getConfigValue, indent, isOneOfInputObjectType, normalizeAvoidOptionals, NormalizedAvoidOptionalsConfig, ParsedTypesConfig, transformComment, wrapWithSingleQuotes, } from '@graphql-codegen/visitor-plugin-common'; import autoBind from 'auto-bind'; import { EnumTypeDefinitionNode, FieldDefinitionNode, GraphQLObjectType, GraphQLSchema, InputValueDefinitionNode, isEnumType, Kind, ListTypeNode, NamedTypeNode, NonNullTypeNode, TypeDefinitionNode, UnionTypeDefinitionNode, } from 'graphql'; import { TypeScriptPluginConfig } from './config.js'; import { TypeScriptOperationVariablesToObject } from './typescript-variables-to-object.js'; export interface TypeScriptPluginParsedConfig extends ParsedTypesConfig { avoidOptionals: NormalizedAvoidOptionalsConfig; constEnums: boolean; enumsAsTypes: boolean; futureProofEnums: boolean; futureProofUnions: boolean; enumsAsConst: boolean; numericEnums: boolean; onlyEnums: boolean; onlyOperationTypes: boolean; immutableTypes: boolean; maybeValue: string; inputMaybeValue: string; noExport: boolean; useImplementingTypes: boolean; } export const EXACT_SIGNATURE = `type Exact = { [K in keyof T]: T[K] };`; export const MAKE_OPTIONAL_SIGNATURE = `type MakeOptional = Omit & { [SubKey in K]?: Maybe };`; export const MAKE_MAYBE_SIGNATURE = `type MakeMaybe = Omit & { [SubKey in K]: Maybe };`; export const MAKE_EMPTY_SIGNATURE = `type MakeEmpty = { [_ in K]?: never };`; export const MAKE_INCREMENTAL_SIGNATURE = `type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };`; export class TsVisitor< TRawConfig extends TypeScriptPluginConfig = TypeScriptPluginConfig, TParsedConfig extends TypeScriptPluginParsedConfig = TypeScriptPluginParsedConfig > extends BaseTypesVisitor { constructor(schema: GraphQLSchema, pluginConfig: TRawConfig, additionalConfig: Partial = {}) { super(schema, pluginConfig, { noExport: getConfigValue(pluginConfig.noExport, false), avoidOptionals: normalizeAvoidOptionals(getConfigValue(pluginConfig.avoidOptionals, false)), maybeValue: getConfigValue(pluginConfig.maybeValue, 'T | null'), inputMaybeValue: getConfigValue( pluginConfig.inputMaybeValue, getConfigValue(pluginConfig.maybeValue, 'Maybe') ), constEnums: getConfigValue(pluginConfig.constEnums, false), enumsAsTypes: getConfigValue(pluginConfig.enumsAsTypes, false), futureProofEnums: getConfigValue(pluginConfig.futureProofEnums, false), futureProofUnions: getConfigValue(pluginConfig.futureProofUnions, false), enumsAsConst: getConfigValue(pluginConfig.enumsAsConst, false), numericEnums: getConfigValue(pluginConfig.numericEnums, false), onlyEnums: getConfigValue(pluginConfig.onlyEnums, false), onlyOperationTypes: getConfigValue(pluginConfig.onlyOperationTypes, false), immutableTypes: getConfigValue(pluginConfig.immutableTypes, false), useImplementingTypes: getConfigValue(pluginConfig.useImplementingTypes, false), entireFieldWrapperValue: getConfigValue(pluginConfig.entireFieldWrapperValue, 'T'), wrapEntireDefinitions: getConfigValue(pluginConfig.wrapEntireFieldDefinitions, false), ...additionalConfig, } as TParsedConfig); autoBind(this); const enumNames = Object.values(schema.getTypeMap()) .filter(isEnumType) .map(type => type.name); this.setArgumentsTransformer( new TypeScriptOperationVariablesToObject( this.scalars, this.convertName, this.config.avoidOptionals, this.config.immutableTypes, null, enumNames, pluginConfig.enumPrefix, pluginConfig.enumSuffix, this.config.enumValues, false, this.config.directiveArgumentAndInputFieldMappings, 'InputMaybe' ) ); this.setDeclarationBlockConfig({ enumNameValueSeparator: ' =', ignoreExport: this.config.noExport, }); } protected _getTypeForNode(node: NamedTypeNode, isVisitingInputType: boolean): string { const typeAsString = node.name.value; if (this.config.useImplementingTypes) { const allTypesMap = this._schema.getTypeMap(); const implementingTypes: string[] = []; // TODO: Move this to a better place, since we are using this logic in some other places as well. for (const graphqlType of Object.values(allTypesMap)) { if (graphqlType instanceof GraphQLObjectType) { const allInterfaces = graphqlType.getInterfaces(); if (allInterfaces.some(int => typeAsString === int.name)) { implementingTypes.push(this.convertName(graphqlType.name)); } } } if (implementingTypes.length > 0) { return implementingTypes.join(' | '); } } const typeString = super._getTypeForNode(node, isVisitingInputType); const schemaType = this._schema.getType(node.name.value); if (isEnumType(schemaType)) { // futureProofEnums + enumsAsTypes combination adds the future value to the enum type itself // so it's not necessary to repeat it in the usage const futureProofEnumUsageEnabled = this.config.futureProofEnums === true && this.config.enumsAsTypes !== true; if (futureProofEnumUsageEnabled && this.config.allowEnumStringTypes === true) { return `${typeString} | '%future added value' | ` + '`${' + typeString + '}`'; } if (futureProofEnumUsageEnabled) { return `${typeString} | '%future added value'`; } if (this.config.allowEnumStringTypes === true) { return `${typeString} | ` + '`${' + typeString + '}`'; } } return typeString; } public getWrapperDefinitions(): string[] { if (this.config.onlyEnums) return []; const definitions: string[] = [ this.getMaybeValue(), this.getInputMaybeValue(), this.getExactDefinition(), this.getMakeOptionalDefinition(), this.getMakeMaybeDefinition(), this.getMakeEmptyDefinition(), this.getIncrementalDefinition(), ]; if (this.config.wrapFieldDefinitions) { definitions.push(this.getFieldWrapperValue()); } if (this.config.wrapEntireDefinitions) { definitions.push(this.getEntireFieldWrapperValue()); } return definitions; } public getExactDefinition(): string { if (this.config.onlyEnums) return ''; return `${this.getExportPrefix()}${EXACT_SIGNATURE}`; } public getMakeOptionalDefinition(): string { return `${this.getExportPrefix()}${MAKE_OPTIONAL_SIGNATURE}`; } public getMakeMaybeDefinition(): string { if (this.config.onlyEnums) return ''; return `${this.getExportPrefix()}${MAKE_MAYBE_SIGNATURE}`; } public getMakeEmptyDefinition(): string { return `${this.getExportPrefix()}${MAKE_EMPTY_SIGNATURE}`; } public getIncrementalDefinition(): string { return `${this.getExportPrefix()}${MAKE_INCREMENTAL_SIGNATURE}`; } public getMaybeValue(): string { return `${this.getExportPrefix()}type Maybe = ${this.config.maybeValue};`; } public getInputMaybeValue(): string { return `${this.getExportPrefix()}type InputMaybe = ${this.config.inputMaybeValue};`; } protected clearOptional(str: string): string { if (str.startsWith('Maybe')) { return str.replace(/Maybe<(.*?)>$/, '$1'); } if (str.startsWith('InputMaybe')) { return str.replace(/InputMaybe<(.*?)>$/, '$1'); } return str; } protected getExportPrefix(): string { if (this.config.noExport) { return ''; } return super.getExportPrefix(); } getMaybeWrapper(ancestors): string { const currentVisitContext = this.getVisitorKindContextFromAncestors(ancestors); const isInputContext = currentVisitContext.includes(Kind.INPUT_OBJECT_TYPE_DEFINITION); return isInputContext ? 'InputMaybe' : 'Maybe'; } NamedType(node: NamedTypeNode, key, parent, path, ancestors): string { return `${this.getMaybeWrapper(ancestors)}<${super.NamedType(node, key, parent, path, ancestors)}>`; } ListType(node: ListTypeNode, key, parent, path, ancestors): string { return `${this.getMaybeWrapper(ancestors)}<${super.ListType(node, key, parent, path, ancestors)}>`; } UnionTypeDefinition(node: UnionTypeDefinitionNode, key: string | number | undefined, parent: any): string { if (this.config.onlyOperationTypes || this.config.onlyEnums) return ''; let withFutureAddedValue: string[] = []; if (this.config.futureProofUnions) { withFutureAddedValue = [ this.config.immutableTypes ? `{ readonly __typename?: "%other" }` : `{ __typename?: "%other" }`, ]; } const originalNode = parent[key] as UnionTypeDefinitionNode; const possibleTypes = originalNode.types .map(t => (this.scalars[t.name.value] ? this._getScalar(t.name.value, 'output') : this.convertName(t))) .concat(...withFutureAddedValue) .join(' | '); return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind('type') .withName(this.convertName(node)) .withComment(node.description?.value) .withContent(possibleTypes).string; // return super.UnionTypeDefinition(node, key, parent).concat(withFutureAddedValue).join(""); } protected wrapWithListType(str: string): string { return `${this.config.immutableTypes ? 'ReadonlyArray' : 'Array'}<${str}>`; } NonNullType(node: NonNullTypeNode): string { const baseValue = super.NonNullType(node); return this.clearOptional(baseValue); } FieldDefinition(node: FieldDefinitionNode, key?: number | string, parent?: any): string { const typeString = this.config.wrapEntireDefinitions ? `EntireFieldWrapper<${node.type}>` : (node.type as any as string); const originalFieldNode = parent[key] as FieldDefinitionNode; const addOptionalSign = !this.config.avoidOptionals.field && originalFieldNode.type.kind !== Kind.NON_NULL_TYPE; const comment = this.getNodeComment(node); const { type } = this.config.declarationKind; return ( comment + indent( `${this.config.immutableTypes ? 'readonly ' : ''}${node.name.value}${ addOptionalSign ? '?' : '' }: ${typeString}${this.getPunctuation(type)}` ) ); } InputValueDefinition( node: InputValueDefinitionNode, key?: number | string, parent?: any, _path?: Array, ancestors?: Array ): string { const originalFieldNode = parent[key] as FieldDefinitionNode; const addOptionalSign = !this.config.avoidOptionals.inputValue && (originalFieldNode.type.kind !== Kind.NON_NULL_TYPE || (!this.config.avoidOptionals.defaultValue && node.defaultValue !== undefined)); const comment = this.getNodeComment(node); const declarationKind = this.config.declarationKind.type; let type: string = node.type as any as string; if (node.directives && this.config.directiveArgumentAndInputFieldMappings) { type = this._getDirectiveOverrideType(node.directives) || type; } const readonlyPrefix = this.config.immutableTypes ? 'readonly ' : ''; const buildFieldDefinition = (isOneOf = false) => { return `${readonlyPrefix}${node.name.value}${addOptionalSign && !isOneOf ? '?' : ''}: ${ isOneOf ? this.clearOptional(type) : type }${this.getPunctuation(declarationKind)}`; }; const realParentDef = ancestors?.[ancestors.length - 1]; if (realParentDef) { const parentType = this._schema.getType(realParentDef.name.value); if (isOneOfInputObjectType(parentType)) { if (originalFieldNode.type.kind === Kind.NON_NULL_TYPE) { throw new Error( 'Fields on an input object type can not be non-nullable. It seems like the schema was not validated.' ); } const fieldParts: Array = []; for (const fieldName of Object.keys(parentType.getFields())) { if (fieldName === node.name.value) { fieldParts.push(buildFieldDefinition(true)); continue; } fieldParts.push(`${readonlyPrefix}${fieldName}?: never;`); } return comment + indent(`{ ${fieldParts.join(' ')} }`); } } return comment + indent(buildFieldDefinition()); } EnumTypeDefinition(node: EnumTypeDefinitionNode): string { const enumName = node.name.value; // In case of mapped external enum string if (this.config.enumValues[enumName]?.sourceFile) { return `export { ${this.config.enumValues[enumName].typeIdentifier} };\n`; } const getValueFromConfig = (enumValue: string | number) => { if (typeof this.config.enumValues[enumName]?.mappedValues?.[enumValue] !== 'undefined') { return this.config.enumValues[enumName].mappedValues[enumValue]; } return null; }; const withFutureAddedValue = [ this.config.futureProofEnums ? [indent('| ' + wrapWithSingleQuotes('%future added value'))] : [], ]; const enumTypeName = this.convertName(node, { useTypesPrefix: this.config.enumPrefix, useTypesSuffix: this.config.enumSuffix, }); if (this.config.enumsAsTypes) { return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind('type') .withComment(node.description?.value) .withName(enumTypeName) .withContent( '\n' + node.values .map(enumOption => { const name = enumOption.name.value; const enumValue: string | number = getValueFromConfig(name) ?? name; const comment = transformComment(enumOption.description?.value, 1); return comment + indent('| ' + wrapWithSingleQuotes(enumValue)); }) .concat(...withFutureAddedValue) .join('\n') ).string; } if (this.config.numericEnums) { const block = new DeclarationBlock(this._declarationBlockConfig) .export() .withComment(node.description?.value) .withName(enumTypeName) .asKind('enum') .withBlock( node.values .map((enumOption, i) => { const valueFromConfig = getValueFromConfig(enumOption.name.value); const enumValue: string | number = valueFromConfig ?? i; const comment = transformComment(enumOption.description?.value, 1); const optionName = this.makeValidEnumIdentifier( this.convertName(enumOption, { useTypesPrefix: false, transformUnderscore: true, }) ); return comment + indent(optionName) + ` = ${enumValue}`; }) .concat(...withFutureAddedValue) .join(',\n') ).string; return block; } if (this.config.enumsAsConst) { const typeName = `export type ${enumTypeName} = typeof ${enumTypeName}[keyof typeof ${enumTypeName}];`; const enumAsConst = new DeclarationBlock({ ...this._declarationBlockConfig, blockTransformer: block => { return block + ' as const'; }, }) .export() .asKind('const') .withName(enumTypeName) .withComment(node.description?.value) .withBlock( node.values .map(enumOption => { const optionName = this.makeValidEnumIdentifier( this.convertName(enumOption, { useTypesPrefix: false, transformUnderscore: true, }) ); const comment = transformComment(enumOption.description?.value, 1); const name = enumOption.name.value; const enumValue: string | number = getValueFromConfig(name) ?? name; return comment + indent(`${optionName}: ${wrapWithSingleQuotes(enumValue)}`); }) .join(',\n') ).string; return [enumAsConst, typeName].join('\n'); } return new DeclarationBlock(this._declarationBlockConfig) .export() .asKind(this.config.constEnums ? 'const enum' : 'enum') .withName(enumTypeName) .withComment(node.description?.value) .withBlock(this.buildEnumValuesBlock(enumName, node.values)).string; } protected getPunctuation(_declarationKind: DeclarationKind): string { return ';'; } } ================================================ FILE: packages/plugins/typescript/typescript/tests/__snapshots__/typescript.spec.ts.snap ================================================ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`TypeScript > should use implementing types as node type - issue #5126 1`] = ` "/** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Matrix = { __typename?: 'Matrix'; pills: Array; }; export type Pill = { id: Scalars['ID']['output']; }; export type RedPill = Pill & { __typename?: 'RedPill'; red: Scalars['String']['output']; }; export type GreenPill = Pill & { __typename?: 'GreenPill'; green: Scalars['String']['output']; }; export type Foo = { id: Scalars['ID']['output']; }; export type Bar = Foo & { __typename?: 'Bar'; lol: Scalars['String']['output']; }; export type Hello = { __typename?: 'Hello'; foo: Bar; }; export type NoInterface = { __typename?: 'NoInterface'; hello: Hello; }; export type NestedInterface = { field: Scalars['String']['output']; }; export type NestedType1 = NestedInterface & { __typename?: 'NestedType1'; hi: Scalars['String']['output']; }; export type NestedType2 = NestedInterface & { __typename?: 'NestedType2'; ho: Scalars['String']['output']; }; export type NestedField = { __typename?: 'NestedField'; nested: NestedType1 | NestedType2; }; " `; ================================================ FILE: packages/plugins/typescript/typescript/tests/typescript.spec.ts ================================================ import { mergeOutputs, Types } from '@graphql-codegen/plugin-helpers'; import { validateTs } from '@graphql-codegen/testing'; import { buildSchema, GraphQLEnumType, GraphQLObjectType, GraphQLSchema, parse } from 'graphql'; import { plugin } from '../src/index.js'; describe('TypeScript', () => { it('should expose Maybe', async () => { const schema = buildSchema(/* GraphQL */ ` scalar A `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.prepend).toBeSimilarStringTo('export type Maybe ='); }); describe('description to comment', () => { it('Should include a description for Scalars type', async () => { const schema = buildSchema(/* GraphQL */ ` "My custom scalar" scalar A `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } /** My custom scalar */ A: { input: any; output: any; } }; `); }); it('Should add description for input types', async () => { const schema = buildSchema(/* GraphQL */ ` "MyInput" input MyInput { f: String } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.prepend).toBeSimilarStringTo('export type InputMaybe = Maybe;'); expect(result.content).toBeSimilarStringTo(` /** MyInput */ export type MyInput = { f?: InputMaybe; }`); }); it('Should add description for input fields', async () => { const schema = buildSchema(/* GraphQL */ ` "MyInput" input MyInput { "f is something" f: String! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` /** MyInput */ export type MyInput = { /** f is something */ f: Scalars['String']['input']; }`); }); it('Should work with multiline comment', async () => { const schema = buildSchema(/* GraphQL */ ` """ MyInput multiline """ input MyInput { f: String! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` /** * MyInput * multiline */ export type MyInput = { f: Scalars['String']['input']; }`); }); it('Should work with unions', async () => { const schema = buildSchema(/* GraphQL */ ` "my union" union A = B | C type B { id: ID } type C { id: ID } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` /** my union */ export type A = B | C`); }); it('Should work with types', async () => { const schema = buildSchema(/* GraphQL */ ` "this is b" type B { id: ID } "this is c" type C { id: ID } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` /** this is b */ export type B = { __typename?: 'B'; id?: Maybe; }`); expect(result.content).toBeSimilarStringTo(` /** this is c */ export type C = { __typename?: 'C'; id?: Maybe; }`); }); it('Should work with type fields', async () => { const schema = buildSchema(/* GraphQL */ ` type B { "the id" id: ID } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type B = { __typename?: 'B'; /** the id */ id?: Maybe; };`); }); it('Should work with inteface and inteface fields', async () => { const schema = buildSchema(/* GraphQL */ ` interface Node { "the id" id: ID! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type Node = { /** the id */ id: Scalars['ID']['output']; };`); }); it('Should work with enum and enum values', async () => { const schema = buildSchema(/* GraphQL */ ` "custom enum" enum MyEnum { "this is a" A "this is b" B } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` /** custom enum */ export enum MyEnum { /** this is a */ A = 'A', /** this is b */ B = 'B' }`); }); it('Should remove underscore from enum values', async () => { const schema = buildSchema(/* GraphQL */ ` enum MyEnum { A_B_C X_Y_Z _TEST My_Value } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export enum MyEnum { ABC = 'A_B_C', XYZ = 'X_Y_Z', Test = '_TEST', MyValue = 'My_Value' }`); }); it('Should leave underscores in enum values when the value is only underscores', async () => { const schema = buildSchema(/* GraphQL */ ` enum MyEnum { _ __ _TEST } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export enum MyEnum { _ = '_', __ = '__', Test = '_TEST' }`); }); it('Should work with enum as const', async () => { const schema = buildSchema(/* GraphQL */ ` enum MyEnum { A_B_C X_Y_Z _TEST My_Value _123 } `); const result = (await plugin( schema, [], { enumsAsConst: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const MyEnum = { ABC: 'A_B_C', XYZ: 'X_Y_Z', Test: '_TEST', MyValue: 'My_Value', '123': '_123' } as const; export type MyEnum = typeof MyEnum[keyof typeof MyEnum];`); }); it('Should work with enum as const combined with enum values', async () => { const schema = buildSchema(/* GraphQL */ ` enum MyEnum { A_B_C X_Y_Z _TEST My_Value } `); const result = (await plugin( schema, [], { enumsAsConst: true, enumValues: { MyEnum: { A_B_C: 0, X_Y_Z: 'Foo', _TEST: 'Bar', My_Value: 1, }, }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export const MyEnum = { ABC: 0, XYZ: 'Foo', Test: 'Bar', MyValue: 1 } as const; export type MyEnum = typeof MyEnum[keyof typeof MyEnum];`); }); it('Should work with enum and enum values (enumsAsTypes)', async () => { const schema = buildSchema(/* GraphQL */ ` "custom enum" enum MyEnum { "this is a" A "this is b" B } `); const result = (await plugin( schema, [], { enumsAsTypes: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` /** custom enum */ export type MyEnum = /** this is a */ | 'A' /** this is b */ | 'B';`); }); it('Should work with directives', async () => { const schema = buildSchema(/* GraphQL */ ` "My custom directive" directive @AsNumber on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION `); const result = await plugin( schema, [], { directiveArgumentAndInputFieldMappings: { AsNumber: 'number' } }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` /** Type overrides using directives */ export type DirectiveArgumentAndInputFieldMappings = { /** My custom directive */ AsNumber: number; }; `); }); }); describe('disable comment generation', () => { it('Should not include a description for Scalars type', async () => { const schema = buildSchema(/* GraphQL */ ` "My custom scalar" scalar A `); const result = await plugin(schema, [], { disableDescriptions: true }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo(`/** My custom scalar */`); expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } A: { input: any; output: any; } }; `); }); it('Should not add description for input types', async () => { const schema = buildSchema(/* GraphQL */ ` "MyInput" input MyInput { f: String } `); const result = await plugin(schema, [], { disableDescriptions: true }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo('/** MyInput */'); expect(result.content).toBeSimilarStringTo(` export type MyInput = { f?: InputMaybe; }`); }); it('Should not add description for input fields', async () => { const schema = buildSchema(/* GraphQL */ ` "MyInput" input MyInput { "f is something" f: String! } `); const result = await plugin(schema, [], { disableDescriptions: true }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo('/** MyInput */'); expect(result.content).not.toBeSimilarStringTo('/** f is something */'); expect(result.content).toBeSimilarStringTo(` export type MyInput = { f: Scalars['String']['input']; }`); }); it('Should remove multiline comment', async () => { const schema = buildSchema(/* GraphQL */ ` """ MyInput multiline """ input MyInput { f: String! } `); const result = await plugin(schema, [], { disableDescriptions: true }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo(` /** * MyInput * multiline */ `); expect(result.content).toBeSimilarStringTo(` export type MyInput = { f: Scalars['String']['input']; }`); }); it('Should work with unions', async () => { const schema = buildSchema(/* GraphQL */ ` "my union" union A = B | C type B { id: ID } type C { id: ID } `); const result = await plugin(schema, [], { disableDescriptions: true }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo('/** my union */'); expect(result.content).toBeSimilarStringTo(` export type A = B | C`); }); it('Should work with types', async () => { const schema = buildSchema(/* GraphQL */ ` "this is b" type B { id: ID } "this is c" type C { id: ID } `); const result = await plugin(schema, [], { disableDescriptions: true }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo('/** this is b */'); expect(result.content).toBeSimilarStringTo(` export type B = { __typename?: 'B'; id?: Maybe; }`); expect(result.content).not.toBeSimilarStringTo('/** this is c */'); expect(result.content).toBeSimilarStringTo(` export type C = { __typename?: 'C'; id?: Maybe; }`); }); it('Should work with type fields', async () => { const schema = buildSchema(/* GraphQL */ ` type B { "the id" id: ID } `); const result = await plugin(schema, [], { disableDescriptions: true }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo('/** the id */'); expect(result.content).toBeSimilarStringTo(` export type B = { __typename?: 'B'; id?: Maybe; };`); }); it('Should work with inteface and inteface fields', async () => { const schema = buildSchema(/* GraphQL */ ` interface Node { "the id" id: ID! } `); const result = await plugin(schema, [], { disableDescriptions: true }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo('/** the id */'); expect(result.content).toBeSimilarStringTo(` export type Node = { id: Scalars['ID']['output']; };`); }); it('Should work with enum and enum values', async () => { const schema = buildSchema(/* GraphQL */ ` "custom enum" enum MyEnum { "this is a" A "this is b" B } `); const result = await plugin(schema, [], { disableDescriptions: true }, { outputFile: '' }); expect(result.content).not.toBeSimilarStringTo('/** custom enum */'); expect(result.content).not.toBeSimilarStringTo('/** this is a */'); expect(result.content).not.toBeSimilarStringTo('/** this is b */'); expect(result.content).toBeSimilarStringTo(` export enum MyEnum { A = 'A', B = 'B' }`); }); it('Should work with enum and enum values (enumsAsTypes)', async () => { const schema = buildSchema(/* GraphQL */ ` "custom enum" enum MyEnum { "this is a" A "this is b" B } `); const result = (await plugin( schema, [], { enumsAsTypes: true, disableDescriptions: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).not.toBeSimilarStringTo('/** custom enum */'); expect(result.content).not.toBeSimilarStringTo('/** this is a */'); expect(result.content).not.toBeSimilarStringTo('/** this is b */'); expect(result.content).toBeSimilarStringTo(` export type MyEnum = | 'A' | 'B';`); }); it('Should not work when config is false', async () => { const schema = buildSchema(/* GraphQL */ ` "custom enum" enum MyEnum { "this is a" A "this is b" B } `); const result = (await plugin( schema, [], { enumsAsTypes: true, disableDescriptions: false }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` /** custom enum */ export type MyEnum = /** this is a */ | 'A' /** this is b */ | 'B';`); }); }); describe('Issues', () => { it('#6815 - Generate different type for Maybe wrapper based on input variables', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { test(id: ID): String testWithInput(filter: Filter): String } input Filter { a: String b: Int } `); const result = (await plugin( testSchema, [], { maybeValue: 'T | null', inputMaybeValue: 'T | null | undefined', }, { outputFile: '' } )) as Types.ComplexPluginOutput; const output = mergeOutputs([result]); expect(output).toContain(`export type InputMaybe = T | null | undefined;`); expect(output).toContain(`export type Maybe = T | null;`); expect(output).toContain(`test?: Maybe;`); expect(output).toContain(`id?: InputMaybe;`); expect(output).toContain(`filter?: InputMaybe;`); expect(output).toContain(`a?: InputMaybe;`); expect(output).toContain(`b?: InputMaybe;`); }); it('#5643 - Incorrect combinations of declartionKinds leads to syntax error', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Base { id: ID! } type MyType implements Base { id: ID! } type Query { t: MyType! } `); const result = (await plugin( testSchema, [], { declarationKind: { type: 'class', interface: 'interface', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; const output = mergeOutputs([result]); expect(output).not.toContain(`export class MyType extends Base {`); expect(output).toContain(`export class MyType implements Base {`); }); it('#4564 - numeric enum values set on schema level', async () => { const testSchema = new GraphQLSchema({ types: [ new GraphQLObjectType({ name: 'Query', fields: { test: { type: new GraphQLEnumType({ name: 'MyEnum', values: { missing: { value: 0, }, }, }), }, }, }), ], }); const result = (await plugin(testSchema, [], {}, { outputFile: '' })) as Types.ComplexPluginOutput; const output = mergeOutputs([result]); expect(output).not.toContain(`Missing = 'missing'`); expect(output).toContain(`Missing = 0`); }); it('#4564 - numeric enum values set on schema level - complex numeric', async () => { const testSchema = new GraphQLSchema({ types: [ new GraphQLObjectType({ name: 'Query', fields: { test: { type: new GraphQLEnumType({ name: 'MyEnum', values: { available: { value: '01', }, somethingElse: { value: '99', }, }, }), }, }, }), ], }); const result = (await plugin(testSchema, [], {}, { outputFile: '' })) as Types.ComplexPluginOutput; const output = mergeOutputs([result]); expect(output).toContain(`Available = '01'`); expect(output).toContain(`SomethingElse = '99'`); }); it('#7898 - falsy enum value set on schema with enumsAsTypes set', async () => { const testSchema = new GraphQLSchema({ types: [ new GraphQLObjectType({ name: 'Query', fields: { test: { type: new GraphQLEnumType({ name: 'MyEnum', values: { EnumValueName: { value: 0, }, }, }), }, }, }), ], }); const result = (await plugin( testSchema, [], { enumsAsTypes: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; const output = mergeOutputs([result]); expect(output).not.toContain('EnumValueName'); expect(output).toContain('0'); }); it('#6532 - numeric enum values with namingConvention', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { test: Test! } enum Test { Boop BIP BaP TEST_VALUE } `); const result = (await plugin( testSchema, [], { numericEnums: true, }, { outputFile: '' } )) as Types.ComplexPluginOutput; const output = mergeOutputs([result]); expect(output).toBeSimilarStringTo(`export enum Test { Boop = 0, Bip = 1, BaP = 2, TestValue = 3 }`); }); it('#3137 - numeric enum value', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Query { test: Test! } enum Test { A B C } `); const result = (await plugin( testSchema, [], { enumValues: { Test: { A: 0, B: 'test', C: '2', }, }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; const output = mergeOutputs([result]); expect(output).toBeSimilarStringTo(`export enum Test { A = 0, B = 'test', C = '2' }`); }); it('#4157 - Should generate numeric values for enums if numericEnums is set to true', async () => { const testSchema = buildSchema(/* GraphQl */ ` enum Status { Idle Running Error } `); const result = (await plugin( testSchema, [], { numericEnums: true, }, { outputFile: '', } )) as Types.ComplexPluginOutput; const output = mergeOutputs([result]); validateTs(output); expect(output).toBeSimilarStringTo(` export enum Status { Idle = 0, Running = 1, Error = 2 } `); }); it('#2679 - incorrect prefix for enums', async () => { const testSchema = buildSchema(/* GraphQL */ ` enum FilterOption { New Active Closed } input UpdateFilterOptionInput { newOption: FilterOption! } type Query { exampleQuery(i: UpdateFilterOptionInput, t: FilterOption): String } `); const result = (await plugin( testSchema, [], { typesPrefix: 'I', enumPrefix: false, }, { outputFile: '' } )) as Types.ComplexPluginOutput; const output = mergeOutputs([result]); validateTs(output); expect(output).toBeSimilarStringTo(` export enum FilterOption { New = 'New', Active = 'Active', Closed = 'Closed' }`); expect(output).toBeSimilarStringTo(` export type IUpdateFilterOptionInput = { newOption: FilterOption; };`); expect(output).toBeSimilarStringTo(` export type IQueryExampleQueryArgs = { i?: InputMaybe; t?: InputMaybe; };`); }); it('#3180 - enumValues and named default import', async () => { const testSchema = buildSchema(/* GraphQL */ ` enum MyEnum { A B C } type Test { t: MyEnum test(a: MyEnum): String } `); const result = (await plugin( testSchema, [], { typesPrefix: 'I', namingConvention: { enumValues: 'change-case-all#constantCase' }, enumValues: { MyEnum: './files#default as MyEnum', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend[0]).toBe(`import MyEnum from './files';`); }); it('#4834 - enum members should be quoted if numeric', async () => { const testSchema = buildSchema(/* GraphQL */ ` enum MediaItemSizeEnum { AXB _1X2 _3X4 } `); const result = (await plugin(testSchema, [], {})) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(`export enum MediaItemSizeEnum { Axb = 'AXB', '1X2' = '_1X2', '3X4' = '_3X4' }`); }); it('#2976 - Issues with mapped enumValues and type prefix in args', async () => { const testSchema = buildSchema(/* GraphQL */ ` enum MyEnum { A B C } type Test { t: MyEnum test(a: MyEnum): String } `); const result = (await plugin( testSchema, [], { typesPrefix: 'I', namingConvention: { enumValues: 'change-case-all#constantCase' }, enumValues: { MyEnum: './files#MyEnum', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(`export type ITest = { __typename?: 'Test'; t?: Maybe; test?: Maybe; };`); expect(result.content).toBeSimilarStringTo(`export type ITestTestArgs = { a?: InputMaybe; };`); }); it('#2082 - Issues with enumValues and types prefix', async () => { const testSchema = buildSchema(/* GraphQL */ ` enum MyEnum { A B C } enum OtherEnum { V } type Test { a: MyEnum b: OtherEnum } `); const result = (await plugin( testSchema, [], { typesPrefix: 'GQL_', enumValues: { MyEnum: './files#MyEnum', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyEnum } from './files';`); expect(result.content).toContain(`enum GQL_OtherEnum {`); expect(result.content).toContain(`a?: Maybe;`); expect(result.content).toContain(`b?: Maybe`); }); it('#1488 - Should generate readonly also in input types when immutableTypes is set', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { f: String! } `); const result = (await plugin( schema, [], { immutableTypes: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyInput = { readonly f: Scalars['String']['input']; };`); validateTs(result); }); it('#3141 - @deprecated directive support', async () => { const schema = buildSchema(/* GraphQL */ ` type User { fullName: String! firstName: String! @deprecated(reason: "Field \`fullName\` has been superseded by \`firstName\`.") } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type User = { __typename?: 'User'; fullName: Scalars['String']['output']; /** @deprecated Field \`fullName\` has been superseded by \`firstName\`. */ firstName: Scalars['String']['output']; };`); validateTs(result); }); it('#7627 - enum value @deprecated directive support', async () => { const schema = buildSchema(` enum MyEnum { A B @deprecated(reason: "Enum value \`B\` has been deprecated.") }`); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export enum MyEnum { A = 'A', /** @deprecated Enum value \`B\` has been deprecated. */ B = 'B' }`); validateTs(result); }); it('#7766 - input value @deprecated directive support', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { A: Int B: Int @deprecated(reason: "input value \`B\` has been deprecated.") } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyInput = { A?: InputMaybe; /** @deprecated input value \`B\` has been deprecated. */ B?: InputMaybe; };`); validateTs(result); }); it('#1462 - Union of scalars and argument of directive', async () => { const schema = buildSchema(/* GraphQL */ ` union Any = String | Int | Float | ID directive @default(value: Any) on ENUM_VALUE | FIELD_DEFINITION type CardEdge { count: Int! @default(value: 1) } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo( `export type Any = Scalars['String']['output'] | Scalars['Int']['output'] | Scalars['Float']['output'] | Scalars['ID']['output'];` ); expect(result.content).toBeSimilarStringTo(` export type CardEdge = { __typename?: 'CardEdge'; count: Scalars['Int']['output']; };`); validateTs(result); }); it('#1954 - Duplicate type names for args type', async () => { const schema = buildSchema(` type PullRequest { reviewThreads(first: Int!): Int } type PullRequestReview { threads(first: Int!, last: Int!): Int }`); const result = (await plugin( schema, [], { addUnderscoreToArgsType: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toContain('PullRequest_ReviewThreadsArgs'); expect(result.content).toContain('PullRequestReview_ThreadsArgs'); }); it('#1980 Do not put prefix on enums in args when enumPrefix: false', async () => { const schema = buildSchema(/* GraphQL */ ` enum SuggestionType { concern goal } type Suggestion { id: ID! userId: ID! suggestionType: SuggestionType! text: String! } type RootQueryType { suggestionsForUser(userId: ID!, suggestionType: SuggestionType!): [Suggestion!] } `); const result = (await plugin(schema, [], { skipTypename: true, declarationKind: 'interface', typesPrefix: 'I', enumPrefix: false, constEnums: true, scalars: { DateTime: 'string', Time: 'string', Date: 'string', }, })) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export interface ISuggestion { id: Scalars['ID']['output']; userId: Scalars['ID']['output']; suggestionType: SuggestionType; text: Scalars['String']['output']; } `); expect(result.content).toBeSimilarStringTo(` export const enum SuggestionType { Concern = 'concern', Goal = 'goal' }; `); expect(result.content).toBeSimilarStringTo(` export interface IRootQueryType { suggestionsForUser?: Maybe>; } `); expect(result.content).toBeSimilarStringTo(` export interface IRootQueryTypeSuggestionsForUserArgs { userId: Scalars['ID']['input']; suggestionType: SuggestionType; } `); }); }); describe('Config', () => { it('Should build type correctly when specified with avoidOptionals config', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo: String bar: String! } `); const result = (await plugin( schema, [], { avoidOptionals: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo: Maybe; bar: Scalars['String']['output']; }; `); validateTs(result); }); it('Should build input type correctly when specified with avoidInputOptionals config', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { foo: String bar: String! } `); const result = (await plugin( schema, [], { avoidOptionals: { inputValue: true } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyInput = { foo: InputMaybe; bar: Scalars['String']['input']; } `); validateTs(result); }); it('Should build type correctly when specified with immutableTypes config', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo: [String!]! } `); const result = (await plugin( schema, [], { immutableTypes: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyType = { readonly __typename?: 'MyType'; readonly foo: ReadonlyArray; }; `); validateTs(result); }); it('Should use const enums when constEnums is set', async () => { const schema = buildSchema(` enum MyEnum { A }`); const result = await plugin(schema, [], { constEnums: true }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export const enum MyEnum { A = 'A' }; `); validateTs(result); }); it('Should use enum as type when enumsAsTypes is set', async () => { const schema = buildSchema(` enum MyEnum { A B }`); const result = (await plugin( schema, [], { enumsAsTypes: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyEnum = | 'A' | 'B'; `); validateTs(result); }); it('Should use enum as type when enumsAsTypes is set and also enumValues', async () => { const schema = buildSchema(` enum MyEnum { A B }`); const result = (await plugin( schema, [], { enumValues: { MyEnum: { A: 'BOOP' } }, enumsAsTypes: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyEnum = | 'BOOP' | 'B'; `); validateTs(result); }); it('Should add `%future added value` to enum when futureProofEnums is set and also enumAsTypes', async () => { const schema = buildSchema(` enum MyEnum { A B } type MyType { required: MyEnum! optional: MyEnum } `); const result = (await plugin( schema, [], { enumsAsTypes: true, futureProofEnums: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyEnum = | 'A' | 'B' | '%future added value' `); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; required: MyEnum; optional?: Maybe; } `); validateTs(result); }); it('Should add `%future added value` to enum usage when futureProofEnums is set, but not enumAsTypes', async () => { const schema = buildSchema(` enum MyEnum { A B } type MyType { required: MyEnum! optional: MyEnum } `); const result = (await plugin( schema, [], { futureProofEnums: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export enum MyEnum { A = 'A', B = 'B' } `); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; required: MyEnum | '%future added value'; optional?: Maybe; } `); validateTs(result); }); it('Should add `%future added value` to enum usage when futureProofEnums is set and allowEnumStringTypes is set', async () => { const schema = buildSchema(` enum MyEnum { A B } type MyType { required: MyEnum! optional: MyEnum } `); const result = (await plugin( schema, [], { futureProofEnums: true, allowEnumStringTypes: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export enum MyEnum { A = 'A', B = 'B' } `); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; required: MyEnum | '%future added value' | \`\${MyEnum}\`; optional?: Maybe; } `); validateTs(result); }); it('Should use custom namingConvention for enums (keep)', async () => { const schema = buildSchema(/* GraphQL */ ` enum Foo { YES NO } type MyType { foo(a: String!, b: String, c: [String], d: [Int!]!): Foo } `); const result = (await plugin( schema, [], { namingConvention: { typeNames: 'change-case-all#lowerCase', enumValues: 'keep', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export enum foo { YES = 'YES', NO = 'NO' } `); expect(result.content).toBeSimilarStringTo(` export type mytypefooargs = { a: Scalars['String']['input']; b?: InputMaybe; c?: InputMaybe>>; d: Array; }; `); expect(result.content).toBeSimilarStringTo(` export type mytype = { __typename?: 'MyType'; foo?: Maybe; }; `); validateTs(result); }); it('Should use custom namingConvention for enums values as string, without specifying other type converters', async () => { const schema = buildSchema(/* GraphQL */ ` enum Foo { YES NO } type MyType { foo(a: String!, b: String, c: [String], d: [Int!]!): Foo } `); const result = (await plugin( schema, [], { namingConvention: { enumValues: 'change-case-all#lowerCase', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export enum Foo { yes = 'YES', no = 'NO' }`); }); it('Should use custom namingConvention for enums', async () => { const schema = buildSchema(/* GraphQL */ ` enum Foo { YES NO } type MyType { foo(a: String!, b: String, c: [String], d: [Int!]!): Foo } `); const result = (await plugin( schema, [], { namingConvention: { typeNames: 'keep', enumValues: 'change-case-all#lowerCase', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export enum Foo { yes = 'YES', no = 'NO' } `); expect(result.content).toBeSimilarStringTo(` export type MyTypefooArgs = { a: Scalars['String']['input']; b?: InputMaybe; c?: InputMaybe>>; d: Array; }; `); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; }; `); validateTs(result); }); it('should handle introspection types (like __TypeKind)', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Post { title: String } type Query { post: Post! } `); const query = parse(/* GraphQL */ ` query Info { __type(name: "Post") { name fields { name type { name kind } } } } `); const result = (await plugin( testSchema, [{ location: '', document: query }], {}, { outputFile: 'graphql.ts', } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` /** An enum describing what kind of type a given \`__Type\` is. */ export enum __TypeKind { /** Indicates this type is a scalar. */ Scalar = 'SCALAR', /** Indicates this type is an object. \`fields\` and \`interfaces\` are valid fields. */ Object = 'OBJECT', /** Indicates this type is an interface. \`fields\`, \`interfaces\`, and \`possibleTypes\` are valid fields. */ Interface = 'INTERFACE', /** Indicates this type is a union. \`possibleTypes\` is a valid field. */ Union = 'UNION', /** Indicates this type is an enum. \`enumValues\` is a valid field. */ Enum = 'ENUM', /** Indicates this type is an input object. \`inputFields\` is a valid field. */ InputObject = 'INPUT_OBJECT', /** Indicates this type is a list. \`ofType\` is a valid field. */ List = 'LIST', /** Indicates this type is a non-null. \`ofType\` is a valid field. */ NonNull = 'NON_NULL' } `); }); it('Should use class correctly when declarationKind: class is set', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { id: ID! displayName: String } type MyType { id: ID! displayName: String } `); const result = (await plugin( schema, [], { declarationKind: 'class', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export class MyInput { id: Scalars['ID']['input']; displayName?: InputMaybe; } `); expect(result.content).toBeSimilarStringTo(` export class MyType { __typename?: 'MyType'; id: Scalars['ID']['output']; displayName?: Maybe; } `); validateTs(result); }); it('Should use interface for type when declarationKind for types is set', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { id: ID! displayName: String } type MyType { id: ID! displayName: String } `); const result = (await plugin( schema, [], { declarationKind: { type: 'interface', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyInput = { id: Scalars['ID']['input']; displayName?: InputMaybe; } `); expect(result.content).toBeSimilarStringTo(` export interface MyType { __typename?: 'MyType'; id: Scalars['ID']['output']; displayName?: Maybe; } `); validateTs(result); }); it('Should use interface for input when declarationKind for inputs is set', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { id: ID! displayName: String } type MyType { id: ID! displayName: String } `); const result = (await plugin( schema, [], { declarationKind: { input: 'interface', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export interface MyInput { id: Scalars['ID']['input']; displayName?: InputMaybe; } `); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; id: Scalars['ID']['output']; displayName?: Maybe; } `); validateTs(result); }); it('Should use interface for arguments when declarationKind for arguments is set', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { id: ID! displayName: String child(id: ID!): MyType } `); const result = (await plugin( schema, [], { declarationKind: { arguments: 'interface', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; id: Scalars['ID']['output']; displayName?: Maybe; child?: Maybe; } `); expect(result.content).toBeSimilarStringTo(` export interface MyTypeChildArgs { id: Scalars['ID']['input']; } `); validateTs(result); }); it('Should use interface for all objects when declarationKind is interface', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { id: ID! displayName: String } type MyType { id: ID! displayName: String } `); const result = (await plugin( schema, [], { declarationKind: 'interface', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export interface MyInput { id: Scalars['ID']['input']; displayName?: InputMaybe; } `); expect(result.content).toBeSimilarStringTo(` export interface MyType { __typename?: 'MyType'; id: Scalars['ID']['output']; displayName?: Maybe; } `); validateTs(result); }); it('Should correctly render empty interfaces', async () => { const schema = buildSchema(` input MyInput type MyType `); const result = (await plugin( schema, [], { declarationKind: 'interface', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export interface MyInput {} `); expect(result.content).toBeSimilarStringTo(` export interface MyType { __typename?: 'MyType'; } `); validateTs(result); }); it('Should extend one interface from another', async () => { const schema = buildSchema(/* GraphQL */ ` interface MyInterface { id: ID! displayName: String } type MyType implements MyInterface { id: ID! displayName: String value: Int } `); const result = (await plugin( schema, [], { declarationKind: 'interface', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export interface MyInterface { id: Scalars['ID']['output']; displayName?: Maybe; } `); expect(result.content).toBeSimilarStringTo(` export interface MyType extends MyInterface { __typename?: 'MyType'; id: Scalars['ID']['output']; displayName?: Maybe; value?: Maybe; } `); validateTs(result); }); it('Should extend mutiple interfaces', async () => { const schema = buildSchema(/* GraphQL */ ` interface MyInterface1 { id: ID! displayName: String } interface MyInterface2 { value: Int } type MyType implements MyInterface1 & MyInterface2 { id: ID! displayName: String value: Int } `); const result = (await plugin( schema, [], { declarationKind: 'interface', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export interface MyInterface1 { id: Scalars['ID']['output']; displayName?: Maybe; } `); expect(result.content).toBeSimilarStringTo(` export interface MyInterface2 { value?: Maybe; } `); expect(result.content).toBeSimilarStringTo(` export interface MyType extends MyInterface1, MyInterface2 { __typename?: 'MyType'; id: Scalars['ID']['output']; displayName?: Maybe; value?: Maybe; } `); validateTs(result); }); }); describe('Scalars', () => { it('Should generate a scalars mapping correctly for built-in scalars', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo: String bar: String! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } };`); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; bar: Scalars['String']['output']; };`); validateTs(result); }); it('Should generate a scalars mapping correctly when using scalars as path', async () => { const schema = buildSchema(/* GraphQL */ ` scalar MyScalar scalar MyScalarInput type MyType { foo: String bar: MyScalar! baz(input: MyScalarInput): MyScalarInput } `); const result = (await plugin( schema, [], { scalars: '../../scalars', }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyScalar } from '../../scalars';`); expect(result.prepend).toContain(`import { MyScalarInput } from '../../scalars';`); expect(result.prepend).toContain(`import { String } from '../../scalars';`); expect(result.prepend).toContain(`import { Boolean } from '../../scalars';`); expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string; output: string; } String: { input: String['input']; output: String['output']; } Boolean: { input: Boolean['input']; output: Boolean['output']; } Int: { input: number; output: number; } Float: { input: number; output: number; } MyScalar: { input: MyScalar['input']; output: MyScalar['output']; } MyScalarInput: { input: MyScalarInput['input']; output: MyScalarInput['output']; } };`); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; bar: Scalars['MyScalar']['output']; baz?: Maybe; };`); expect(result.content).toBeSimilarStringTo(` export type MyTypeBazArgs = { input?: InputMaybe; };`); validateTs(result); }); it('Should import a type of a mapped scalar', async () => { const schema = buildSchema(/* GraphQL */ ` scalar MyScalar scalar MyOtherScalar scalar MyAliasedScalar scalar OrgScalar scalar OrgOtherScalar scalar OrgAliasedScalar type MyType { foo: String bar: MyScalar! baz: MyOtherScalar! qux: MyAliasedScalar! tux(in: MyScalar!): MyScalar! ay: OrgScalar! bee: OrgOtherScalar! ce: OrgAliasedScalar! } `); const result = (await plugin( schema, [], { scalars: { MyScalar: '../../scalars#default', MyOtherScalar: '../../scalars#MyOtherScalar', MyAliasedScalar: '../../scalars#MyAliasedScalar as AliasedScalar', OrgScalar: '@org/scalars#default', OrgOtherScalar: '@org/scalars#OrgOtherScalar', OrgAliasedScalar: '@org/scalars#OrgOtherScalar as OrgAliasedScalar', }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; // It seems like we don't group imports... expect(result.prepend).toContain(`import MyScalar from '../../scalars';`); expect(result.prepend).toContain(`import { MyOtherScalar } from '../../scalars';`); expect(result.prepend).toContain(`import { MyAliasedScalar as AliasedScalar } from '../../scalars';`); expect(result.prepend).toContain(`import OrgScalar from '@org/scalars';`); expect(result.prepend).toContain(`import { OrgOtherScalar } from '@org/scalars';`); expect(result.prepend).toContain(`import { OrgOtherScalar as OrgAliasedScalar } from '@org/scalars';`); expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } MyScalar: { input: MyScalar; output: MyScalar; } MyOtherScalar: { input: MyOtherScalar; output: MyOtherScalar; } MyAliasedScalar: { input: AliasedScalar; output: AliasedScalar; } OrgScalar: { input: OrgScalar; output: OrgScalar; } OrgOtherScalar: { input: OrgOtherScalar; output: OrgOtherScalar; } OrgAliasedScalar: { input: OrgAliasedScalar; output: OrgAliasedScalar; } };`); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; bar: Scalars['MyScalar']['output']; baz: Scalars['MyOtherScalar']['output']; qux: Scalars['MyAliasedScalar']['output']; tux: Scalars['MyScalar']['output']; ay: Scalars['OrgScalar']['output']; bee: Scalars['OrgOtherScalar']['output']; ce: Scalars['OrgAliasedScalar']['output']; };`); expect(result.content).toBeSimilarStringTo(` export type MyTypeTuxArgs = { in: Scalars['MyScalar']['input']; }`); validateTs(result); }); it('Should import a type of a mapped scalar for input/output mapping', async () => { const schema = buildSchema(/* GraphQL */ ` scalar MyScalar scalar MyOtherScalar scalar MyAliasedScalar scalar OrgScalar scalar OrgOtherScalar scalar OrgAliasedScalar type MyType { foo: String bar: MyScalar! baz: MyOtherScalar! qux: MyAliasedScalar! tux(in: MyScalar!): MyScalar! ay: OrgScalar! bee: OrgOtherScalar! ce: OrgAliasedScalar! } `); const result = (await plugin( schema, [], { scalars: { MyScalar: { input: '../../scalarsInput#default as MyScalarInput', output: '../../scalarsOutput#default as MyScalarOutput', }, MyOtherScalar: { input: '../../scalars#MyOtherScalarInput', output: '../../scalars#MyOtherScalarOutput', }, MyAliasedScalar: { input: '../../scalars#MyAliasedScalar as AliasedScalarInput', output: '../../scalars#MyAliasedScalar as AliasedScalarOutput', }, OrgScalar: { input: '@org/scalars-input#default as OrgScalarInput', output: '@org/scalars-output#default as OrgScalarOutput', }, OrgOtherScalar: { input: '@org/scalars#OrgOtherScalarInput', output: '@org/scalars#OrgOtherScalarOutput', }, OrgAliasedScalar: { input: '@org/scalars#OrgOtherScalar as OrgAliasedScalarInput', output: '@org/scalars#OrgOtherScalar as OrgAliasedScalarOutput', }, }, }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import MyScalarInput from '../../scalarsInput';`); expect(result.prepend).toContain(`import MyScalarOutput from '../../scalarsOutput';`); expect(result.prepend).toContain(`import { MyOtherScalarInput } from '../../scalars';`); expect(result.prepend).toContain(`import { MyOtherScalarOutput } from '../../scalars';`); expect(result.prepend).toContain(`import { MyAliasedScalar as AliasedScalarInput } from '../../scalars';`); expect(result.prepend).toContain(`import { MyAliasedScalar as AliasedScalarOutput } from '../../scalars';`); expect(result.prepend).toContain(`import OrgScalarInput from '@org/scalars-input';`); expect(result.prepend).toContain(`import OrgScalarOutput from '@org/scalars-output';`); expect(result.prepend).toContain(`import { OrgOtherScalarInput } from '@org/scalars';`); expect(result.prepend).toContain(`import { OrgOtherScalarOutput } from '@org/scalars';`); expect(result.prepend).toContain(`import { OrgOtherScalar as OrgAliasedScalarInput } from '@org/scalars';`); expect(result.prepend).toContain(`import { OrgOtherScalar as OrgAliasedScalarOutput } from '@org/scalars';`); expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } MyScalar: { input: MyScalarInput; output: MyScalarOutput; } MyOtherScalar: { input: MyOtherScalarInput; output: MyOtherScalarOutput; } MyAliasedScalar: { input: AliasedScalarInput; output: AliasedScalarOutput; } OrgScalar: { input: OrgScalarInput; output: OrgScalarOutput; } OrgOtherScalar: { input: OrgOtherScalarInput; output: OrgOtherScalarOutput; } OrgAliasedScalar: { input: OrgAliasedScalarInput; output: OrgAliasedScalarOutput; } };`); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; bar: Scalars['MyScalar']['output']; baz: Scalars['MyOtherScalar']['output']; qux: Scalars['MyAliasedScalar']['output']; tux: Scalars['MyScalar']['output']; ay: Scalars['OrgScalar']['output']; bee: Scalars['OrgOtherScalar']['output']; ce: Scalars['OrgAliasedScalar']['output']; };`); expect(result.content).toBeSimilarStringTo(` export type MyTypeTuxArgs = { in: Scalars['MyScalar']['input']; }`); validateTs(result); }); it('Should generate a scalars mapping correctly for custom scalars', async () => { const schema = buildSchema(/* GraphQL */ ` scalar MyScalar type MyType { foo: String bar: MyScalar! buz(input: MyScalar!): MyScalar! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } MyScalar: { input: any; output: any; } };`); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; bar: Scalars['MyScalar']['output']; buz: Scalars['MyScalar']['output']; };`); expect(result.content).toBeSimilarStringTo(` export type MyTypeBuzArgs = { input: Scalars['MyScalar']['input']; }`); validateTs(result); }); it('Should generate a scalars mapping correctly for custom scalars with mapping', async () => { const schema = buildSchema(/* GraphQL */ ` scalar MyScalar type MyType { foo: String bar: MyScalar! buz(input: MyScalar!): MyScalar! } `); const result = (await plugin( schema, [], { scalars: { MyScalar: 'Date' } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } MyScalar: { input: Date; output: Date; } };`); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; bar: Scalars['MyScalar']['output']; buz: Scalars['MyScalar']['output']; };`); expect(result.content).toBeSimilarStringTo(` export type MyTypeBuzArgs = { input: Scalars['MyScalar']['input']; }`); validateTs(result); }); it('Should generate a scalars mapping correctly for custom scalars with input/output mapping', async () => { const schema = buildSchema(/* GraphQL */ ` scalar MyScalar type MyType { foo: String bar: MyScalar! buz(input: MyScalar!): MyScalar! } `); const result = (await plugin( schema, [], { scalars: { MyScalar: { input: 'bigint', output: 'number | bigint' } } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } MyScalar: { input: bigint; output: number | bigint; } };`); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; bar: Scalars['MyScalar']['output']; buz: Scalars['MyScalar']['output']; };`); expect(result.content).toBeSimilarStringTo(` export type MyTypeBuzArgs = { input: Scalars['MyScalar']['input']; }`); validateTs(result); }); it('Should correctly throw an error when an unknown scalar is detected while using `strictScalars`', () => { const schema = buildSchema(/* GraphQL */ ` scalar MyScalar type MyType { foo: String bar: MyScalar! } `); expect(() => { plugin(schema, [], { strictScalars: true }, { outputFile: '' }); }).toThrow('Unknown scalar type MyScalar'); }); it('Should allow overriding default scalar type', async () => { const schema = buildSchema(/* GraphQL */ ` scalar MyScalar type MyType { foo: String bar: MyScalar! buz(input: MyScalar!): MyScalar! } `); const result = (await plugin( schema, [], { defaultScalarType: 'unknown' }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } MyScalar: { input: unknown; output: unknown; } };`); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; bar: Scalars['MyScalar']['output']; buz: Scalars['MyScalar']['output']; };`); expect(result.content).toBeSimilarStringTo(` export type MyTypeBuzArgs = { input: Scalars['MyScalar']['input']; }`); validateTs(result); }); it('Should add FieldWrapper when field definition wrapping is enabled', async () => { const schema = buildSchema(` scalar A `); const result = (await plugin( schema, [], { wrapFieldDefinitions: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toBeSimilarStringTo('export type FieldWrapper ='); validateTs(result); }); it('Should allow the FieldWrapper type to be modified', async () => { const schema = buildSchema(` scalar A `); const result = (await plugin( schema, [], { fieldWrapperValue: 'T | Promise', wrapFieldDefinitions: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toBeSimilarStringTo('export type FieldWrapper = T | Promise'); validateTs(result); }); }); describe('Object (type)', () => { it('Should build type correctly', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo: String bar: String! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo?: Maybe; bar: Scalars['String']['output']; }; `); validateTs(result); }); it('Should build type correctly when implementing interface', async () => { const schema = buildSchema(/* GraphQL */ ` interface MyInterface { foo: String! } type MyType implements MyInterface { foo: String! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyInterface = { foo: Scalars['String']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyType = MyInterface & { __typename?: 'MyType'; foo: Scalars['String']['output']; }; `); validateTs(result); }); it('Should build type correctly when implementing multiple interfaces', async () => { const schema = buildSchema(/* GraphQL */ ` interface MyInterface { foo: String! } interface MyOtherInterface { bar: String! } type MyType implements MyInterface & MyOtherInterface { foo: String! bar: String! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyInterface = { foo: Scalars['String']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyOtherInterface = { bar: Scalars['String']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyType = MyInterface & MyOtherInterface & { __typename?: 'MyType'; foo: Scalars['String']['output']; bar: Scalars['String']['output']; }; `); validateTs(result); }); it('Should build type correctly when implementing interface without adding fields', async () => { const schema = buildSchema(` interface MyInterface { foo: String! } type MyType implements MyInterface `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyInterface = { foo: Scalars['String']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type MyType = MyInterface & { __typename?: 'MyType'; }; `); validateTs(result); }); it('Should build type correctly with links between types', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo: MyOtherType! } type MyOtherType { bar: String! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; foo: MyOtherType; }; `); expect(result.content).toBeSimilarStringTo(` export type MyOtherType = { __typename?: 'MyOtherType'; bar: Scalars['String']['output']; }; `); validateTs(result); }); it('Should build type correctly when wrapping field definitions', async () => { const schema = buildSchema(/* GraphQL */ ` interface MyInterface { foo: String! } type MyType implements MyInterface { foo: String! } `); const result = (await plugin( schema, [], { wrapFieldDefinitions: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyInterface = { foo: FieldWrapper; }; `); expect(result.content).toBeSimilarStringTo(` export type MyType = MyInterface & { __typename?: 'MyType'; foo: FieldWrapper; }; `); validateTs(result); }); it('Should build list type correctly when wrapping field definitions', async () => { const schema = buildSchema(/* GraphQL */ ` type ListOfStrings { foo: [String!]! } type ListOfMaybeStrings { foo: [String]! } `); const result = (await plugin( schema, [], { wrapFieldDefinitions: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type ListOfStrings = { __typename?: 'ListOfStrings'; foo: Array>; }; `); expect(result.content).toBeSimilarStringTo(` export type ListOfMaybeStrings = { __typename?: 'ListOfMaybeStrings'; foo: Array>>; }; `); validateTs(result); }); it('Should build list type correctly when wrapping entire field definitions', async () => { const schema = buildSchema(/* GraphQL */ ` type ListOfStrings { foo: [String!]! } type ListOfMaybeStrings { foo: [String]! } `); const result = (await plugin( schema, [], { wrapEntireFieldDefinitions: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type ListOfStrings = { __typename?: 'ListOfStrings'; foo: EntireFieldWrapper>; }; `); expect(result.content).toBeSimilarStringTo(` export type ListOfMaybeStrings = { __typename?: 'ListOfMaybeStrings'; foo: EntireFieldWrapper>>; }; `); validateTs(result); }); it('Should build list type correctly when wrapping both field definitions and entire field definitions', async () => { const schema = buildSchema(/* GraphQL */ ` type ListOfStrings { foo: [String!]! } type ListOfMaybeStrings { foo: [String]! } `); const result = (await plugin( schema, [], { wrapEntireFieldDefinitions: true, wrapFieldDefinitions: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type ListOfStrings = { __typename?: 'ListOfStrings'; foo: EntireFieldWrapper>>; }; `); expect(result.content).toBeSimilarStringTo(` export type ListOfMaybeStrings = { __typename?: 'ListOfMaybeStrings'; foo: EntireFieldWrapper>>>; }; `); validateTs(result); }); it('Should not wrap input type fields', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { foo: String! } `); const result = (await plugin( schema, [], { wrapFieldDefinitions: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyInput = { foo: Scalars['String']['input']; }; `); validateTs(result); }); }); describe('Union', () => { it('Should build union as type correctly', async () => { const schema = buildSchema(` type MyType { foo: String! } type MyOtherType { bar: String! } union MyUnion = MyType | MyOtherType `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyUnion = MyType | MyOtherType; `); validateTs(result); }); it('Should add `%other` object typename to union when futureProofUnions is set', async () => { const schema = buildSchema(` type MyType { foo: String! } type MyOtherType { bar: String! } union MyUnion = MyType | MyOtherType `); const result = await plugin(schema, [], { futureProofUnions: true }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyUnion = MyType | MyOtherType | { __typename?: "%other" }; `); validateTs(result); }); it('Should add `%other` object typename to union when futureProofUnions and immutableTypes is set', async () => { const schema = buildSchema(` type MyType { foo: String! } type MyOtherType { bar: String! } union MyUnion = MyType | MyOtherType `); const result = await plugin(schema, [], { futureProofUnions: true, immutableTypes: true }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyUnion = MyType | MyOtherType | { readonly __typename?: "%other" }; `); validateTs(result); }); }); describe('Interface', () => { it('Should build interface correctly', async () => { const schema = buildSchema(/* GraphQL */ ` interface MyInterface { foo: String bar: String! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyInterface = { foo?: Maybe; bar: Scalars['String']['output']; }; `); validateTs(result); }); }); describe('Directives', () => { it('Should handle directive declarations correctly', async () => { const schema = buildSchema(` directive @simple on FIELD_DEFINITION directive @withArgument(arg: Int!) on FIELD_DEFINITION directive @objSimple on OBJECT directive @universal on OBJECT | FIELD_DEFINITION | ENUM_VALUE `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).not.toContain('simple'); expect(result.content).not.toContain('withArguments'); expect(result.content).not.toContain('objSimple'); expect(result.content).not.toContain('universal'); validateTs(result); }); it('Should handle type override', async () => { const schema = buildSchema(/* GraphQL */ ` directive @AsNumber on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION input MyInput { id: ID! @AsNumber } type Query { myField(id: ID! @AsNumber): Boolean } `); const result = await plugin( schema, [], { directiveArgumentAndInputFieldMappings: { AsNumber: 'number' } }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type DirectiveArgumentAndInputFieldMappings = { AsNumber: number; }; `); expect(result.content).toBeSimilarStringTo(` export type MyInput = { id: DirectiveArgumentAndInputFieldMappings['AsNumber']; }; export type Query = { __typename?: 'Query'; myField?: Maybe; }; export type QueryMyFieldArgs = { id: DirectiveArgumentAndInputFieldMappings['AsNumber']; }; `); validateTs(result); }); it('Should allow imported types', async () => { const schema = buildSchema(/* GraphQL */ ` directive @AsNumber on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION input MyInput { id: ID! @AsNumber } `); const result = await plugin( schema, [], { directiveArgumentAndInputFieldMappings: { AsNumber: './someModule#MyType' }, directiveArgumentAndInputFieldMappingTypeSuffix: 'Model', }, { outputFile: '' } ); expect(result.prepend).toContain("import { MyType as MyTypeModel } from './someModule';"); expect(result.content).toBeSimilarStringTo(` export type DirectiveArgumentAndInputFieldMappings = { AsNumber: MyTypeModel; }; `); expect(result.content).toBeSimilarStringTo(` export type MyInput = { id: DirectiveArgumentAndInputFieldMappings['AsNumber']; }; `); validateTs(result); }); it('Should use last directive override', async () => { const schema = buildSchema(/* GraphQL */ ` directive @AsNumber on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION directive @AsString on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION input MyInput { id: ID! @AsNumber @AsString } `); const result = await plugin( schema, [], { directiveArgumentAndInputFieldMappings: { AsNumber: 'number', AsString: 'AsString' } }, { outputFile: '' } ); expect(result.content).toBeSimilarStringTo(` export type MyInput = { id: DirectiveArgumentAndInputFieldMappings['AsString']; }; `); validateTs(result); }); it('Should ignore unmapped directives', async () => { const schema = buildSchema(/* GraphQL */ ` directive @AsNumber on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION input MyInput { id: ID! @AsNumber } `); const result = await plugin(schema, [], { directiveArgumentAndInputFieldMappings: {} }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyInput = { id: Scalars['ID']['input']; }; `); validateTs(result); }); describe('@oneOf on input types', () => { const oneOfDirectiveDefinition = /* GraphQL */ ` directive @oneOf on INPUT_OBJECT `; it('correct output for type with single field', async () => { const schema = buildSchema( /* GraphQL */ ` input Input @oneOf { int: Int } type Query { foo(input: Input!): Boolean! } `.concat(oneOfDirectiveDefinition) ); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type Input = { int: Scalars['Int']['input']; }; `); }); it('correct output for type with multiple fields', async () => { const schema = buildSchema( /* GraphQL */ ` input Input @oneOf { int: Int boolean: Boolean } type Query { foo(input: Input!): Boolean! } `.concat(oneOfDirectiveDefinition) ); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type Input = { int: Scalars['Int']['input']; boolean?: never; } | { int?: never; boolean: Scalars['Boolean']['input']; }; `); }); it('respects configured declaration kind with single field', async () => { const schema = buildSchema( /* GraphQL */ ` input Input @oneOf { int: Int } type Query { foo(input: Input!): Boolean! } `.concat(oneOfDirectiveDefinition) ); const result = await plugin(schema, [], { declarationKind: 'interface' }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export interface Input { int: Scalars['Int']['input']; } `); }); it('forces declaration kind of type with multiple fields', async () => { const schema = buildSchema( /* GraphQL */ ` input Input @oneOf { int: Int boolean: Boolean } type Query { foo(input: Input!): Boolean! } `.concat(oneOfDirectiveDefinition) ); const result = await plugin(schema, [], { declarationKind: 'interface' }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type Input = { int: Scalars['Int']['input']; boolean?: never; } | { int?: never; boolean: Scalars['Boolean']['input']; }; `); }); it('raises exception for type with non-optional fields', async () => { const schema = buildSchema( /* GraphQL */ ` input Input @oneOf { int: Int! boolean: Boolean! } type Query { foo(input: Input!): Boolean! } `.concat(oneOfDirectiveDefinition) ); try { await plugin(schema, [], {}, { outputFile: '' }); throw new Error('Plugin should have raised an exception.'); } catch (err) { expect(err.message).toEqual( 'Fields on an input object type can not be non-nullable. It seems like the schema was not validated.' ); } }); it('handles extensions properly', async () => { const schema = buildSchema( /* GraphQL */ ` input Input @oneOf { int: Int } extend input Input { boolean: Boolean } type Query { foo(input: Input!): Boolean! } `.concat(oneOfDirectiveDefinition) ); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type Input = { int: Scalars['Int']['input']; boolean?: never; } | { int?: never; boolean: Scalars['Boolean']['input']; }; `); }); it('handles .isOneOf property on input object types properly', async () => { const schema = buildSchema( /* GraphQL */ ` input Input { int: Int boolean: Boolean } type Query { foo(input: Input!): Boolean! } `.concat(oneOfDirectiveDefinition) ); const inputType: Record<'isOneOf', boolean> = schema.getType('Input') as any; inputType.isOneOf = true; const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type Input = { int: Scalars['Int']['input']; boolean?: never; } | { int?: never; boolean: Scalars['Boolean']['input']; }; `); }); }); }); describe('Naming Convention & Types Prefix', () => { it('Should use custom namingConvention for type name and args typename', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo(a: String!, b: String, c: [String], d: [Int!]!): String } `); const result = (await plugin( schema, [], { namingConvention: 'change-case-all#lowerCase' }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type mytypefooargs = { a: Scalars['String']['input']; b?: InputMaybe; c?: InputMaybe>>; d: Array; }; `); expect(result.content).toBeSimilarStringTo(` export type mytype = { __typename?: 'MyType'; foo?: Maybe; }; `); validateTs(result); }); it('Should use custom namingConvention and add custom prefix', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo(a: String!, b: String, c: [String], d: [Int!]!): String } `); const result = (await plugin( schema, [], { namingConvention: 'change-case-all#lowerCase', typesPrefix: 'I' }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type Imytypefooargs = { a: Scalars['String']['input']; b?: InputMaybe; c?: InputMaybe>>; d: Array; }; `); expect(result.content).toBeSimilarStringTo(` export type Imytype = { __typename?: 'MyType'; foo?: Maybe; }; `); validateTs(result); }); it('Should allow to disable typesPrefix for enums', async () => { const schema = buildSchema(`type T { f: String, e: E } enum E { A }`); const result = (await plugin( schema, [], { typesPrefix: 'I', enumPrefix: false }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toContain(`export enum E {`); expect(result.content).toContain(`e?: Maybe;`); validateTs(result); }); it('Should allow to disable typesSuffix for enums', async () => { const schema = buildSchema(`type T { f: String, e: E } enum E { A }`); const result = (await plugin( schema, [], { typesSuffix: 'I', enumSuffix: false }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toContain(`export enum E {`); expect(result.content).toContain(`e?: Maybe;`); validateTs(result); }); it('Should enable typesPrefix for enums by default', async () => { const schema = buildSchema(`type T { f: String, e: E } enum E { A }`); const result = await plugin(schema, [], { typesPrefix: 'I' }, { outputFile: '' }); expect(result.content).toContain(`export enum IE {`); expect(result.content).toContain(`e?: Maybe;`); validateTs(result); }); const schema = buildSchema(/* GraphQL */ ` enum MyEnum { A B C } type MyType { f: String bar: MyEnum b_a_r: String myOtherField: String } type My_Type { linkTest: MyType } union MyUnion = My_Type | MyType interface Some_Interface { id: ID! } type Impl1 implements Some_Interface { id: ID! } type Impl_2 implements Some_Interface { id: ID! } type impl_3 implements Some_Interface { id: ID! } type Query { something: MyUnion use_interface: Some_Interface } `); it('Should generate correct values when using links between types - lowerCase', async () => { const result = (await plugin( schema, [], { namingConvention: 'change-case-all#lowerCase' }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export enum myenum { a = 'A', b = 'B', c = 'C' } `); expect(result.content).toBeSimilarStringTo(` export type mytype = { __typename?: 'MyType'; f?: Maybe; bar?: Maybe; b_a_r?: Maybe; myOtherField?: Maybe; }; `); expect(result.content).toBeSimilarStringTo(` export type my_type = { __typename?: 'My_Type'; linkTest?: Maybe; }; `); expect(result.content).toBeSimilarStringTo(` export type myunion = my_type | mytype; `); expect(result.content).toBeSimilarStringTo(` export type some_interface = { id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type impl1 = some_interface & { __typename?: 'Impl1'; id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type impl_2 = some_interface & { __typename?: 'Impl_2'; id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type impl_3 = some_interface & { __typename?: 'impl_3'; id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type query = { __typename?: 'Query'; something?: Maybe; use_interface?: Maybe; }; `); validateTs(result); }); it('Should generate correct values when using links between types - pascalCase (default)', async () => { const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export enum MyEnum { A = 'A', B = 'B', C = 'C' } `); expect(result.content).toBeSimilarStringTo(` export type MyType = { __typename?: 'MyType'; f?: Maybe; bar?: Maybe; b_a_r?: Maybe; myOtherField?: Maybe; }; `); expect(result.content).toBeSimilarStringTo(` export type My_Type = { __typename?: 'My_Type'; linkTest?: Maybe; }; `); expect(result.content).toBeSimilarStringTo(` export type MyUnion = My_Type | MyType; `); expect(result.content).toBeSimilarStringTo(` export type Some_Interface = { id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type Impl1 = Some_Interface & { __typename?: 'Impl1'; id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type Impl_2 = Some_Interface & { __typename?: 'Impl_2'; id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type Impl_3 = Some_Interface & { __typename?: 'impl_3'; id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type Query = { __typename?: 'Query'; something?: Maybe; use_interface?: Maybe; }; `); validateTs(result); }); it('Should generate correct values when using links between types - pascalCase (default) with custom prefix', async () => { const result = await plugin(schema, [], { typesPrefix: 'I' }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export enum IMyEnum { A = 'A', B = 'B', C = 'C' }`); expect(result.content).toBeSimilarStringTo(` export type IMyType = { __typename?: 'MyType'; f?: Maybe; bar?: Maybe; b_a_r?: Maybe; myOtherField?: Maybe; };`); expect(result.content).toBeSimilarStringTo(` export type IMy_Type = { __typename?: 'My_Type'; linkTest?: Maybe; }; `); expect(result.content).toBeSimilarStringTo(`export type IMyUnion = IMy_Type | IMyType;`); expect(result.content).toBeSimilarStringTo(` export type ISome_Interface = { id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type IImpl1 = ISome_Interface & { __typename?: 'Impl1'; id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type IImpl_2 = ISome_Interface & { __typename?: 'Impl_2'; id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type IImpl_3 = ISome_Interface & { __typename?: 'impl_3'; id: Scalars['ID']['output']; }; `); expect(result.content).toBeSimilarStringTo(` export type IQuery = { __typename?: 'Query'; something?: Maybe; use_interface?: Maybe; }; `); validateTs(result); }); }); describe('Arguments', () => { it('Should generate correctly types for field arguments - with basic fields', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo(a: String!, b: String, c: [String], d: [Int!]!): String } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyTypeFooArgs = { a: Scalars['String']['input']; b?: InputMaybe; c?: InputMaybe>>; d: Array; }; `); validateTs(result); }); it('Should generate correctly types for field arguments - with default value', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo(a: String = "default", b: String! = "default", c: String, d: String!): String } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyTypeFooArgs = { a?: InputMaybe; b?: Scalars['String']['input']; c?: InputMaybe; d: Scalars['String']['input']; }; `); validateTs(result); }); it('Should generate correctly types for field arguments - with default value and avoidOptionals option set to true', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo(a: String = "default", b: String! = "default", c: String, d: String!): String } `); const result = (await plugin( schema, [], { avoidOptionals: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyTypeFooArgs = { a?: InputMaybe; b?: Scalars['String']['input']; c: InputMaybe; d: Scalars['String']['input']; }; `); validateTs(result); }); it('Should generate correctly types for field arguments - with input type', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { f: String } type MyType { foo(a: MyInput, b: MyInput!, c: [MyInput], d: [MyInput]!, e: [MyInput!]!): String } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyTypeFooArgs = { a?: InputMaybe; b: MyInput; c?: InputMaybe>>; d: Array>; e: Array; }; `); validateTs(result); }); it('Should add custom prefix for mutation arguments', async () => { const schema = buildSchema(/* GraphQL */ ` input Input { name: String } type Mutation { foo(id: ID, input: Input): String } `); const result = await plugin(schema, [], { typesPrefix: 'T' }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type TInput = { name?: InputMaybe; }; `); expect(result.content).toBeSimilarStringTo(` export type TMutation = { __typename?: 'Mutation'; foo?: Maybe; }; export type TMutationFooArgs = { id?: InputMaybe; input?: InputMaybe; }; `); validateTs(result); }); it('Should generate the correct type for a method with arguments (interface object)', async () => { const testSchema = buildSchema(/* GraphQL */ ` interface Node { text(arg1: String!, arg2: String): String } type Book implements Node { id: ID! text(arg: String, arg2: String!): String } type Query { books: [Book!]! } `); const result = await plugin(testSchema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type NodeTextArgs = { arg1: Scalars['String']['input']; arg2?: InputMaybe; }; `); await validateTs(result); }); it('Should generate correctly types for inputs with default value - #4273', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { a: String = "default" b: String! = "default" c: String d: String! } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyInput = { a?: InputMaybe; b?: Scalars['String']['input']; c?: InputMaybe; d: Scalars['String']['input']; }; `); validateTs(result); }); it('Should generate correctly types for inputs with default value and avoidOptionals.defaultValue set to true - #5112', async () => { const schema = buildSchema(/* GraphQL */ ` input MyInput { a: String = "default" b: String! = "default" c: String d: String! } `); const result = await plugin(schema, [], { avoidOptionals: { defaultValue: true } }, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export type MyInput = { a?: InputMaybe; b: Scalars['String']['input']; c?: InputMaybe; d: Scalars['String']['input']; }; `); validateTs(result); }); it('Should generate correctly types for field arguments with default value and avoidOptionals.defaultValue option set to true - #5112', async () => { const schema = buildSchema(/* GraphQL */ ` type MyType { foo(a: String = "default", b: String! = "default", c: String, d: String!): String } `); const result = (await plugin( schema, [], { avoidOptionals: { defaultValue: true } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export type MyTypeFooArgs = { a?: InputMaybe; b: Scalars['String']['input']; c?: InputMaybe; d: Scalars['String']['input']; }; `); validateTs(result); }); }); describe('Enum', () => { it('Should build basic enum correctly', async () => { const schema = buildSchema(`enum MyEnum { A, B, C }`); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toBeSimilarStringTo(` export enum MyEnum { A = 'A', B = 'B', C = 'C' } `); validateTs(result); }); it('Should build enum correctly with custom values', async () => { const schema = buildSchema(`enum MyEnum { A, B, C }`); const result = (await plugin( schema, [], { enumValues: { MyEnum: { A: 'SomeValue', B: 'TEST' } } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` export enum MyEnum { A = 'SomeValue', B = 'TEST', C = 'C' } `); validateTs(result); }); it('Should build enum correctly with custom imported enum', async () => { const schema = buildSchema(`enum MyEnum { A, B, C }`); const result = (await plugin( schema, [], { enumValues: { MyEnum: './my-file#MyEnum' } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).not.toContain(`export enum MyEnum`); expect(result.prepend).toContain(`import { MyEnum } from './my-file';`); validateTs(result); }); it('Should build enum correctly with custom imported enum from namespace with different name', async () => { const schema = buildSchema(`enum MyEnum { A, B, C }`); const result = (await plugin( schema, [], { enumValues: { MyEnum: './my-file#NS.ETest' } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).not.toContain(`export enum MyEnum`); expect(result.content).toContain(`export { MyEnum }`); expect(result.prepend).toContain(`import MyEnum = NS.ETest;`); expect(result.prepend).toContain(`import { NS } from './my-file';`); validateTs(result); }); it('Should build enum correctly with custom imported enum from namespace with same name', async () => { const schema = buildSchema(`enum MyEnum { A, B, C }`); const result = (await plugin( schema, [], { enumValues: { MyEnum: './my-file#NS.MyEnum' } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).not.toContain(`export enum MyEnum`); expect(result.content).toContain(`export { MyEnum };`); expect(result.prepend).toContain(`import MyEnum = NS.MyEnum;`); expect(result.prepend).toContain(`import { NS } from './my-file';`); validateTs(result); }); it('Should build enum correctly with custom imported enum with different name', async () => { const schema = buildSchema(`enum MyEnum { A, B, C } type Query { t: MyEnum }`); const result = (await plugin( schema, [], { enumValues: { MyEnum: './my-file#MyCustomEnum' } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).not.toContain(`export enum MyEnum`); expect(result.prepend).toContain(`import { MyCustomEnum as MyEnum } from './my-file';`); expect(result.content).toContain(`export { MyEnum };`); validateTs(result); }); it('Should import all enums from a single file when specified as string', async () => { const schema = buildSchema(`enum MyEnum { A, B, C } enum MyEnum2 { X, Y, Z }`); const result = (await plugin( schema, [], { enumValues: './my-file' }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).not.toContain(`export enum MyEnum`); expect(result.content).not.toContain(`export enum MyEnum2`); expect(result.prepend).toContain(`import { MyEnum } from './my-file';`); expect(result.prepend).toContain(`import { MyEnum2 } from './my-file';`); validateTs(result); }); it('Should re-export external enums', async () => { const schema = buildSchema(`enum MyEnum { A, B, C } enum MyEnum2 { X, Y, Z }`); const result = (await plugin( schema, [], { enumValues: { MyEnum: './my-file#MyEnum', MyEnum2: './my-file#MyEnum2X' } }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.content).toContain(`export { MyEnum };`); expect(result.content).toContain(`export { MyEnum2 };`); expect(result.prepend).toContain(`import { MyEnum2X as MyEnum2 } from './my-file';`); validateTs(result); }); it('Should re-export external enums when single file option used', async () => { const schema = buildSchema(`enum MyEnum { A, B, C } enum MyEnum2 { X, Y, Z }`); const result = (await plugin( schema, [], { enumValues: './my-file' }, { outputFile: '' } )) as Types.ComplexPluginOutput; expect(result.prepend).toContain(`import { MyEnum } from './my-file';`); expect(result.prepend).toContain(`import { MyEnum2 } from './my-file';`); expect(result.content).toContain(`export { MyEnum };`); expect(result.content).toContain(`export { MyEnum2 };`); validateTs(result); }); it('allowEnumStringTypes', async () => { const schema = buildSchema(/* GraphQL */ ` enum MyEnum { A B C } type Query { a: MyEnum } `); const result = (await plugin( schema, [], { allowEnumStringTypes: true }, { outputFile: '' } )) as Types.ComplexPluginOutput; validateTs(result); expect(result.content).toBeSimilarStringTo('a?: Maybe;'); }); }); it('should not have [object Object]', async () => { const schema = buildSchema(/* GraphQL */ ` type User { id: Int! name: String! email: String! } type QueryRoot { allUsers: [User]! userById(id: Int!): User # Generates a new answer for the guessing game answer: [Int!]! } type SubscriptionRoot { newUser: User } schema { query: QueryRoot subscription: SubscriptionRoot } `); const content = await plugin(schema, [], {}, { outputFile: '' }); expect(content).not.toContainEqual('[object Object]'); validateTs(content); }); it('should contain __typename', async () => { const schema = buildSchema(/* GraphQL */ ` type User { id: Int! name: String! email: String! } type QueryRoot { allUsers: [User]! userById(id: Int!): User # Generates a new answer for the guessing game answer: [Int!]! } type SubscriptionRoot { newUser: User } schema { query: QueryRoot subscription: SubscriptionRoot } `); const result = await plugin(schema, [], {}, { outputFile: '' }); expect(result.content).toContain('__typename'); validateTs(result); }); it('should not contain __typename', async () => { const schema = buildSchema(/* GraphQL */ ` type User { id: Int! name: String! email: String! } type QueryRoot { allUsers: [User]! userById(id: Int!): User # Generates a new answer for the guessing game answer: [Int!]! } type SubscriptionRoot { newUser: User } schema { query: QueryRoot subscription: SubscriptionRoot } `); const result = await plugin(schema, [], { skipTypename: true }, { outputFile: '' }); expect(result.content).not.toContain('__typename'); validateTs(result); }); it('should not contain "export" when noExport is set to true', async () => { const schema = buildSchema(/* GraphQL */ ` type User { id: Int! name: String! email: String! } type QueryRoot { allUsers: [User]! userById(id: Int!): User # Generates a new answer for the guessing game answer: [Int!]! } type SubscriptionRoot { newUser: User } schema { query: QueryRoot subscription: SubscriptionRoot } `); const result = await plugin(schema, [], { noExport: true }, { outputFile: '' }); expect(result.content).not.toContain('export'); validateTs(result); }); it('should keep non-optional arguments non-optional - issue #2323', async () => { const testSchema = buildSchema(/* GraphQL */ ` enum OrderBy { name id } input Filter { contain: String } type Node { id: ID! name: String! } type Connection { nodes: [Node] } type Query { list(after: String, orderBy: OrderBy = name, filter: Filter!): Connection! } `); const output = (await plugin( testSchema, [], { avoidOptionals: false, maybeValue: 'T | undefined', } as any, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; // Filter.contain should be optional expect(output.content).toBeSimilarStringTo(` export type Filter = { contain?: InputMaybe; }; `); // filter should be non-optional expect(output.content).toBeSimilarStringTo(` export type QueryListArgs = { after?: InputMaybe; orderBy?: InputMaybe; filter: Filter; }; `); }); it('should respect defined enum values', async () => { const testSchema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { foo: { type: new GraphQLEnumType({ name: 'Foo', values: { Bar: { value: 'Qux', }, }, }), }, }, }), }); const output = await plugin(testSchema, [], {}, { outputFile: 'graphql.ts' }); expect(output.content).toBeSimilarStringTo(` export enum Foo { Bar = 'Qux' } `); }); it('should use implementing types as node type - issue #5126', async () => { const testSchema = buildSchema(/* GraphQL */ ` type Matrix { pills: [Pill!]! } interface Pill { id: ID! } type RedPill implements Pill { red: String! } type GreenPill implements Pill { green: String! } interface Foo { id: ID! } type Bar implements Foo { lol: String! } type Hello { foo: Foo! } type NoInterface { hello: Hello! } interface NestedInterface implements Foo { field: String! } type NestedType1 implements NestedInterface { hi: String! } type NestedType2 implements NestedInterface { ho: String! } type NestedField { nested: NestedInterface! } `); const output = (await plugin( testSchema, [], { useImplementingTypes: true, } as any, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; expect(output.content).toMatchSnapshot(); // Type should be Array and not Pill expect(output.content).toBeSimilarStringTo(` export type Matrix = { __typename?: 'Matrix'; pills: Array; }; `); // Type should be Bar and not Foo expect(output.content).toBeSimilarStringTo(` export type Hello = { __typename?: 'Hello'; foo: Bar; }; `); // Type should be Hello and not empty expect(output.content).toBeSimilarStringTo(` export type NoInterface = { __typename?: 'NoInterface'; hello: Hello; }; `); // Type should be NestedType1|NestedType2 expect(output.content).toBeSimilarStringTo(` export type NestedField = { __typename?: 'NestedField'; nested: NestedType1 | NestedType2; }; `); }); }); ================================================ FILE: packages/plugins/typescript/typescript/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'typescript', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/presets/client/CHANGELOG.md ================================================ # @graphql-codegen/client-preset ## 5.2.4 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^11.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/11.0.0) (from `^10.0.0`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/gql-tag-operations@5.1.4 - @graphql-codegen/plugin-helpers@6.1.1 - @graphql-codegen/typed-document-node@6.1.7 - @graphql-codegen/typescript@5.0.9 - @graphql-codegen/typescript-operations@5.0.9 - @graphql-codegen/visitor-plugin-common@6.2.4 ## 5.2.3 ### Patch Changes - Updated dependencies [[`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf)]: - @graphql-codegen/visitor-plugin-common@6.2.3 - @graphql-codegen/typescript-operations@5.0.8 - @graphql-codegen/gql-tag-operations@5.1.3 - @graphql-codegen/typed-document-node@6.1.6 - @graphql-codegen/typescript@5.0.8 ## 5.2.2 ### Patch Changes - Updated dependencies [[`f588d91`](https://github.com/dotansimha/graphql-code-generator/commit/f588d91ac43ea0aa5931915ce980d2e6876bb59c)]: - @graphql-codegen/visitor-plugin-common@6.2.2 - @graphql-codegen/gql-tag-operations@5.1.2 - @graphql-codegen/typescript-operations@5.0.7 - @graphql-codegen/typed-document-node@6.1.5 - @graphql-codegen/typescript@5.0.7 ## 5.2.1 ### Patch Changes - Updated dependencies [[`b995ed1`](https://github.com/dotansimha/graphql-code-generator/commit/b995ed13a49379ea05e0e313fac68b557527523a)]: - @graphql-codegen/visitor-plugin-common@6.2.1 - @graphql-codegen/gql-tag-operations@5.1.1 - @graphql-codegen/typescript-operations@5.0.6 - @graphql-codegen/typed-document-node@6.1.4 - @graphql-codegen/typescript@5.0.6 ## 5.2.0 ### Minor Changes - [#10510](https://github.com/dotansimha/graphql-code-generator/pull/10510) [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670) Thanks [@nickmessing](https://github.com/nickmessing)! - add importExtension configuration option ### Patch Changes - Updated dependencies [[`f821e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f821e8ab9351f23a9f7e5d5e6fc69c8e8868cad8), [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/visitor-plugin-common@6.2.0 - @graphql-codegen/gql-tag-operations@5.1.0 - @graphql-codegen/plugin-helpers@6.1.0 - @graphql-codegen/typescript-operations@5.0.5 - @graphql-codegen/typed-document-node@6.1.3 - @graphql-codegen/typescript@5.0.5 ## 5.1.3 ### Patch Changes - [#10499](https://github.com/dotansimha/graphql-code-generator/pull/10499) [`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix nested fragment not getting correct meta field in Client Preset - Updated dependencies [[`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d)]: - @graphql-codegen/visitor-plugin-common@6.1.2 - @graphql-codegen/gql-tag-operations@5.0.5 - @graphql-codegen/typescript-operations@5.0.4 - @graphql-codegen/typed-document-node@6.1.2 - @graphql-codegen/typescript@5.0.4 ## 5.1.2 ### Patch Changes - Updated dependencies [[`6715330`](https://github.com/dotansimha/graphql-code-generator/commit/67153304646694d75aee24afd70c3fce12e9f1f2)]: - @graphql-codegen/visitor-plugin-common@6.1.1 - @graphql-codegen/gql-tag-operations@5.0.4 - @graphql-codegen/typescript-operations@5.0.3 - @graphql-codegen/typed-document-node@6.1.1 - @graphql-codegen/typescript@5.0.3 ## 5.1.1 ### Patch Changes - Updated dependencies [[`1debf51`](https://github.com/dotansimha/graphql-code-generator/commit/1debf51aa714e2a53256419c549f6770b6c894a6)]: - @graphql-codegen/gql-tag-operations@5.0.3 ## 5.1.0 ### Minor Changes - [#10459](https://github.com/dotansimha/graphql-code-generator/pull/10459) [`87184aa`](https://github.com/dotansimha/graphql-code-generator/commit/87184aa240cb6209e7b3ade13aa54da6ff0b3dff) Thanks [@eddeee888](https://github.com/eddeee888)! - Forward immutableTypes to client preset config ## 5.0.3 ### Patch Changes - Updated dependencies [[`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26)]: - @graphql-codegen/visitor-plugin-common@6.1.0 - @graphql-codegen/gql-tag-operations@5.0.2 - @graphql-codegen/typescript-operations@5.0.2 - @graphql-codegen/typed-document-node@6.0.2 - @graphql-codegen/typescript@5.0.2 ## 5.0.2 ### Patch Changes - Updated dependencies [[`accdab6`](https://github.com/dotansimha/graphql-code-generator/commit/accdab69106605241933e9d66d64dc7077656f30)]: - @graphql-codegen/visitor-plugin-common@6.0.1 - @graphql-codegen/gql-tag-operations@5.0.1 - @graphql-codegen/typescript-operations@5.0.1 - @graphql-codegen/typed-document-node@6.0.1 - @graphql-codegen/typescript@5.0.1 ## 5.0.1 ### Patch Changes - [#10393](https://github.com/dotansimha/graphql-code-generator/pull/10393) [`ee2276c`](https://github.com/dotansimha/graphql-code-generator/commit/ee2276cb073a87458eda957a17c9e296c1cf313a) Thanks [@eddeee888](https://github.com/eddeee888)! - Include undefined explicitly for input maybe value in Client Preset ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGE: Use Record instead of {} for empty object type - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Stop passing through the deprecated config option `dedupeFragments` - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/visitor-plugin-common@6.0.0 - @graphql-codegen/plugin-helpers@6.0.0 - @graphql-codegen/typescript@5.0.0 - @graphql-codegen/typescript-operations@5.0.0 - @graphql-codegen/add@6.0.0 - @graphql-codegen/gql-tag-operations@5.0.0 - @graphql-codegen/typed-document-node@6.0.0 ## 4.8.3 ### Patch Changes - [#10362](https://github.com/dotansimha/graphql-code-generator/pull/10362) [`3188b8c`](https://github.com/dotansimha/graphql-code-generator/commit/3188b8c39e9fd24e3dbbd0bcc8767052153eb399) Thanks [@Brookke](https://github.com/Brookke)! - Make generated type compatible with noImplicitOverride=true - [#10373](https://github.com/dotansimha/graphql-code-generator/pull/10373) [`c3295f9`](https://github.com/dotansimha/graphql-code-generator/commit/c3295f9c60383e5631ccc4080bc28e7c00a4d61b) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix client preset not working with exactOptionalPropertyTypes=true when documentMode=string - Updated dependencies [[`3188b8c`](https://github.com/dotansimha/graphql-code-generator/commit/3188b8c39e9fd24e3dbbd0bcc8767052153eb399), [`c3295f9`](https://github.com/dotansimha/graphql-code-generator/commit/c3295f9c60383e5631ccc4080bc28e7c00a4d61b)]: - @graphql-codegen/typed-document-node@5.1.2 ## 4.8.2 ### Patch Changes - [#10120](https://github.com/dotansimha/graphql-code-generator/pull/10120) [`98392fc`](https://github.com/dotansimha/graphql-code-generator/commit/98392fc5d91035b5b5b0ffdefd78d0398762a523) Thanks [@yangirov](https://github.com/yangirov)! - The `@graphql-codegen/client-preset` package now supports the `enumValues` option. - Updated dependencies [[`e324382`](https://github.com/dotansimha/graphql-code-generator/commit/e3243824cfe0d7ab463cf0d5a6455715510959be)]: - @graphql-codegen/plugin-helpers@5.1.1 ## 4.8.1 ### Patch Changes - [#10330](https://github.com/dotansimha/graphql-code-generator/pull/10330) [`c5efba3`](https://github.com/dotansimha/graphql-code-generator/commit/c5efba34a7b422720be9ce32937dd19fb0784bae) Thanks [@jnoordsij](https://github.com/jnoordsij)! - Make graphql-sock optional peerDep - Updated dependencies [[`c5efba3`](https://github.com/dotansimha/graphql-code-generator/commit/c5efba34a7b422720be9ce32937dd19fb0784bae)]: - @graphql-codegen/typescript-operations@4.6.1 ## 4.8.0 ### Minor Changes - [#10323](https://github.com/dotansimha/graphql-code-generator/pull/10323) [`f3cf4df`](https://github.com/dotansimha/graphql-code-generator/commit/f3cf4df358a896c5df0a7d8909c2fbf192e10c01) Thanks [@eddeee888](https://github.com/eddeee888)! - Add support for `nullability.errorHandlingClient`. This allows clients to get stronger types with [semantic nullability](https://github.com/graphql/graphql-wg/blob/main/rfcs/SemanticNullability.md)-enabled schemas. ### Patch Changes - Updated dependencies [[`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc), [`f3cf4df`](https://github.com/dotansimha/graphql-code-generator/commit/f3cf4df358a896c5df0a7d8909c2fbf192e10c01)]: - @graphql-codegen/visitor-plugin-common@5.8.0 - @graphql-codegen/typescript-operations@4.6.0 - @graphql-codegen/gql-tag-operations@4.0.17 - @graphql-codegen/typed-document-node@5.1.1 - @graphql-codegen/typescript@4.1.6 ## 4.7.0 ### Minor Changes - [#10307](https://github.com/dotansimha/graphql-code-generator/pull/10307) [`bfe3c75`](https://github.com/dotansimha/graphql-code-generator/commit/bfe3c7575e0b5f3a252fe9d72416f7829e44c885) Thanks [@mvantellingen](https://github.com/mvantellingen)! - Update generated code to be compatible with TypeScript 5.8 `erasableSyntaxOnly` flag ### Patch Changes - Updated dependencies [[`bfe3c75`](https://github.com/dotansimha/graphql-code-generator/commit/bfe3c7575e0b5f3a252fe9d72416f7829e44c885)]: - @graphql-codegen/typed-document-node@5.1.0 ## 4.6.4 ### Patch Changes - [#10302](https://github.com/dotansimha/graphql-code-generator/pull/10302) [`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix Apollo unmask directive incorrectly generating fragmentRefs - Updated dependencies [[`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a)]: - @graphql-codegen/visitor-plugin-common@5.7.1 - @graphql-codegen/typescript-operations@4.5.1 - @graphql-codegen/gql-tag-operations@4.0.16 - @graphql-codegen/typed-document-node@5.0.15 - @graphql-codegen/typescript@4.1.5 ## 4.6.3 ### Patch Changes - [#10298](https://github.com/dotansimha/graphql-code-generator/pull/10298) [`3efc472`](https://github.com/dotansimha/graphql-code-generator/commit/3efc472b970754b05b1e1f9fe7d33cfa5ec65455) Thanks [@dotansimha](https://github.com/dotansimha)! - Fix a bug where fragment spreads with `@client` directives is not being removed from the generated persisted documents - Updated dependencies [[`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c)]: - @graphql-codegen/visitor-plugin-common@5.7.0 - @graphql-codegen/typescript-operations@4.5.0 - @graphql-codegen/gql-tag-operations@4.0.15 - @graphql-codegen/typed-document-node@5.0.14 - @graphql-codegen/typescript@4.1.4 ## 4.6.2 ### Patch Changes - [#10280](https://github.com/dotansimha/graphql-code-generator/pull/10280) [`6da52a3`](https://github.com/dotansimha/graphql-code-generator/commit/6da52a3248c0ac9ef32140d130ac3da6fcaa1445) Thanks [@konomae](https://github.com/konomae)! - fix `onlyEnums` passthrough in client-preset ## 4.6.1 ### Patch Changes - Updated dependencies [[`ec07018`](https://github.com/dotansimha/graphql-code-generator/commit/ec070189a1a3c4d41f2457b56a68b506c81f28ba)]: - @graphql-codegen/gql-tag-operations@4.0.14 ## 4.6.0 ### Minor Changes - [#10268](https://github.com/dotansimha/graphql-code-generator/pull/10268) [`8737dd8`](https://github.com/dotansimha/graphql-code-generator/commit/8737dd86b4ce3d14234a515fa494736bf7ec35dd) Thanks [@eddeee888](https://github.com/eddeee888)! - Forward customDirectives to support Apollo unmask - [#10155](https://github.com/dotansimha/graphql-code-generator/pull/10155) [`ed71811`](https://github.com/dotansimha/graphql-code-generator/commit/ed71811ace083be61c575609e361c629ed7c1740) Thanks [@nebbles](https://github.com/nebbles)! - client-preset generated output is configurable with onlyOperationTypes and onlyEnumTypes ### Patch Changes - Updated dependencies [[`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517)]: - @graphql-codegen/visitor-plugin-common@5.6.1 - @graphql-codegen/gql-tag-operations@4.0.13 - @graphql-codegen/typescript-operations@4.4.1 - @graphql-codegen/typed-document-node@5.0.13 - @graphql-codegen/typescript@4.1.3 ## 4.5.1 ### Patch Changes - [#9981](https://github.com/dotansimha/graphql-code-generator/pull/9981) [`05aa6b4`](https://github.com/dotansimha/graphql-code-generator/commit/05aa6b4cee6214674b25c9d20df27ce5e0e3927c) Thanks [@azu](https://github.com/azu)! - The client preset now allows the use of the `enumsAsConst` config option - Updated dependencies [[`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a), [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba)]: - @graphql-codegen/visitor-plugin-common@5.6.0 - @graphql-codegen/typescript-operations@4.4.0 - @graphql-codegen/gql-tag-operations@4.0.12 - @graphql-codegen/typed-document-node@5.0.12 - @graphql-codegen/typescript@4.1.2 ## 4.5.0 ### Minor Changes - [#10136](https://github.com/dotansimha/graphql-code-generator/pull/10136) [`3fd4486`](https://github.com/dotansimha/graphql-code-generator/commit/3fd4486a548c27099377c7bd696a22d1638227f4) Thanks [@wxt2005](https://github.com/wxt2005)! - foward skipTypeNameForRoot to client-preset ### Patch Changes - [#10182](https://github.com/dotansimha/graphql-code-generator/pull/10182) [`effd875`](https://github.com/dotansimha/graphql-code-generator/commit/effd875b205fa9c5a99ce5e7fcdeb86cea7723fc) Thanks [@eddeee888](https://github.com/eddeee888)! - Revert slimmer client preset output - Updated dependencies [[`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc), [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03), [`c7af639`](https://github.com/dotansimha/graphql-code-generator/commit/c7af63964089938150402db69d49f11f93bb5175)]: - @graphql-codegen/visitor-plugin-common@5.5.0 - @graphql-codegen/plugin-helpers@5.1.0 - @graphql-codegen/typed-document-node@5.0.11 - @graphql-codegen/gql-tag-operations@4.0.11 - @graphql-codegen/typescript-operations@4.3.1 - @graphql-codegen/typescript@4.1.1 ## 4.4.0 ### Minor Changes - [#10073](https://github.com/dotansimha/graphql-code-generator/pull/10073) [`8471a18`](https://github.com/dotansimha/graphql-code-generator/commit/8471a180cd61dc03dedace87876c5973b09b35f8) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Reduce noise of generated code by only generating code relevant to GraphQL operations. ### Patch Changes - [#10075](https://github.com/dotansimha/graphql-code-generator/pull/10075) [`67e7556`](https://github.com/dotansimha/graphql-code-generator/commit/67e75561a3e862f26cfbb40e8ec5a08f821f9ddf) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Add note about enabling bundle size reduction for the generated `graphql` tag file. - Updated dependencies [[`67e7556`](https://github.com/dotansimha/graphql-code-generator/commit/67e75561a3e862f26cfbb40e8ec5a08f821f9ddf), [`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4)]: - @graphql-codegen/gql-tag-operations@4.0.10 - @graphql-codegen/visitor-plugin-common@5.4.0 - @graphql-codegen/typescript-operations@4.3.0 - @graphql-codegen/typescript@4.1.0 - @graphql-codegen/typed-document-node@5.0.10 ## 4.3.3 ### Patch Changes - [#9817](https://github.com/dotansimha/graphql-code-generator/pull/9817) [`7ac42a3`](https://github.com/dotansimha/graphql-code-generator/commit/7ac42a33915985b9504bc16f38a22e057bbcd1ab) Thanks [@nikitalocalhost](https://github.com/nikitalocalhost)! - Resolve runtime error when using the babel plugin within an ESM environment. ## 4.3.2 ### Patch Changes - Updated dependencies [[`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2)]: - @graphql-codegen/visitor-plugin-common@5.3.1 - @graphql-codegen/gql-tag-operations@4.0.9 - @graphql-codegen/typescript-operations@4.2.3 - @graphql-codegen/typed-document-node@5.0.9 - @graphql-codegen/typescript@4.0.9 ## 4.3.1 ### Patch Changes - Updated dependencies [[`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3), [`14ce39e`](https://github.com/dotansimha/graphql-code-generator/commit/14ce39e41dfee38c652be736664177fa2b1df421)]: - @graphql-codegen/visitor-plugin-common@5.3.0 - @graphql-codegen/gql-tag-operations@4.0.8 - @graphql-codegen/typescript-operations@4.2.2 - @graphql-codegen/typed-document-node@5.0.8 - @graphql-codegen/typescript@4.0.8 ## 4.3.0 ### Minor Changes - [#10001](https://github.com/dotansimha/graphql-code-generator/pull/10001) [`1be6e65`](https://github.com/dotansimha/graphql-code-generator/commit/1be6e65943b85162f3d465189d0a6df4b962df5d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Support discriminating `null` and `undefined` within the `useFragment` function. ```ts function MyComponent(props: FragmentType | null) { const data = useFragment(MyFragment, props) // data is `MyFragment | null` } function MyComponent(props: FragmentType | undefined) { const data = useFragment(MyFragment, props) // data is `MyFragment | undefined` } ``` Before, the returned type from `useFragment` was always `TType | null | undefined`. - [#9804](https://github.com/dotansimha/graphql-code-generator/pull/9804) [`5e594ef`](https://github.com/dotansimha/graphql-code-generator/commit/5e594ef8f39b9e1036b6bcaa977f914a66fec03e) Thanks [@rachel-church](https://github.com/rachel-church)! - Preserving `Array` or `ReadonlyArray` in `useFragment()` return type. ### Patch Changes - [#9996](https://github.com/dotansimha/graphql-code-generator/pull/9996) [`99f449c`](https://github.com/dotansimha/graphql-code-generator/commit/99f449c8dcd645d49eda26e4ddfcb8ad7056ecbf) Thanks [@nahn20](https://github.com/nahn20)! - Added configuration to allow for custom hash functions for persisted documents in the client preset ### Example ```ts filename="codegen.ts" {10-12} import { type CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'schema.graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', presetConfig: { persistedDocuments: { hashAlgorithm: operation => { const shasum = crypto.createHash('sha512') shasum.update(operation) return shasum.digest('hex') } } } } } } ``` - Updated dependencies [[`5501c62`](https://github.com/dotansimha/graphql-code-generator/commit/5501c621f19eb5ef8e703a21f7367e07e41f199c)]: - @graphql-codegen/add@5.0.3 ## 4.2.6 ### Patch Changes - Updated dependencies [[`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431), [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e)]: - @graphql-codegen/plugin-helpers@5.0.4 - @graphql-codegen/visitor-plugin-common@5.2.0 - @graphql-codegen/gql-tag-operations@4.0.7 - @graphql-codegen/typescript-operations@4.2.1 - @graphql-codegen/typed-document-node@5.0.7 - @graphql-codegen/typescript@4.0.7 ## 4.2.5 ### Patch Changes - [#9889](https://github.com/dotansimha/graphql-code-generator/pull/9889) [`cd60e14`](https://github.com/dotansimha/graphql-code-generator/commit/cd60e14c4dc5a496a93089dae677fc797c04671e) Thanks [@Sojaner](https://github.com/Sojaner)! - Omit `__typename` from being added on the root node of a subscription when using `addTypenameSelectionDocumentTransform` with documentTransforms since a single root node is expected and the code generator fails because of that (refer to https://spec.graphql.org/draft/#sec-Single-root-field) ## 4.2.4 ### Patch Changes - Updated dependencies [[`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53), [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d)]: - @graphql-codegen/visitor-plugin-common@5.1.0 - @graphql-codegen/typescript-operations@4.2.0 - @graphql-codegen/gql-tag-operations@4.0.6 - @graphql-codegen/typed-document-node@5.0.6 - @graphql-codegen/typescript@4.0.6 ## 4.2.3 ### Patch Changes - Updated dependencies [[`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5)]: - @graphql-codegen/visitor-plugin-common@5.0.0 - @graphql-codegen/gql-tag-operations@4.0.5 - @graphql-codegen/typescript-operations@4.1.3 - @graphql-codegen/typed-document-node@5.0.5 - @graphql-codegen/typescript@4.0.5 ## 4.2.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/visitor-plugin-common@4.1.2 - @graphql-codegen/typescript-operations@4.1.2 - @graphql-codegen/add@5.0.2 - @graphql-codegen/gql-tag-operations@4.0.4 - @graphql-codegen/typed-document-node@5.0.4 - @graphql-codegen/typescript@4.0.4 - @graphql-codegen/plugin-helpers@5.0.3 ## 4.2.1 ### Patch Changes - [#9557](https://github.com/dotansimha/graphql-code-generator/pull/9557) [`48ddaeae1`](https://github.com/dotansimha/graphql-code-generator/commit/48ddaeae1809cb52e6de5aa14f0d47bedde9d547) Thanks [@konomae](https://github.com/konomae)! - Add eslint-disable comment to fragment-masking.ts - Updated dependencies [[`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f)]: - @graphql-codegen/visitor-plugin-common@4.1.1 - @graphql-codegen/gql-tag-operations@4.0.3 - @graphql-codegen/typescript-operations@4.1.1 - @graphql-codegen/typed-document-node@5.0.3 - @graphql-codegen/typescript@4.0.3 ## 4.2.0 ### Minor Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - The client preset now allows the use of the `futureProofEnums` config option ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/add@5.0.1 - @graphql-codegen/gql-tag-operations@4.0.2 - @graphql-codegen/plugin-helpers@5.0.2 - @graphql-codegen/typed-document-node@5.0.2 - @graphql-codegen/typescript@4.0.2 - @graphql-codegen/typescript-operations@4.1.0 - @graphql-codegen/visitor-plugin-common@4.1.0 ## 4.1.0 ### Minor Changes - [#9562](https://github.com/dotansimha/graphql-code-generator/pull/9562) [`5beee9794`](https://github.com/dotansimha/graphql-code-generator/commit/5beee9794de208fed17e516a259535f56d626c9d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Add the `addTypenameSelectionDocumentTransform` for automatically adding `__typename` selections to all objct type selection sets. This is useful for GraphQL Clients such as Apollo Client or urql that need typename information for their cache to function. **Example Usage** ``` import { addTypenameSelectionDocumentTransform } from '@graphql-codegen/client-preset'; import { CodegenConfig } from "@graphql-codegen/cli"; const config: CodegenConfig = { schema: "YOUR_GRAPHQL_ENDPOINT", documents: ["./**/*.{ts,tsx}"], ignoreNoDocuments: true, generates: { "./gql/": { preset: "client", plugins: [], presetConfig: { persistedDocuments: true, }, documentTransforms: [addTypenameSelectionDocumentTransform], }, }, }; export default config; ``` ### Patch Changes - Updated dependencies [[`bb1e0e96e`](https://github.com/dotansimha/graphql-code-generator/commit/bb1e0e96ed9d519684630cd7ea53869b48b4632e)]: - @graphql-codegen/plugin-helpers@5.0.1 ## 4.0.1 ### Patch Changes - [#9497](https://github.com/dotansimha/graphql-code-generator/pull/9497) [`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a) Thanks [@eddeee888](https://github.com/eddeee888)! - Revert default ID scalar input type to string We changed the ID Scalar input type from `string` to `string | number` in the latest major version of `typescript` plugin. This causes issues for server plugins (e.g. typescript-resolvers) that depends on `typescript` plugin. This is because the scalar type needs to be manually inverted on setup which is confusing. - Updated dependencies [[`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a)]: - @graphql-codegen/visitor-plugin-common@4.0.1 - @graphql-codegen/typescript-operations@4.0.1 - @graphql-codegen/typescript@4.0.1 - @graphql-codegen/gql-tag-operations@4.0.1 - @graphql-codegen/typed-document-node@5.0.1 ## 4.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Minor Changes - [#9196](https://github.com/dotansimha/graphql-code-generator/pull/9196) [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96) Thanks [@beerose](https://github.com/beerose)! - Add `@defer` directive support When a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved. Once start using the `@defer` directive in your queries, the generated code will automatically include support for the directive. ```jsx // src/index.tsx import { graphql } from './gql' const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `) const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `) ``` The generated type for `GetUserQuery` will have information that the fragment is _incremental,_ meaning it may not be available right away. ```tsx // gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query' } & { ' $fragmentRefs'?: { OrdersFragment: Incremental } }) ``` Apart from generating code that includes support for the `@defer` directive, the Codegen also exports a utility function called `isFragmentReady`. You can use it to conditionally render components based on whether the data for a deferred fragment is available: ```jsx const OrdersList = (props: { data: FragmentType }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && } )} ); } export default App; ``` - [#9353](https://github.com/dotansimha/graphql-code-generator/pull/9353) [`d7e335b58`](https://github.com/dotansimha/graphql-code-generator/commit/d7e335b5874a821c9f609c66d554921ed8c6de19) Thanks [@charpeni](https://github.com/charpeni)! - Implement the ability the specify the hash algorithm used for persisted documents via `persistedDocuments.hashAlgorithm` ### Patch Changes - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-tools/documents@^1.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/documents/v/1.0.0) (from `^0.1.0`, in `dependencies`) - Updated dependency [`@graphql-tools/utils@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/10.0.0) (from `^9.0.0`, in `dependencies`) - [#9315](https://github.com/dotansimha/graphql-code-generator/pull/9315) [`6d2de206a`](https://github.com/dotansimha/graphql-code-generator/commit/6d2de206abdcce9e176bbc157cd27b37a20b0f97) Thanks [@luvejo](https://github.com/luvejo)! - improve error message - [#9385](https://github.com/dotansimha/graphql-code-generator/pull/9385) [`a7dda3546`](https://github.com/dotansimha/graphql-code-generator/commit/a7dda3546567b5bb70015fc3ae197562231d7911) Thanks [@beerose](https://github.com/beerose)! - Improve isFragmentReady utility function to work with noUncheckedIndexedAccess TSC setting - [#9196](https://github.com/dotansimha/graphql-code-generator/pull/9196) [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96) Thanks [@beerose](https://github.com/beerose)! - Pass `emitLegacyCommonJSImports` and `isStringDocumentMode` to the client preset config - [#9414](https://github.com/dotansimha/graphql-code-generator/pull/9414) [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d) Thanks [@beerose](https://github.com/beerose)! - Include nested fragments in string documentMode - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96), [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c), [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d), [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0), [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c)]: - @graphql-codegen/gql-tag-operations@4.0.0 - @graphql-codegen/plugin-helpers@5.0.0 - @graphql-codegen/visitor-plugin-common@4.0.0 - @graphql-codegen/typed-document-node@5.0.0 - @graphql-codegen/typescript-operations@4.0.0 - @graphql-codegen/typescript@4.0.0 - @graphql-codegen/add@5.0.0 ## 3.0.1 ### Patch Changes - Updated dependencies [[`386cf9044`](https://github.com/dotansimha/graphql-code-generator/commit/386cf9044a41d87ed45069b22d26b30f4b262a85), [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00)]: - @graphql-codegen/visitor-plugin-common@3.1.1 - @graphql-codegen/gql-tag-operations@3.0.1 - @graphql-codegen/typescript-operations@3.0.4 - @graphql-codegen/typed-document-node@4.0.1 - @graphql-codegen/typescript@3.0.4 ## 3.0.0 ### Major Changes - [#9137](https://github.com/dotansimha/graphql-code-generator/pull/9137) [`2256c8b5d`](https://github.com/dotansimha/graphql-code-generator/commit/2256c8b5d0e13057d35692bbeba3b7b8f94d8712) Thanks [@beerose](https://github.com/beerose)! - Add `TypedDocumentNode` string alternative that doesn't require GraphQL AST on the client. This change requires `@graphql-typed-document-node/core` in version `3.2.0` or higher. ### Patch Changes - [#9137](https://github.com/dotansimha/graphql-code-generator/pull/9137) [`2256c8b5d`](https://github.com/dotansimha/graphql-code-generator/commit/2256c8b5d0e13057d35692bbeba3b7b8f94d8712) Thanks [@beerose](https://github.com/beerose)! - dependencies updates: - Updated dependency [`@graphql-typed-document-node/core@3.2.0` ↗︎](https://www.npmjs.com/package/@graphql-typed-document-node/core/v/3.2.0) (from `3.1.2`, in `dependencies`) - Updated dependencies [[`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835), [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087), [`92d86b009`](https://github.com/dotansimha/graphql-code-generator/commit/92d86b009579edf70f60b0b8e28658af93ff9fd1), [`2256c8b5d`](https://github.com/dotansimha/graphql-code-generator/commit/2256c8b5d0e13057d35692bbeba3b7b8f94d8712), [`acb647e4e`](https://github.com/dotansimha/graphql-code-generator/commit/acb647e4efbddecf732b6e55dc47ac40c9bdaf08), [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd)]: - @graphql-codegen/visitor-plugin-common@3.1.0 - @graphql-codegen/plugin-helpers@4.2.0 - @graphql-codegen/typescript@3.0.3 - @graphql-codegen/typed-document-node@4.0.0 - @graphql-codegen/gql-tag-operations@3.0.0 - @graphql-codegen/typescript-operations@3.0.3 ## 2.1.1 ### Patch Changes - [#9049](https://github.com/dotansimha/graphql-code-generator/pull/9049) [`9430c3811`](https://github.com/dotansimha/graphql-code-generator/commit/9430c38111579c8c0023cbabfae047156ae2df42) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-typed-document-node/core@3.1.2` ↗︎](https://www.npmjs.com/package/@graphql-typed-document-node/core/v/3.1.2) (from `3.1.1`, in `dependencies`) - Updated dependencies [[`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a), [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc), [`b343626c9`](https://github.com/dotansimha/graphql-code-generator/commit/b343626c978b9ee0f14e314cea6c01ae3dad057c)]: - @graphql-codegen/visitor-plugin-common@3.0.2 - @graphql-codegen/gql-tag-operations@2.0.2 - @graphql-codegen/typescript-operations@3.0.2 - @graphql-codegen/typed-document-node@3.0.2 - @graphql-codegen/typescript@3.0.2 ## 2.1.0 ### Minor Changes - [#8893](https://github.com/dotansimha/graphql-code-generator/pull/8893) [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c) Thanks [@n1ru4l](https://github.com/n1ru4l)! - It is no longer mandatory to declare an empty plugins array when using a preset - [#8723](https://github.com/dotansimha/graphql-code-generator/pull/8723) [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15) Thanks [@kazekyo](https://github.com/kazekyo)! - Introduce a new feature called DocumentTransform. DocumentTransform is a functionality that allows you to modify `documents` before they are processed by plugins. You can use functions passed to the `documentTransforms` option to make changes to GraphQL documents. To use this feature, you can write `documentTransforms` as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { // Make some changes to the documents return documents } } ] } } } export default config ``` For instance, to remove a `@localOnlyDirective` directive from `documents`, you can write the following code: ```js import type { CodegenConfig } from '@graphql-codegen/cli' import { visit } from 'graphql' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { return documents.map(documentFile => { documentFile.document = visit(documentFile.document, { Directive: { leave(node) { if (node.name.value === 'localOnlyDirective') return null } } }) return documentFile }) } } ] } } } export default config ``` DocumentTransform can also be specified by file name. You can create a custom file for a specific transformation and pass it to `documentTransforms`. Let's create the document transform as a file: ```js module.exports = { transform: ({ documents }) => { // Make some changes to the documents return documents } } ``` Then, you can specify the file name as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: ['./my-document-transform.js'] } } } export default config ``` ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - [#8995](https://github.com/dotansimha/graphql-code-generator/pull/8995) [`fe2e9c7a5`](https://github.com/dotansimha/graphql-code-generator/commit/fe2e9c7a5f2731e06dd285e391936608dfa3fb51) Thanks [@charpeni](https://github.com/charpeni)! - Use `gqlTagName` for generated examples - [#8971](https://github.com/dotansimha/graphql-code-generator/pull/8971) [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Allow passing fragment documents to APIs like Apollos `readFragment` - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`fe2e9c7a5`](https://github.com/dotansimha/graphql-code-generator/commit/fe2e9c7a5f2731e06dd285e391936608dfa3fb51), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/add@4.0.1 - @graphql-codegen/gql-tag-operations@2.0.1 - @graphql-codegen/plugin-helpers@4.1.0 - @graphql-codegen/typed-document-node@3.0.1 - @graphql-codegen/typescript@3.0.1 - @graphql-codegen/typescript-operations@3.0.1 - @graphql-codegen/visitor-plugin-common@3.0.1 ## 2.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@babel/helper-plugin-utils@^7.20.2` ↗︎](https://www.npmjs.com/package/@babel/helper-plugin-utils/v/7.20.2) (from `^7.14.5`, in `dependencies`) - Updated dependency [`@babel/template@^7.20.7` ↗︎](https://www.npmjs.com/package/@babel/template/v/7.20.7) (from `^7.15.4`, in `dependencies`) - [#8871](https://github.com/dotansimha/graphql-code-generator/pull/8871) [`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5) Thanks [@B2o5T](https://github.com/B2o5T)! - eslint fixes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/visitor-plugin-common@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 - @graphql-codegen/add@4.0.0 - @graphql-codegen/gql-tag-operations@2.0.0 - @graphql-codegen/typescript-operations@3.0.0 - @graphql-codegen/typed-document-node@3.0.0 - @graphql-codegen/typescript@3.0.0 ## 1.3.0 ### Minor Changes - [#8757](https://github.com/dotansimha/graphql-code-generator/pull/8757) [`4f290aa72`](https://github.com/dotansimha/graphql-code-generator/commit/4f290aa7279a05ffa40920c1c9e5e5b37c164335) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Add support for persisted documents. You can now generate and embed a persisted documents hash for the executable documents. ```ts /** codegen.ts */ import { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx'], ignoreNoDocuments: true, // for better experience with the watcher generates: { './src/gql/': { preset: 'client', plugins: [], presetConfig: { persistedDocuments: true } } } } export default config ``` This will generate `./src/gql/persisted-documents.json` (dictionary of hashes with their operation string). In addition to that each generated document node will have a `__meta__.hash` property. ```ts import { gql } from './gql.js' const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `) console.log((allFilmsWithVariablesQueryDocument as any)['__meta__']['hash']) ``` - [#8757](https://github.com/dotansimha/graphql-code-generator/pull/8757) [`4f290aa72`](https://github.com/dotansimha/graphql-code-generator/commit/4f290aa7279a05ffa40920c1c9e5e5b37c164335) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Add support for embedding metadata in the document AST. It is now possible to embed metadata (e.g. for your GraphQL client within the emitted code). ```ts /** codegen.ts */ import { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://graphql.org/graphql/', documents: ['src/**/*.tsx'], ignoreNoDocuments: true, // for better experience with the watcher generates: { './src/gql/': { preset: 'client', plugins: [], presetConfig: { onExecutableDocumentNode(documentNode) { return { operation: documentNode.definitions[0].operation, name: documentNode.definitions[0].name.value } } } } } } export default config ``` You can then access the metadata via the `__meta__` property on the document node. ```ts import { gql } from './gql.js' const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { allFilms(first: $first) { edges { node { ...FilmItem } } } } `) console.log((allFilmsWithVariablesQueryDocument as any)['__meta__']) ``` ### Patch Changes - [#8757](https://github.com/dotansimha/graphql-code-generator/pull/8757) [`4f290aa72`](https://github.com/dotansimha/graphql-code-generator/commit/4f290aa7279a05ffa40920c1c9e5e5b37c164335) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Added dependency [`@graphql-tools/documents@^0.1.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/documents/v/0.1.0) (to `dependencies`) - Updated dependencies [[`a98198524`](https://github.com/dotansimha/graphql-code-generator/commit/a9819852443884b43de7c15040ccffc205f9177a)]: - @graphql-codegen/visitor-plugin-common@2.13.8 - @graphql-codegen/gql-tag-operations@1.6.2 - @graphql-codegen/typescript-operations@2.5.13 - @graphql-codegen/typed-document-node@2.3.13 - @graphql-codegen/typescript@2.8.8 ## 1.2.6 ### Patch Changes - [#8796](https://github.com/dotansimha/graphql-code-generator/pull/8796) [`902451601`](https://github.com/dotansimha/graphql-code-generator/commit/902451601b5edf9cb7768e57f332fe6ade79c20a) Thanks [@shmax](https://github.com/shmax)! - remove extra asterisk and add missing semicolon in generated output - Updated dependencies [[`902451601`](https://github.com/dotansimha/graphql-code-generator/commit/902451601b5edf9cb7768e57f332fe6ade79c20a)]: - @graphql-codegen/gql-tag-operations@1.6.1 ## 1.2.5 ### Patch Changes - Updated dependencies [[`eb454d06c`](https://github.com/dotansimha/graphql-code-generator/commit/eb454d06c977f11f7d4a7b0b07eb80f8fd590560), [`2a33fc774`](https://github.com/dotansimha/graphql-code-generator/commit/2a33fc7741f7a9532bef68606666d4e3db7785a3)]: - @graphql-codegen/visitor-plugin-common@2.13.7 - @graphql-codegen/gql-tag-operations@1.6.0 - @graphql-codegen/typescript-operations@2.5.12 - @graphql-codegen/typed-document-node@2.3.12 - @graphql-codegen/typescript@2.8.7 ## 1.2.4 ### Patch Changes - [#8771](https://github.com/dotansimha/graphql-code-generator/pull/8771) [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.8.0`, in `dependencies`) - [#8752](https://github.com/dotansimha/graphql-code-generator/pull/8752) [`cbca5a7ea`](https://github.com/dotansimha/graphql-code-generator/commit/cbca5a7ea3591f7ccf42399842cddb3581b40cf7) Thanks [@pbrink231](https://github.com/pbrink231)! - add typescript `avoidOptionals` to forwarded config - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/gql-tag-operations@1.5.12 - @graphql-codegen/plugin-helpers@3.1.2 - @graphql-codegen/visitor-plugin-common@2.13.6 - @graphql-codegen/typescript-operations@2.5.11 - @graphql-codegen/typed-document-node@2.3.11 - @graphql-codegen/typescript@2.8.6 ## 1.2.3 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/add@3.2.3 - @graphql-codegen/visitor-plugin-common@2.13.5 - @graphql-codegen/gql-tag-operations@1.5.11 - @graphql-codegen/typescript-operations@2.5.10 - @graphql-codegen/typed-document-node@2.3.10 - @graphql-codegen/typescript@2.8.5 ## 1.2.2 ### Patch Changes - [#8702](https://github.com/dotansimha/graphql-code-generator/pull/8702) [`0eb0dde8a`](https://github.com/dotansimha/graphql-code-generator/commit/0eb0dde8a0eb89805711287798561a0b14b6dd59) Thanks [@ithinkdancan](https://github.com/ithinkdancan)! - add config for nonOptionalTypename - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/typed-document-node@2.3.9 - @graphql-codegen/visitor-plugin-common@2.13.4 - @graphql-codegen/add@3.2.2 - @graphql-codegen/gql-tag-operations@1.5.10 - @graphql-codegen/typescript-operations@2.5.9 - @graphql-codegen/typescript@2.8.4 ## 1.2.1 ### Patch Changes - Updated dependencies [[`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe)]: - @graphql-codegen/visitor-plugin-common@2.13.3 - @graphql-codegen/typescript-operations@2.5.8 - @graphql-codegen/gql-tag-operations@1.5.9 - @graphql-codegen/typed-document-node@2.3.8 - @graphql-codegen/typescript@2.8.3 ## 1.2.0 ### Minor Changes - [#8657](https://github.com/dotansimha/graphql-code-generator/pull/8657) [`4b96035a8`](https://github.com/dotansimha/graphql-code-generator/commit/4b96035a8e0abca6715db586e8915ae968c403c6) Thanks [@charlypoly](https://github.com/charlypoly)! - Export a testing helper: `makeFragmentData(data, fragment)` ## 1.1.5 ### Patch Changes - Updated dependencies [[`00ddc9368`](https://github.com/dotansimha/graphql-code-generator/commit/00ddc9368211a4511b9f80d543d57c85fff840cb)]: - @graphql-codegen/gql-tag-operations@1.5.8 ## 1.1.4 ### Patch Changes - Updated dependencies [[`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122)]: - @graphql-codegen/visitor-plugin-common@2.13.2 - @graphql-codegen/typescript@2.8.2 - @graphql-codegen/gql-tag-operations@1.5.7 - @graphql-codegen/typescript-operations@2.5.7 - @graphql-codegen/typed-document-node@2.3.7 ## 1.1.3 ### Patch Changes - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/visitor-plugin-common@2.13.1 - @graphql-codegen/plugin-helpers@2.7.2 - @graphql-codegen/gql-tag-operations@1.5.6 - @graphql-codegen/typescript-operations@2.5.6 - @graphql-codegen/typed-document-node@2.3.6 - @graphql-codegen/typescript@2.8.1 ## 1.1.2 ### Patch Changes - [#8545](https://github.com/dotansimha/graphql-code-generator/pull/8545) [`3e7792486`](https://github.com/dotansimha/graphql-code-generator/commit/3e7792486e088a0dc10a0e3e4f5e0dff2ca031de) Thanks [@tojump](https://github.com/tojump)! - Forward dedupeFragments config option ## 1.1.1 ### Patch Changes - [#8523](https://github.com/dotansimha/graphql-code-generator/pull/8523) [`3a3202fbb`](https://github.com/dotansimha/graphql-code-generator/commit/3a3202fbb671617d34075040e7aa8129650bbcb1) Thanks [@charlypoly](https://github.com/charlypoly)! - allow non-typescript plugins ## 1.1.0 ### Minor Changes - [#8498](https://github.com/dotansimha/graphql-code-generator/pull/8498) [`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b) Thanks [@charlypoly](https://github.com/charlypoly)! - Fragment masking ` $fragmentName` and ` $fragmentRefs` are optionals ### Patch Changes - [#8500](https://github.com/dotansimha/graphql-code-generator/pull/8500) [`71aae7a92`](https://github.com/dotansimha/graphql-code-generator/commit/71aae7a92f77ec5ce29631b292d84e066219ea35) Thanks [@charlypoly](https://github.com/charlypoly)! - Add warning and errors to prevent unwanted configuration - Updated dependencies [[`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b)]: - @graphql-codegen/visitor-plugin-common@2.13.0 - @graphql-codegen/gql-tag-operations@1.5.5 - @graphql-codegen/typescript-operations@2.5.5 - @graphql-codegen/typed-document-node@2.3.5 - @graphql-codegen/typescript@2.7.5 ## 1.0.7 ### Patch Changes - [#8472](https://github.com/dotansimha/graphql-code-generator/pull/8472) [`a08fb6502`](https://github.com/dotansimha/graphql-code-generator/commit/a08fb6502f5dec6babcb78dbecd621f05a3e300c) Thanks [@panusoi](https://github.com/panusoi)! - The client preset now allows the use of the `enumsAsTypes` config option ## 1.0.6 ### Patch Changes - Updated dependencies [[`1bd7f771c`](https://github.com/dotansimha/graphql-code-generator/commit/1bd7f771ccb949a5a37395c7c57cb41c19340714)]: - @graphql-codegen/visitor-plugin-common@2.12.2 - @graphql-codegen/gql-tag-operations@1.5.4 - @graphql-codegen/typescript-operations@2.5.4 - @graphql-codegen/typed-document-node@2.3.4 - @graphql-codegen/typescript@2.7.4 ## 1.0.5 ### Patch Changes - [#8457](https://github.com/dotansimha/graphql-code-generator/pull/8457) [`126194017`](https://github.com/dotansimha/graphql-code-generator/commit/1261940173b8266d17fa03c1775104aff6086d3c) Thanks [@charlypoly](https://github.com/charlypoly)! - typo in config mapping ## 1.0.4 ### Patch Changes - [#8455](https://github.com/dotansimha/graphql-code-generator/pull/8455) [`d19573d88`](https://github.com/dotansimha/graphql-code-generator/commit/d19573d889513abab77a99d5f75f25612a891446) Thanks [@charlypoly](https://github.com/charlypoly)! - The client preset now allows the use of the following `config`: - `scalars` - `defaultScalarType` - `strictScalars` - `namingConvention` - `useTypeImports` - `skipTypename` - `arrayInputCoercion` ## 1.0.3 ### Patch Changes - [#8443](https://github.com/dotansimha/graphql-code-generator/pull/8443) [`e2d115146`](https://github.com/dotansimha/graphql-code-generator/commit/e2d11514695ca56674983e8b3b7549cd3b440a5d) Thanks [@charlypoly](https://github.com/charlypoly)! - fix(gql-tag-operations): issues with "no documents" scenario - Updated dependencies [[`e2d115146`](https://github.com/dotansimha/graphql-code-generator/commit/e2d11514695ca56674983e8b3b7549cd3b440a5d)]: - @graphql-codegen/gql-tag-operations@1.5.3 ## 1.0.2 ### Patch Changes - [#8402](https://github.com/dotansimha/graphql-code-generator/pull/8402) [`a76c606e3`](https://github.com/dotansimha/graphql-code-generator/commit/a76c606e3b631ef903d4066e2643bc7f95457e30) Thanks [@charlypoly](https://github.com/charlypoly)! - dependencies updates: - Updated dependency [`@graphql-codegen/gql-tag-operations@1.5.1` ↗︎](https://www.npmjs.com/package/@graphql-codegen/gql-tag-operations/v/1.5.1) (from `^1.5.0`, in `dependencies`) - [#8402](https://github.com/dotansimha/graphql-code-generator/pull/8402) [`a76c606e3`](https://github.com/dotansimha/graphql-code-generator/commit/a76c606e3b631ef903d4066e2643bc7f95457e30) Thanks [@charlypoly](https://github.com/charlypoly)! - update `@graphql-codegen/gql-tag-operations` - Updated dependencies [[`a76c606e3`](https://github.com/dotansimha/graphql-code-generator/commit/a76c606e3b631ef903d4066e2643bc7f95457e30)]: - @graphql-codegen/gql-tag-operations@1.5.2 ## 1.0.1 ### Patch Changes - [#8302](https://github.com/dotansimha/graphql-code-generator/pull/8302) [`876844e76`](https://github.com/dotansimha/graphql-code-generator/commit/876844e7644a917172f09b3c4eb54a2f4c90e4c6) Thanks [@charlypoly](https://github.com/charlypoly)! - **`@graphql-codegen/gql-tag-operations` and `@graphql-codegen/gql-tag-operations-preset`** Introduce a `gqlTagName` configuration option *** **`@graphql-codegen/client-preset`** New preset for GraphQL Code Generator v3, more information on the RFC: https://github.com/dotansimha/graphql-code-generator/issues/8296 *** **`@graphql-codegen/cli`** Update init wizard with 3.0 recommendations (`codegen.ts`, `client` preset) - Updated dependencies [[`876844e76`](https://github.com/dotansimha/graphql-code-generator/commit/876844e7644a917172f09b3c4eb54a2f4c90e4c6)]: - @graphql-codegen/gql-tag-operations@1.5.0 ================================================ FILE: packages/presets/client/package.json ================================================ { "name": "@graphql-codegen/client-preset", "version": "5.2.4", "description": "GraphQL Code Generator preset for client.", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/presets/client" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "devDependencies": { "@types/babel__helper-plugin-utils": "7.10.3", "@types/babel__template": "7.4.4", "graphql-sock": "1.0.0" }, "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", "@graphql-codegen/add": "^6.0.0", "@graphql-codegen/typed-document-node": "^6.1.7", "@graphql-codegen/typescript": "^5.0.9", "@graphql-codegen/typescript-operations": "^5.0.9", "@graphql-codegen/gql-tag-operations": "5.1.4", "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-codegen/visitor-plugin-common": "^6.2.4", "@graphql-typed-document-node/core": "3.2.0", "@graphql-tools/documents": "^1.0.0", "@graphql-tools/utils": "^11.0.0", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql-sock": "^1.0.0" }, "peerDependenciesMeta": { "graphql-sock": { "optional": true } }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/presets/client/src/add-typename-selection-document-transform.ts ================================================ import { ASTNode, OperationDefinitionNode, Kind, visit } from 'graphql'; import { Types } from '@graphql-codegen/plugin-helpers'; /** * Automatically adds `__typename` selections to every object type in your GraphQL document except the root node in subscriptions since a single root field is expected (https://spec.graphql.org/draft/#sec-Single-root-field). * This is useful for GraphQL Clients such as Apollo Client or urql that need typename information for their cache to function. */ export const addTypenameSelectionDocumentTransform: Types.DocumentTransformObject = { transform({ documents }) { return documents.map(document => ({ ...document, document: document.document ? visit(document.document, { SelectionSet(node, _, parent) { const isSubscriptionRoot = typeof (parent as ASTNode)?.kind === 'string' && (parent as ASTNode).kind === 'OperationDefinition' && (parent as OperationDefinitionNode).operation === 'subscription'; if ( !isSubscriptionRoot && !node.selections.find(selection => selection.kind === 'Field' && selection.name.value === '__typename') ) { return { ...node, selections: [ { kind: Kind.FIELD, name: { kind: Kind.NAME, value: '__typename', }, }, ...node.selections, ], }; } return undefined; }, }) : undefined, })); }, }; ================================================ FILE: packages/presets/client/src/babel.ts ================================================ import * as path from 'path'; import type { PluginObj, PluginPass } from '@babel/core'; import { declare } from '@babel/helper-plugin-utils'; import template from '@babel/template'; import type { NodePath } from '@babel/traverse'; import type { Program } from '@babel/types'; import { ClientSideBaseVisitor } from '@graphql-codegen/visitor-plugin-common'; import { buildSchema, parse } from 'graphql'; const noopSchema = buildSchema(`type Query { _: Int }`); type ClientBabelPresetOptions = { artifactDirectory?: string; gqlTagName?: string; }; export default declare((api, opts): PluginObj => { const visitor = new ClientSideBaseVisitor(noopSchema, [], {}, {}); const artifactDirectory = opts['artifactDirectory'] ?? ''; const gqlTagName = opts['gqlTagName'] || 'gql'; let program: NodePath; return { name: 'client-preset', visitor: { Program(path) { program = path; }, CallExpression(path, state) { if (path.node.callee.type !== 'Identifier' || path.node.callee.name !== gqlTagName) { return; } const [argument] = path.node.arguments; if (argument == null) { return; } if (argument.type !== 'TemplateLiteral') { return; } const [content] = argument.quasis; const ast = parse(content.value.raw); const [firstDefinition] = ast.definitions; if (firstDefinition.kind !== 'FragmentDefinition' && firstDefinition.kind !== 'OperationDefinition') { return; } if (firstDefinition.name == null) { return; } const operationOrFragmentName = firstDefinition.kind === 'OperationDefinition' ? visitor.getOperationVariableName(firstDefinition) : visitor.getFragmentVariableName(firstDefinition); const importPath = getRelativeImportPath(state, artifactDirectory); const importDeclaration = template.smart(` import { %%importName%% } from %%importPath%% `); program.unshiftContainer( 'body', importDeclaration({ importName: api.types.identifier(operationOrFragmentName), importPath: api.types.stringLiteral(importPath), }) ); path.replaceWith(api.types.identifier(operationOrFragmentName)); }, }, }; }); function getRelativeImportPath(state: PluginPass, artifactDirectory: string, fileToRequire = 'graphql'): string { if (state.file == null) { throw new Error('Babel state is missing expected file name'); } const { filename } = state.file.opts; const relative = path.relative(path.dirname(filename), path.resolve(artifactDirectory)); const relativeReference = relative.length === 0 || !relative.startsWith('.') ? './' : ''; const platformSpecificPath = relativeReference + path.join(relative, fileToRequire); // ensure windows paths are written as unix paths return platformSpecificPath.split(path.sep).join(path.posix.sep); } ================================================ FILE: packages/presets/client/src/fragment-masking-plugin.ts ================================================ import { normalizeImportExtension, type PluginFunction } from '@graphql-codegen/plugin-helpers'; const fragmentTypeHelper = ` export type FragmentType> = TDocumentType extends DocumentTypeDecoration< infer TType, any > ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never;`; const makeFragmentDataHelper = ` export function makeFragmentData< F extends DocumentTypeDecoration, FT extends ResultOf >(data: FT, _fragment: F): FragmentType { return data as FragmentType; }`; const defaultUnmaskFunctionName = 'useFragment'; const createUnmaskFunctionTypeDefinitions = (unmaskFunctionName = defaultUnmaskFunctionName) => [ `// return non-nullable if \`fragmentType\` is non-nullable export function ${unmaskFunctionName}( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType;`, `// return nullable if \`fragmentType\` is undefined export function ${unmaskFunctionName}( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined;`, `// return nullable if \`fragmentType\` is nullable export function ${unmaskFunctionName}( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null;`, `// return nullable if \`fragmentType\` is nullable or undefined export function ${unmaskFunctionName}( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined;`, `// return array of non-nullable if \`fragmentType\` is array of non-nullable export function ${unmaskFunctionName}( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array;`, `// return array of nullable if \`fragmentType\` is array of nullable export function ${unmaskFunctionName}( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined;`, `// return readonly array of non-nullable if \`fragmentType\` is array of non-nullable export function ${unmaskFunctionName}( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray;`, `// return readonly array of nullable if \`fragmentType\` is array of nullable export function ${unmaskFunctionName}( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined;`, ]; const createUnmaskFunction = (unmaskFunctionName = defaultUnmaskFunctionName) => ` ${createUnmaskFunctionTypeDefinitions(unmaskFunctionName).join('\n')} export function ${unmaskFunctionName}( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } `; const isFragmentReadyFunction = (isStringDocumentMode: boolean) => { if (isStringDocumentMode) { return `\ export function isFragmentReady( queryNode: TypedDocumentString, fragmentNode: TypedDocumentString, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = queryNode.__meta__?.deferredFields as Record; const fragName = fragmentNode.__meta__?.fragmentName as string | undefined; if (!deferredFields || !fragName) return true; const fields = deferredFields[fragName] ?? []; return fields.length > 0 && fields.every(field => data && field in data); } `; } return `\ export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } `; }; /** * Plugin for generating fragment masking helper functions. */ export const plugin: PluginFunction<{ useTypeImports?: boolean; augmentedModuleName?: string; unmaskFunctionName?: string; emitLegacyCommonJSImports?: boolean; importExtension?: '' | `.${string}`; isStringDocumentMode?: boolean; }> = ( _, __, { useTypeImports, augmentedModuleName, unmaskFunctionName, emitLegacyCommonJSImports, importExtension, isStringDocumentMode, }, _info ) => { const appendedImportExtension = normalizeImportExtension({ emitLegacyCommonJSImports, importExtension, }); const documentNodeImport = `${useTypeImports ? 'import type' : 'import'} { ResultOf, DocumentTypeDecoration${ isStringDocumentMode ? '' : ', TypedDocumentNode' } } from '@graphql-typed-document-node/core';\n`; const deferFragmentHelperImports = `${useTypeImports ? 'import type' : 'import'} { Incremental${ isStringDocumentMode ? ', TypedDocumentString' : '' } } from './graphql${appendedImportExtension}';\n`; const fragmentDefinitionNodeImport = isStringDocumentMode ? '' : `${useTypeImports ? 'import type' : 'import'} { FragmentDefinitionNode } from 'graphql';\n`; if (augmentedModuleName == null) { return [ documentNodeImport, fragmentDefinitionNodeImport, deferFragmentHelperImports, `\n`, fragmentTypeHelper, `\n`, createUnmaskFunction(unmaskFunctionName), `\n`, makeFragmentDataHelper, `\n`, isFragmentReadyFunction(isStringDocumentMode), ].join(``); } return [ documentNodeImport, `declare module "${augmentedModuleName}" {`, [ ...fragmentTypeHelper.split(`\n`), `\n`, ...createUnmaskFunctionTypeDefinitions(unmaskFunctionName).join('\n').split('\n'), `\n`, makeFragmentDataHelper, ] .map(line => (line === `\n` || line === '' ? line : ` ${line}`)) .join(`\n`), `}`, ].join(`\n`); }; ================================================ FILE: packages/presets/client/src/index.ts ================================================ import * as addPlugin from '@graphql-codegen/add'; import * as gqlTagPlugin from '@graphql-codegen/gql-tag-operations'; import { normalizeImportExtension, type PluginFunction, type Types } from '@graphql-codegen/plugin-helpers'; import * as typedDocumentNodePlugin from '@graphql-codegen/typed-document-node'; import * as typescriptPlugin from '@graphql-codegen/typescript'; import * as typescriptOperationPlugin from '@graphql-codegen/typescript-operations'; import { ClientSideBaseVisitor, DocumentMode } from '@graphql-codegen/visitor-plugin-common'; import { parse, printSchema, type DocumentNode, type GraphQLSchema } from 'graphql'; import * as fragmentMaskingPlugin from './fragment-masking-plugin.js'; import { generateDocumentHash, normalizeAndPrintDocumentNode } from './persisted-documents.js'; import { processSources } from './process-sources.js'; export { default as babelOptimizerPlugin } from './babel.js'; export type FragmentMaskingConfig = { /** @description Name of the function that should be used for unmasking a masked fragment property. * @default `'useFragment'` */ unmaskFunctionName?: string; }; export type ClientPresetConfig = { /** * @description Fragment masking hides data from components and only allows accessing the data by using a unmasking function. * @exampleMarkdown * ```tsx * const config = { * schema: 'https://graphql.org/graphql/', * documents: ['src/**\/*.tsx', '!src\/gql/**\/*'], * generates: { * './src/gql/': { * preset: 'client', * presetConfig: { * fragmentMasking: false, * } * }, * }, * }; * export default config; * ``` */ fragmentMasking?: FragmentMaskingConfig | boolean; /** * @description Specify the name of the "graphql tag" function to use * @default "graphql" * * E.g. `graphql` or `gql`. * * @exampleMarkdown * ```tsx * const config = { * schema: 'https://graphql.org/graphql/', * documents: ['src/**\/*.tsx', '!src\/gql/**\/*'], * generates: { * './src/gql/': { * preset: 'client', * presetConfig: { * gqlTagName: 'gql', * } * }, * }, * }; * export default config; * ``` */ gqlTagName?: string; /** * Generate metadata for a executable document node and embed it in the emitted code. */ onExecutableDocumentNode?: (documentNode: DocumentNode) => void | Record; /** Persisted operations configuration. */ persistedDocuments?: | boolean | { /** * @description Behavior for the output file. * @default 'embedHashInDocument' * "embedHashInDocument" will add a property within the `DocumentNode` with the hash of the operation. * "replaceDocumentWithHash" will fully drop the document definition. */ mode?: 'embedHashInDocument' | 'replaceDocumentWithHash'; /** * @description Name of the property that will be added to the `DocumentNode` with the hash of the operation. */ hashPropertyName?: string; /** * @description Algorithm or function used to generate the hash, could be useful if your server expects something specific (e.g., Apollo Server expects `sha256`). * * A custom hash function can be provided to generate the hash if the preset algorithms don't fit your use case. The function receives the operation and should return the hash string. * * The algorithm parameter is typed with known algorithms and as a string rather than a union because it solely depends on Crypto's algorithms supported * by the version of OpenSSL on the platform. * * @default `sha1` */ hashAlgorithm?: 'sha1' | 'sha256' | (string & {}) | ((operation: string) => string); }; }; const isOutputFolderLike = (baseOutputDir: string) => baseOutputDir.endsWith('/'); export const preset: Types.OutputPreset = { prepareDocuments: (outputFilePath, outputSpecificDocuments) => [...outputSpecificDocuments, `!${outputFilePath}`], buildGeneratesSection: async options => { if (!isOutputFolderLike(options.baseOutputDir)) { throw new Error( '[client-preset] target output should be a directory, ex: "src/gql/". Make sure you add "/" at the end of the directory path' ); } if (options.plugins.length > 0 && Object.keys(options.plugins).some(p => p.startsWith('typescript'))) { throw new Error( '[client-preset] providing typescript-based `plugins` with `preset: "client" leads to duplicated generated types' ); } const isPersistedOperations = !!options.presetConfig?.persistedDocuments; if (options.config.nullability?.errorHandlingClient) { options.schemaAst = await semanticToStrict(options.schemaAst!); options.schema = parse(printSchema(options.schemaAst)); } const reexports: Array = []; // the `client` preset is restricting the config options inherited from `typescript`, `typescript-operations` and others. const forwardedConfig = { scalars: options.config.scalars, defaultScalarType: options.config.defaultScalarType, strictScalars: options.config.strictScalars, namingConvention: options.config.namingConvention, useTypeImports: options.config.useTypeImports, skipTypename: options.config.skipTypename, arrayInputCoercion: options.config.arrayInputCoercion, enumsAsTypes: options.config.enumsAsTypes, enumsAsConst: options.config.enumsAsConst, enumValues: options.config.enumValues, futureProofEnums: options.config.futureProofEnums, nonOptionalTypename: options.config.nonOptionalTypename, avoidOptionals: options.config.avoidOptionals, documentMode: options.config.documentMode, skipTypeNameForRoot: options.config.skipTypeNameForRoot, onlyOperationTypes: options.config.onlyOperationTypes, onlyEnums: options.config.onlyEnums, customDirectives: options.config.customDirectives, immutableTypes: options.config.immutableTypes, }; const visitor = new ClientSideBaseVisitor(options.schemaAst, [], options.config, options.config); let fragmentMaskingConfig: FragmentMaskingConfig | null = null; if (typeof options?.presetConfig?.fragmentMasking === 'object') { fragmentMaskingConfig = options.presetConfig.fragmentMasking; } else if (options?.presetConfig?.fragmentMasking !== false) { // `true` by default fragmentMaskingConfig = {}; } const onExecutableDocumentNodeHook = options.presetConfig.onExecutableDocumentNode ?? null; const isMaskingFragments = fragmentMaskingConfig != null; const persistedDocuments = options.presetConfig.persistedDocuments ? { hashPropertyName: (typeof options.presetConfig.persistedDocuments === 'object' && options.presetConfig.persistedDocuments.hashPropertyName) || 'hash', omitDefinitions: (typeof options.presetConfig.persistedDocuments === 'object' && options.presetConfig.persistedDocuments.mode) === 'replaceDocumentWithHash' || false, hashAlgorithm: (typeof options.presetConfig.persistedDocuments === 'object' && options.presetConfig.persistedDocuments.hashAlgorithm) || 'sha1', } : null; const sourcesWithOperations = processSources(options.documents, node => { if (node.kind === 'FragmentDefinition') { return visitor.getFragmentVariableName(node); } return visitor.getOperationVariableName(node); }); const sources = sourcesWithOperations.map(({ source }) => source); const tdnFinished = createDeferred(); const persistedDocumentsMap = new Map(); const pluginMap = { ...options.pluginMap, [`add`]: addPlugin, [`typescript`]: typescriptPlugin, [`typescript-operations`]: typescriptOperationPlugin, [`typed-document-node`]: { ...typedDocumentNodePlugin, plugin: async (...args: Parameters) => { try { return await typedDocumentNodePlugin.plugin(...args); } finally { tdnFinished.resolve(); } }, }, [`gen-dts`]: gqlTagPlugin, }; function onExecutableDocumentNode(documentNode: DocumentNode) { const meta = onExecutableDocumentNodeHook?.(documentNode); if (persistedDocuments) { const documentString = normalizeAndPrintDocumentNode(documentNode); const hash = generateDocumentHash(documentString, persistedDocuments.hashAlgorithm); persistedDocumentsMap.set(hash, documentString); return { ...meta, [persistedDocuments.hashPropertyName]: hash }; } if (meta) { return meta; } return undefined; } const plugins: Array = [ { [`add`]: { content: `/* eslint-disable */` } }, { [`typescript`]: { inputMaybeValue: 'T | null | undefined', }, }, { [`typescript-operations`]: {} }, { [`typed-document-node`]: { unstable_onExecutableDocumentNode: onExecutableDocumentNode, unstable_omitDefinitions: persistedDocuments?.omitDefinitions ?? false, }, }, ...options.plugins, ]; const genDtsPlugins: Array = [ { [`add`]: { content: `/* eslint-disable */` } }, { [`gen-dts`]: { sourcesWithOperations } }, ]; const gqlArtifactFileExtension = '.ts'; reexports.push('gql'); const config = { ...options.config, inlineFragmentTypes: isMaskingFragments ? 'mask' : options.config['inlineFragmentTypes'], }; let fragmentMaskingFileGenerateConfig: Types.GenerateOptions | null = null; const importExtension = normalizeImportExtension({ emitLegacyCommonJSImports: options.config.emitLegacyCommonJSImports, importExtension: options.config.importExtension, }); if (isMaskingFragments === true) { const fragmentMaskingArtifactFileExtension = '.ts'; reexports.push('fragment-masking'); fragmentMaskingFileGenerateConfig = { filename: `${options.baseOutputDir}fragment-masking${fragmentMaskingArtifactFileExtension}`, pluginMap: { [`add`]: addPlugin, [`fragment-masking`]: fragmentMaskingPlugin, }, plugins: [ { [`add`]: { content: `/* eslint-disable */` } }, { [`fragment-masking`]: {}, }, ], schema: options.schema, config: { useTypeImports: options.config.useTypeImports, unmaskFunctionName: fragmentMaskingConfig.unmaskFunctionName, emitLegacyCommonJSImports: options.config.emitLegacyCommonJSImports, importExtension, isStringDocumentMode: options.config.documentMode === DocumentMode.string, }, documents: [], documentTransforms: options.documentTransforms, }; } let indexFileGenerateConfig: Types.GenerateOptions | null = null; if (reexports.length) { indexFileGenerateConfig = { filename: `${options.baseOutputDir}index.ts`, pluginMap: { [`add`]: addPlugin, }, plugins: [ { [`add`]: { content: reexports .sort() .map(moduleName => `export * from "./${moduleName}${importExtension}";`) .join('\n'), }, }, ], schema: options.schema, config: {}, documents: [], documentTransforms: options.documentTransforms, }; } return [ { filename: `${options.baseOutputDir}graphql.ts`, plugins, pluginMap, schema: options.schema, config: { inlineFragmentTypes: isMaskingFragments ? 'mask' : options.config['inlineFragmentTypes'], ...forwardedConfig, }, documents: sources, documentTransforms: options.documentTransforms, }, { filename: `${options.baseOutputDir}gql${gqlArtifactFileExtension}`, plugins: genDtsPlugins, pluginMap, schema: options.schema, config: { ...config, gqlTagName: options.presetConfig.gqlTagName || 'graphql', }, documents: sources, documentTransforms: options.documentTransforms, }, ...(isPersistedOperations ? [ { filename: `${options.baseOutputDir}persisted-documents.json`, plugins: [ { [`persisted-operations`]: {}, }, ], pluginMap: { [`persisted-operations`]: { plugin: async () => { await tdnFinished.promise; return { content: JSON.stringify(Object.fromEntries(persistedDocumentsMap.entries()), null, 2), }; }, }, }, schema: options.schema, config: {}, documents: sources, documentTransforms: options.documentTransforms, }, ] : []), ...(fragmentMaskingFileGenerateConfig ? [fragmentMaskingFileGenerateConfig] : []), ...(indexFileGenerateConfig ? [indexFileGenerateConfig] : []), ]; }, }; type Deferred = { resolve: (value: T) => void; reject: (value: unknown) => void; promise: Promise; }; function createDeferred(): Deferred { const d = {} as Deferred; d.promise = new Promise((resolve, reject) => { d.resolve = resolve; d.reject = reject; }); return d; } const semanticToStrict = async (schema: GraphQLSchema): Promise => { try { const sock = await import('graphql-sock'); return sock.semanticToStrict(schema); } catch { throw new Error( "To use the `nullability.errorHandlingClient` option, you must install the 'graphql-sock' package." ); } }; export { addTypenameSelectionDocumentTransform } from './add-typename-selection-document-transform.js'; ================================================ FILE: packages/presets/client/src/persisted-documents.spec.ts ================================================ import { parse } from 'graphql'; import { normalizeAndPrintDocumentNode } from './persisted-documents'; describe('normalizeAndPrintDocumentNode', () => { it('should remove client specific directives/fields from the document', () => { const document = parse(/* GraphQL */ ` query myQuery { regularField clientSideOnlyField @client } `); const result = normalizeAndPrintDocumentNode(document); expect(result).toMatchInlineSnapshot(`"query myQuery { regularField }"`); }); it('should remove @client when it is specified on an fragment spread', () => { const document = parse(/* GraphQL */ ` query myQuery { regularField clientSideOnlyField @client ...myFrag @client ...myOtherFrag } fragment myFrag on Query { someField } `); const result = normalizeAndPrintDocumentNode(document); expect(result).toMatchInlineSnapshot( `"fragment myFrag on Query { someField } query myQuery { regularField ...myOtherFrag }"` ); }); it('should remove @client when it is specified on an inline fragment', () => { const document = parse(/* GraphQL */ ` query myQuery { regularField clientSideOnlyField @client ...myFrag @client ... on Query @client { someField } ... on Query { regularField } } fragment myFrag on Query { someField } `); const result = normalizeAndPrintDocumentNode(document); expect(result).toMatchInlineSnapshot( `"fragment myFrag on Query { someField } query myQuery { regularField ... on Query { regularField } }"` ); }); }); ================================================ FILE: packages/presets/client/src/persisted-documents.ts ================================================ import { printExecutableGraphQLDocument } from '@graphql-tools/documents'; import * as crypto from 'crypto'; import { Kind, visit, type DocumentNode } from 'graphql'; const CLIENT_DIRECTIVE_NAME = 'client'; const CONNECTION_DIRECTIVE_NAME = 'connection'; /** * This function generates a hash from a document node. */ export function generateDocumentHash( operation: string, algorithm: 'sha1' | 'sha256' | (string & {}) | ((operation: string) => string) ): string { if (typeof algorithm === 'function') { return algorithm(operation); } const shasum = crypto.createHash(algorithm); shasum.update(operation); return shasum.digest('hex'); } /** * Normalizes and prints a document node. */ export function normalizeAndPrintDocumentNode(documentNode: DocumentNode): string { /** * This removes all client specific directives/fields from the document * that the server does not know about. * In a future version this should be more configurable. * If you look at this and want to customize it. * Send a PR :) */ const sanitizedDocument = visit(documentNode, { [Kind.FIELD](field) { if (field.directives?.some(directive => directive.name.value === CLIENT_DIRECTIVE_NAME)) { return null; } }, [Kind.FRAGMENT_SPREAD](spread) { if (spread.directives?.some(directive => directive.name.value === CLIENT_DIRECTIVE_NAME)) { return null; } }, [Kind.INLINE_FRAGMENT](fragment) { if (fragment.directives?.some(directive => directive.name.value === CLIENT_DIRECTIVE_NAME)) { return null; } }, [Kind.DIRECTIVE](directive) { if (directive.name.value === CONNECTION_DIRECTIVE_NAME) { return null; } }, }); return printExecutableGraphQLDocument(sanitizedDocument); } ================================================ FILE: packages/presets/client/src/process-sources.ts ================================================ import { OperationOrFragment, SourceWithOperations } from '@graphql-codegen/gql-tag-operations'; import { Source } from '@graphql-tools/utils'; import { FragmentDefinitionNode, OperationDefinitionNode } from 'graphql'; export type BuildNameFunction = (type: OperationDefinitionNode | FragmentDefinitionNode) => string; export function processSources(sources: Array, buildName: BuildNameFunction) { const sourcesWithOperations: Array = []; for (const originalSource of sources) { const source = fixLinebreaks(originalSource); const { document } = source; const operations: Array = []; for (const definition of document?.definitions ?? []) { if (definition?.kind !== `OperationDefinition` && definition?.kind !== 'FragmentDefinition') continue; if (definition.name?.kind !== `Name`) { if (definition?.kind === `OperationDefinition`) { // eslint-disable-next-line no-console console.warn(`[client-preset] the following anonymous operation is skipped: ${source.rawSDL}`); } continue; } operations.push({ initialName: buildName(definition), definition, }); } if (operations.length === 0) continue; sourcesWithOperations.push({ source, operations, }); } return sourcesWithOperations; } /** * https://github.com/dotansimha/graphql-code-generator/issues/7362 * * Source file is read by @graphql/tools using fs.promises.readFile, * which means that the linebreaks are read as-is and the result will be different * depending on the OS: it will contain LF (\n) on Linux/MacOS and CRLF (\r\n) on Windows. * * In most scenarios that would be OK. However, front-end preset is using the resulting string * as a TypeScript type. Which means that the string will be compared against a template literal, * for example: * *
    
     * `
     * query a {
     *    a
     *  }
     * ` === '\n query a {\n    a\n  }\n '
     * 
    * * According to clause 12.8.6.2 of ECMAScript Language Specification * (https://tc39.es/ecma262/#sec-static-semantics-trv), * when comparing strings, JavaScript doesn't care which linebreaks does the source file contain, * any linebreak (CR, LF or CRLF) is LF from JavaScript standpoint * (otherwise the result of the above comparison would be OS-dependent, which doesn't make sense). * * Therefore gql-tag-operation would break on Windows as it would generate * * '\r\n query a {\r\n a\r\n }\r\n ' * * which is NOT equal to * *
    
     * `
     * query a {
     *    a
     *  }
     * `
     * 
    * * Therefore we need to replace \r\n with \n in the string. * * @param source */ function fixLinebreaks(source: Source) { const fixedSource = { ...source }; fixedSource.rawSDL = source.rawSDL.replace(/\r\n/g, '\n'); return fixedSource; } ================================================ FILE: packages/presets/client/tests/babel.spec.ts ================================================ import * as path from 'path'; import { transformFileSync } from '@babel/core'; import babelPlugin from '../src/babel.js'; describe('client-preset > babelPlugin', () => { test('can imports files in the same directory', () => { const result = transformFileSync(path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), { plugins: [[babelPlugin, { artifactDirectory: path.join(__dirname, 'fixtures') }]], babelrc: false, configFile: false, }).code; expect(result).toMatchInlineSnapshot(` "import { CFragmentDoc } from "./graphql"; import { BDocument } from "./graphql"; import { ADocument } from "./graphql"; /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import gql from 'gql-tag'; //@ts-ignore const A = ADocument; //@ts-ignore const B = BDocument; //@ts-ignore const C = CFragmentDoc;" `); }); test('can import files in another directory', () => { const result = transformFileSync(path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), { plugins: [[babelPlugin, { artifactDirectory: __dirname }]], babelrc: false, configFile: false, }).code; expect(result).toMatchInlineSnapshot(` "import { CFragmentDoc } from "../graphql"; import { BDocument } from "../graphql"; import { ADocument } from "../graphql"; /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import gql from 'gql-tag'; //@ts-ignore const A = ADocument; //@ts-ignore const B = BDocument; //@ts-ignore const C = CFragmentDoc;" `); }); }); ================================================ FILE: packages/presets/client/tests/client-preset.nullability.spec.ts ================================================ import '@graphql-codegen/testing'; import { executeCodegen } from '@graphql-codegen/cli'; import * as prettier from 'prettier'; import { preset } from '../src/index.js'; const schema = /* GraphQL */ ` directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION type Query { me: User } type User { field: String @semanticNonNull fieldLevel0: String @semanticNonNull(levels: [0]) fieldLevel1: String @semanticNonNull(levels: [1]) fieldBothLevels: String @semanticNonNull(levels: [0, 1]) list: [String] @semanticNonNull listLevel0: [String] @semanticNonNull(levels: [0]) listLevel1: [String] @semanticNonNull(levels: [1]) listBothLevels: [String] @semanticNonNull(levels: [0, 1]) nonNullableList: [String]! @semanticNonNull nonNullableListLevel0: [String]! @semanticNonNull(levels: [0]) nonNullableListLevel1: [String]! @semanticNonNull(levels: [1]) nonNullableListBothLevels: [String]! @semanticNonNull(levels: [0, 1]) listWithNonNullableItem: [String!] @semanticNonNull listWithNonNullableItemLevel0: [String!] @semanticNonNull(levels: [0]) listWithNonNullableItemLevel1: [String!] @semanticNonNull(levels: [1]) listWithNonNullableItemBothLevels: [String!] @semanticNonNull(levels: [0, 1]) nonNullableListWithNonNullableItem: [String!]! @semanticNonNull nonNullableListWithNonNullableItemLevel0: [String!]! @semanticNonNull(levels: [0]) nonNullableListWithNonNullableItemLevel1: [String!]! @semanticNonNull(levels: [1]) nonNullableListWithNonNullableItemBothLevels: [String!]! @semanticNonNull(levels: [0, 1]) } `; const document = /* GraphQL */ ` query Test { me { field fieldLevel0 fieldLevel1 fieldBothLevels list listLevel0 listLevel1 listBothLevels nonNullableList nonNullableListLevel0 nonNullableListLevel1 nonNullableListBothLevels listWithNonNullableItem listWithNonNullableItemLevel0 listWithNonNullableItemLevel1 listWithNonNullableItemBothLevels nonNullableListWithNonNullableItem nonNullableListWithNonNullableItemLevel0 nonNullableListWithNonNullableItemLevel1 nonNullableListWithNonNullableItemBothLevels } } `; describe('client-preset - nullability', () => { it('converts semanticNonNull to non-null when nullability.errorHandlingClient=true', async () => { const { result } = await executeCodegen({ schema, documents: [document], generates: { 'out1/': { preset, config: { nullability: { errorHandlingClient: true, }, }, }, }, }); const graphqlFile = result.find(f => f.filename === 'out1/graphql.ts'); const formattedContent = prettier.format(graphqlFile.content, { parser: 'typescript' }); expect(formattedContent).toBeSimilarStringTo(` export type TestQuery = { __typename?: "Query"; me?: { __typename?: "User"; field: string; fieldLevel0: string; fieldLevel1?: string | null; fieldBothLevels: string; list: Array; listLevel0: Array; listLevel1?: Array | null; listBothLevels: Array; nonNullableList: Array; nonNullableListLevel0: Array; nonNullableListLevel1: Array; nonNullableListBothLevels: Array; listWithNonNullableItem: Array; listWithNonNullableItemLevel0: Array; listWithNonNullableItemLevel1?: Array | null; listWithNonNullableItemBothLevels: Array; nonNullableListWithNonNullableItem: Array; nonNullableListWithNonNullableItemLevel0: Array; nonNullableListWithNonNullableItemLevel1: Array; nonNullableListWithNonNullableItemBothLevels: Array; } | null; }; `); }); it('leave semanticNonNull as null when nullability.errorHandlingClient=false', async () => { const { result } = await executeCodegen({ schema, documents: [document], generates: { 'out1/': { preset, config: { nullability: { errorHandlingClient: false, }, }, }, }, }); const graphqlFile = result.find(f => f.filename === 'out1/graphql.ts'); const formattedContent = prettier.format(graphqlFile.content, { parser: 'typescript' }); expect(formattedContent).toBeSimilarStringTo(` export type TestQuery = { __typename?: "Query"; me?: { __typename?: "User"; field?: string | null; fieldLevel0?: string | null; fieldLevel1?: string | null; fieldBothLevels?: string | null; list?: Array | null; listLevel0?: Array | null; listLevel1?: Array | null; listBothLevels?: Array | null; nonNullableList: Array; nonNullableListLevel0: Array; nonNullableListLevel1: Array; nonNullableListBothLevels: Array; listWithNonNullableItem?: Array | null; listWithNonNullableItemLevel0?: Array | null; listWithNonNullableItemLevel1?: Array | null; listWithNonNullableItemBothLevels?: Array | null; nonNullableListWithNonNullableItem: Array; nonNullableListWithNonNullableItemLevel0: Array; nonNullableListWithNonNullableItemLevel1: Array; nonNullableListWithNonNullableItemBothLevels: Array; } | null; }; `); }); }); ================================================ FILE: packages/presets/client/tests/client-preset.spec.ts ================================================ import { executeCodegen } from '@graphql-codegen/cli'; import { mergeOutputs } from '@graphql-codegen/plugin-helpers'; import { validateTs } from '@graphql-codegen/testing'; import * as crypto from 'crypto'; import * as fs from 'fs'; import { print } from 'graphql'; import path from 'path'; import { addTypenameSelectionDocumentTransform, preset } from '../src/index.js'; describe('client-preset', () => { it('can generate simple examples uppercase names', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, }); expect(result).toHaveLength(4); // index.ts (re-exports) const indexFile = result.find(file => file.filename === 'out1/index.ts'); expect(indexFile.content).toEqual(`export * from "./fragment-masking"; export * from "./gql";`); // gql.ts const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { "\\n query A {\\n a\\n }\\n": typeof types.ADocument, "\\n query B {\\n b\\n }\\n": typeof types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": typeof types.CFragmentDoc, }; const documents: Documents = { "\\n query A {\\n a\\n }\\n": types.ADocument, "\\n query B {\\n b\\n }\\n": types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": types.CFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * \`\`\`ts * const query = graphql(\`query GetUser($id: ID!) { user(id: $id) { name } }\`); * \`\`\` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query A {\\n a\\n }\\n"): (typeof documents)["\\n query A {\\n a\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query B {\\n b\\n }\\n"): (typeof documents)["\\n query B {\\n b\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n fragment C on Query {\\n c\\n }\\n"): (typeof documents)["\\n fragment C on Query {\\n c\\n }\\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;" `); // graphql.ts const graphqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(graphqlFile).toBeDefined(); }); it('can generate simple examples lowercase names', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-lowercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, }); expect(result).toHaveLength(4); // index.ts (re-exports) const indexFile = result.find(file => file.filename === 'out1/index.ts'); expect(indexFile.content).toEqual(`export * from "./fragment-masking"; export * from "./gql";`); // gql.ts const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { "\\n query a {\\n a\\n }\\n": typeof types.ADocument, "\\n query b {\\n b\\n }\\n": typeof types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": typeof types.CFragmentDoc, }; const documents: Documents = { "\\n query a {\\n a\\n }\\n": types.ADocument, "\\n query b {\\n b\\n }\\n": types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": types.CFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * \`\`\`ts * const query = graphql(\`query GetUser($id: ID!) { user(id: $id) { name } }\`); * \`\`\` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query a {\\n a\\n }\\n"): (typeof documents)["\\n query a {\\n a\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query b {\\n b\\n }\\n"): (typeof documents)["\\n query b {\\n b\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n fragment C on Query {\\n c\\n }\\n"): (typeof documents)["\\n fragment C on Query {\\n c\\n }\\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;" `); // graphql.ts const graphqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(graphqlFile).toBeDefined(); }); it('generates \\n regardless of whether the source contains LF or CRLF', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/crlf-operation.ts'), generates: { 'out1/': { preset, }, }, }); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { "\\n query a {\\n a\\n }\\n": typeof types.ADocument, "\\n query b {\\n b\\n }\\n": typeof types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": typeof types.CFragmentDoc, }; const documents: Documents = { "\\n query a {\\n a\\n }\\n": types.ADocument, "\\n query b {\\n b\\n }\\n": types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": types.CFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * \`\`\`ts * const query = graphql(\`query GetUser($id: ID!) { user(id: $id) { name } }\`); * \`\`\` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query a {\\n a\\n }\\n"): (typeof documents)["\\n query a {\\n a\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query b {\\n b\\n }\\n"): (typeof documents)["\\n query b {\\n b\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n fragment C on Query {\\n c\\n }\\n"): (typeof documents)["\\n fragment C on Query {\\n c\\n }\\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;" `); }); it("follows 'useTypeImports': true", async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, config: { useTypeImports: true, }, }); expect(result.length).toBe(4); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql'; import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { "\\n query A {\\n a\\n }\\n": typeof types.ADocument, "\\n query B {\\n b\\n }\\n": typeof types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": typeof types.CFragmentDoc, }; const documents: Documents = { "\\n query A {\\n a\\n }\\n": types.ADocument, "\\n query B {\\n b\\n }\\n": types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": types.CFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * \`\`\`ts * const query = graphql(\`query GetUser($id: ID!) { user(id: $id) { name } }\`); * \`\`\` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query A {\\n a\\n }\\n"): (typeof documents)["\\n query A {\\n a\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query B {\\n b\\n }\\n"): (typeof documents)["\\n query B {\\n b\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n fragment C on Query {\\n c\\n }\\n"): (typeof documents)["\\n fragment C on Query {\\n c\\n }\\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename?: 'Query', a?: string | null }; export type BQueryVariables = Exact<{ [key: string]: never; }>; export type BQuery = { __typename?: 'Query', b?: string | null }; export type CFragment = { __typename?: 'Query', c?: string | null } & { ' $fragmentName'?: 'CFragment' }; export const CFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"C"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Query"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"c"}}]}}]} as unknown as DocumentNode; export const ADocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"A"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode; export const BDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"B"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode;" `); expect(graphqlFile.content).toContain( "import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'" ); expect(gqlFile.content).toContain( "import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'" ); }); it("follows 'nonOptionalTypename': true", async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, config: { nonOptionalTypename: true, }, }); expect(result.length).toBe(4); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { "\\n query A {\\n a\\n }\\n": typeof types.ADocument, "\\n query B {\\n b\\n }\\n": typeof types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": typeof types.CFragmentDoc, }; const documents: Documents = { "\\n query A {\\n a\\n }\\n": types.ADocument, "\\n query B {\\n b\\n }\\n": types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": types.CFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * \`\`\`ts * const query = graphql(\`query GetUser($id: ID!) { user(id: $id) { name } }\`); * \`\`\` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query A {\\n a\\n }\\n"): (typeof documents)["\\n query A {\\n a\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query B {\\n b\\n }\\n"): (typeof documents)["\\n query B {\\n b\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n fragment C on Query {\\n c\\n }\\n"): (typeof documents)["\\n fragment C on Query {\\n c\\n }\\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename: 'Query', a?: string | null }; export type BQueryVariables = Exact<{ [key: string]: never; }>; export type BQuery = { __typename: 'Query', b?: string | null }; export type CFragment = { __typename: 'Query', c?: string | null } & { ' $fragmentName'?: 'CFragment' }; export const CFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"C"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Query"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"c"}}]}}]} as unknown as DocumentNode; export const ADocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"A"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode; export const BDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"B"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode;" `); expect(graphqlFile.content).toContain("__typename: 'Query';"); }); it('supports Apollo fragment masking', async () => { const { result } = await executeCodegen({ schema: /* GraphQL */ ` type Query { me: User } type User { id: ID! name: String! age: Int! } `, documents: /* GraphQL */ ` query Me { unmasked: me { id ...User_Me @unmask } masked: me { id ...User_Me } } fragment User_Me on User { name age } `, generates: { 'out1/': { preset, presetConfig: { fragmentMasking: false }, config: { inlineFragmentTypes: 'mask', customDirectives: { apolloUnmask: true }, }, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; me?: Maybe; }; export type User = { __typename?: 'User'; age: Scalars['Int']['output']; id: Scalars['ID']['output']; name: Scalars['String']['output']; }; export type MeQueryVariables = Exact<{ [key: string]: never; }>; export type MeQuery = { __typename?: 'Query', unmasked?: { __typename?: 'User', id: string, name: string, age: number } | null, masked?: ( { __typename?: 'User', id: string } & { ' $fragmentRefs'?: { 'User_MeFragment': User_MeFragment } } ) | null }; export type User_MeFragment = { __typename?: 'User', name: string, age: number } & { ' $fragmentName'?: 'User_MeFragment' }; export const User_MeFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"User_Me"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"age"}}]}}]} as unknown as DocumentNode; export const MeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"unmasked"},"name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"User_Me"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"unmask"}}]}]}},{"kind":"Field","alias":{"kind":"Name","value":"masked"},"name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"User_Me"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"User_Me"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"age"}}]}}]} as unknown as DocumentNode;" `); }); it('prevent duplicate operations', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String } `, ], documents: path.join(__dirname, 'fixtures/duplicate-operation.ts'), generates: { 'out1/': { preset, }, }, config: { useTypeImports: true, }, }); expect(result.length).toBe(4); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql'; import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { "\\n query a {\\n a\\n }\\n": typeof types.ADocument, }; const documents: Documents = { "\\n query a {\\n a\\n }\\n": types.ADocument, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * \`\`\`ts * const query = graphql(\`query GetUser($id: ID!) { user(id: $id) { name } }\`); * \`\`\` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query a {\\n a\\n }\\n"): (typeof documents)["\\n query a {\\n a\\n }\\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename?: 'Query', a?: string | null }; export const ADocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"a"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode;" `); expect(gqlFile.content.match(/query a {/g).length).toBe(4); }); describe('fragment masking', () => { it('fragmentMasking: false', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { fragmentMasking: false, }, }, }, }); expect(result).toHaveLength(3); const fileNames = result.map(res => res.filename); expect(fileNames).toContain('out1/index.ts'); expect(fileNames).toContain('out1/gql.ts'); expect(fileNames).toContain('out1/graphql.ts'); const indexFile = result.find(file => file.filename === 'out1/index.ts'); expect(indexFile.content).toMatchInlineSnapshot(`"export * from "./gql";"`); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { "\\n query A {\\n a\\n }\\n": typeof types.ADocument, "\\n query B {\\n b\\n }\\n": typeof types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": typeof types.CFragmentDoc, }; const documents: Documents = { "\\n query A {\\n a\\n }\\n": types.ADocument, "\\n query B {\\n b\\n }\\n": types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": types.CFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * \`\`\`ts * const query = graphql(\`query GetUser($id: ID!) { user(id: $id) { name } }\`); * \`\`\` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query A {\\n a\\n }\\n"): (typeof documents)["\\n query A {\\n a\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query B {\\n b\\n }\\n"): (typeof documents)["\\n query B {\\n b\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n fragment C on Query {\\n c\\n }\\n"): (typeof documents)["\\n fragment C on Query {\\n c\\n }\\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;" `); }); it('fragmentMasking: {}', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { fragmentMasking: {}, }, }, }, }); expect(result).toHaveLength(4); }); it('fragmentMasking.unmaskFunctionName', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { fragmentMasking: { unmaskFunctionName: 'iLikeTurtles', }, }, }, }, }); expect(result).toHaveLength(4); const gqlFile = result.find(file => file.filename === 'out1/fragment-masking.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { FragmentDefinitionNode } from 'graphql'; import { Incremental } from './graphql'; export type FragmentType> = TDocumentType extends DocumentTypeDecoration< infer TType, any > ? [TType] extends [{ ' $fragmentName'?: infer TKey }] ? TKey extends string ? { ' $fragmentRefs'?: { [key in TKey]: TType } } : never : never : never; // return non-nullable if \`fragmentType\` is non-nullable export function iLikeTurtles( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if \`fragmentType\` is undefined export function iLikeTurtles( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | undefined ): TType | undefined; // return nullable if \`fragmentType\` is nullable export function iLikeTurtles( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null ): TType | null; // return nullable if \`fragmentType\` is nullable or undefined export function iLikeTurtles( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if \`fragmentType\` is array of non-nullable export function iLikeTurtles( _documentNode: DocumentTypeDecoration, fragmentType: Array>> ): Array; // return array of nullable if \`fragmentType\` is array of nullable export function iLikeTurtles( _documentNode: DocumentTypeDecoration, fragmentType: Array>> | null | undefined ): Array | null | undefined; // return readonly array of non-nullable if \`fragmentType\` is array of non-nullable export function iLikeTurtles( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return readonly array of nullable if \`fragmentType\` is array of nullable export function iLikeTurtles( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function iLikeTurtles( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | Array>> | ReadonlyArray>> | null | undefined ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData< F extends DocumentTypeDecoration, FT extends ResultOf >(data: FT, _fragment: F): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, data: FragmentType, any>> | null | undefined ): data is FragmentType { const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ ?.deferredFields; if (!deferredFields) return true; const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; return fields.length > 0 && fields.every(field => data && field in data); } " `); }); it('can accept null in useFragment', async () => { const docPath = path.join(__dirname, 'fixtures/with-fragment.ts'); const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { foo: Foo foos: [Foo] } type Foo { value: String } `, ], documents: docPath, generates: { 'out1/': { preset, presetConfig: { fragmentMasking: true, }, }, }, }); const content = mergeOutputs([ ...result, fs.readFileSync(docPath, 'utf8'), ` function App(props: { data: FooQuery }) { const fragment: FooFragment | null | undefined = useFragment(Fragment, props.data.foo); return fragment == null ? "no data" : fragment.value; } `, ]); validateTs(content, undefined, false, true, [`Duplicate identifier 'DocumentNode'.`], true); }); it('can accept list in useFragment', async () => { const docPath = path.join(__dirname, 'fixtures/with-fragment.ts'); const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { foo: Foo foos: [Foo!] } type Foo { value: String } `, ], documents: docPath, generates: { 'out1/': { preset, presetConfig: { fragmentMasking: true, }, }, }, }); const content = mergeOutputs([ ...result, fs.readFileSync(docPath, 'utf8'), ` function App(props: { foos: Array> }) { const fragments: Array = useFragment(Fragment, props.foos); return fragments.map(f => f.value); } `, ]); validateTs(content, undefined, false, true, [`Duplicate identifier 'DocumentNode'.`], true); }); it('useFragment preserves ReadonlyArray type', async () => { const docPath = path.join(__dirname, 'fixtures/with-fragment.ts'); const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { foo: Foo foos: [Foo!] } type Foo { value: String } `, ], documents: docPath, generates: { 'out1/': { preset, presetConfig: { fragmentMasking: true, }, }, }, }); const content = mergeOutputs([ ...result, fs.readFileSync(docPath, 'utf8'), ` function App(props: { data: FoosQuery }) { const fragments: ReadonlyArray | null | undefined = useFragment(Fragment, props.data.foos); return fragments == null ? "no data" : fragments.map(f => f.value); } `, ]); validateTs(content, undefined, false, true, [`Duplicate identifier 'DocumentNode'.`], true); }); }); it('generates correct named imports for ESM', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, importExtension: '.js', }); expect(result).toHaveLength(4); // index.ts (re-exports) const indexFile = result.find(file => file.filename === 'out1/index.ts'); expect(indexFile.content).toEqual(`export * from "./fragment-masking.js"; export * from "./gql.js";`); // gql.ts const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql.js'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { "\\n query A {\\n a\\n }\\n": typeof types.ADocument, "\\n query B {\\n b\\n }\\n": typeof types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": typeof types.CFragmentDoc, }; const documents: Documents = { "\\n query A {\\n a\\n }\\n": types.ADocument, "\\n query B {\\n b\\n }\\n": types.BDocument, "\\n fragment C on Query {\\n c\\n }\\n": types.CFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * \`\`\`ts * const query = graphql(\`query GetUser($id: ID!) { user(id: $id) { name } }\`); * \`\`\` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query A {\\n a\\n }\\n"): (typeof documents)["\\n query A {\\n a\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query B {\\n b\\n }\\n"): (typeof documents)["\\n query B {\\n b\\n }\\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n fragment C on Query {\\n c\\n }\\n"): (typeof documents)["\\n fragment C on Query {\\n c\\n }\\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;" `); // graphql.ts const graphqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(graphqlFile).toBeDefined(); }); it('should dedupe fragments - #8670', async () => { const dir = path.join(__dirname, 'tmp/duplicate-fragments'); const cleanUp = async () => { await fs.promises.rm(dir, { recursive: true, force: true }); }; const docPath = path.join(__dirname, 'fixtures/reused-fragment.ts'); const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { user(id: ID!): User! event(id: ID!): Event! } type User { id: ID! username: String! email: String! } type Event { id: ID! owner: User! attendees: [User!]! } `, ], documents: [docPath], generates: { 'out1/': { preset, plugins: [], }, }, }); // TODO: Consider using in-memory file system for tests like this. try { await cleanUp(); } catch {} await fs.promises.mkdir(path.join(dir, 'out1'), { recursive: true }); for (const file of result) { if (file.filename === 'out1/graphql.ts') { await fs.promises.writeFile(path.join(dir, file.filename), file.content, 'utf-8'); } } const { default: jiti } = await import('jiti'); const loader = jiti('', {}); const { EventQueryDocument } = loader(path.join(dir, 'out1/graphql.ts')); const printed = print(EventQueryDocument); expect(printed.match(/fragment SharedComponentFragment on User/g)?.length).toBe(1); await cleanUp(); }); it('should dedupe fragments in a "string" document mode', async () => { const dir = path.join(__dirname, 'tmp/duplicate-fragments-string'); const cleanUp = async () => { await fs.promises.rm(dir, { recursive: true, force: true }); }; const docPath = path.join(__dirname, 'fixtures/reused-fragment.ts'); const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { user(id: ID!): User! event(id: ID!): Event! } type User { id: ID! username: String! email: String! } type Event { id: ID! owner: User! attendees: [User!]! } `, ], documents: [docPath], generates: { 'out1/': { preset, plugins: [], config: { documentMode: 'string', }, }, }, }); // TODO: Consider using in-memory file system for tests like this. try { await cleanUp(); } catch {} await fs.promises.mkdir(path.join(dir, 'out1'), { recursive: true }); for (const file of result) { if (file.filename === 'out1/graphql.ts') { await fs.promises.writeFile(path.join(dir, file.filename), file.content, 'utf-8'); } } const { default: jiti } = await import('jiti'); const loader = jiti('', {}); const { EventQueryDocument } = loader(path.join(dir, 'out1/graphql.ts')); expect(EventQueryDocument.match(/fragment SharedComponentFragment on User/g)?.length).toBe(1); await cleanUp(); }); describe('when no operations are found', () => { it('still generates the helper `graphql()` (or under another `presetConfig.gqlTagName` name) function', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], generates: { 'out1/': { preset, }, }, emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(4); // index.ts (re-exports) const indexFile = result.find(file => file.filename === 'out1/index.ts'); expect(indexFile.content).toEqual(`export * from "./fragment-masking.js"; export * from "./gql.js";`); // gql.ts const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql.js'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; const documents = {}; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * * * @example * \`\`\`ts * const query = graphql(\`query GetUser($id: ID!) { user(id: $id) { name } }\`); * \`\`\` * * The query argument is unknown! * Please regenerate the types. */ export function graphql(source: string): unknown; export function graphql(source: string) { return (documents as any)[source] ?? {}; } export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;" `); // graphql.ts const graphqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(graphqlFile).toBeDefined(); }); }); describe('importExtension configuration', () => { it('generates imports with .mjs extension when importExtension is set to .mjs', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, importExtension: '.mjs', }); expect(result).toHaveLength(4); const indexFile = result.find(file => file.filename === 'out1/index.ts'); expect(indexFile.content).toEqual(`export * from "./fragment-masking.mjs"; export * from "./gql.mjs";`); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toContain(`import * as types from './graphql.mjs';`); }); it('generates imports with no extension when importExtension is empty string', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, importExtension: '', }); expect(result).toHaveLength(4); const indexFile = result.find(file => file.filename === 'out1/index.ts'); expect(indexFile.content).toEqual(`export * from "./fragment-masking"; export * from "./gql";`); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toContain(`import * as types from './graphql';`); }); it('uses importExtension over emitLegacyCommonJSImports when both are set', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, importExtension: '.mjs', emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(4); const indexFile = result.find(file => file.filename === 'out1/index.ts'); // Should use .mjs from importExtension, not .js from emitLegacyCommonJSImports: false expect(indexFile.content).toEqual(`export * from "./fragment-masking.mjs"; export * from "./gql.mjs";`); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toContain(`import * as types from './graphql.mjs';`); }); it('uses importExtension set to empty string even when emitLegacyCommonJSImports is false', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, importExtension: '', emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(4); const indexFile = result.find(file => file.filename === 'out1/index.ts'); // Should use empty string from importExtension, not .js from emitLegacyCommonJSImports: false expect(indexFile.content).toEqual(`export * from "./fragment-masking"; export * from "./gql";`); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toContain(`import * as types from './graphql';`); }); it('generates imports with custom .cjs extension when importExtension is set to .cjs', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, }, }, importExtension: '.cjs', }); expect(result).toHaveLength(4); const indexFile = result.find(file => file.filename === 'out1/index.ts'); expect(indexFile.content).toEqual(`export * from "./fragment-masking.cjs"; export * from "./gql.cjs";`); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toContain(`import * as types from './graphql.cjs';`); }); }); it('embed metadata in executable document node', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: [ /* GraphQL */ ` query aaa { a } `, /* GraphQL */ ` query bbb { b } `, ], generates: { 'out1/': { preset, presetConfig: { onExecutableDocumentNode(node) { return { cacheKeys: [node.definitions[0].name.value], }; }, }, }, }, emitLegacyCommonJSImports: false, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type BbbQueryVariables = Exact<{ [key: string]: never; }>; export type BbbQuery = { __typename?: 'Query', b?: string | null }; export type AaaQueryVariables = Exact<{ [key: string]: never; }>; export type AaaQuery = { __typename?: 'Query', a?: string | null }; export const BbbDocument = {"__meta__":{"cacheKeys":["bbb"]},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"bbb"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode; export const AaaDocument = {"__meta__":{"cacheKeys":["aaa"]},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"aaa"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode;" `); }); describe('persisted operations', () => { it('apply default settings', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { persistedDocuments: true, }, }, }, emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(5); const persistedDocuments = result.find(file => file.filename === 'out1/persisted-documents.json'); expect(persistedDocuments.content).toMatchInlineSnapshot(` "{ "b61b879c1eb0040bce65d70c8adfb1ae9360f52f": "query A { a }", "c3ea9f3f937d47d72c70055ea55c7cf88a35e608": "query B { b }" }" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename?: 'Query', a?: string | null }; export type BQueryVariables = Exact<{ [key: string]: never; }>; export type BQuery = { __typename?: 'Query', b?: string | null }; export type CFragment = { __typename?: 'Query', c?: string | null } & { ' $fragmentName'?: 'CFragment' }; export const CFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"C"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Query"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"c"}}]}}]} as unknown as DocumentNode; export const ADocument = {"__meta__":{"hash":"b61b879c1eb0040bce65d70c8adfb1ae9360f52f"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"A"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode; export const BDocument = {"__meta__":{"hash":"c3ea9f3f937d47d72c70055ea55c7cf88a35e608"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"B"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode;" `); }); it('mode="replaceDocumentWithHash"', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { persistedDocuments: { mode: 'replaceDocumentWithHash', }, }, }, }, emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(5); const persistedDocuments = result.find(file => file.filename === 'out1/persisted-documents.json'); expect(persistedDocuments.content).toMatchInlineSnapshot(` "{ "b61b879c1eb0040bce65d70c8adfb1ae9360f52f": "query A { a }", "c3ea9f3f937d47d72c70055ea55c7cf88a35e608": "query B { b }" }" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename?: 'Query', a?: string | null }; export type BQueryVariables = Exact<{ [key: string]: never; }>; export type BQuery = { __typename?: 'Query', b?: string | null }; export type CFragment = { __typename?: 'Query', c?: string | null } & { ' $fragmentName'?: 'CFragment' }; export const CFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"C"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Query"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"c"}}]}}]} as unknown as DocumentNode; export const ADocument = {"__meta__":{"hash":"b61b879c1eb0040bce65d70c8adfb1ae9360f52f"}} as unknown as DocumentNode; export const BDocument = {"__meta__":{"hash":"c3ea9f3f937d47d72c70055ea55c7cf88a35e608"}} as unknown as DocumentNode;" `); }); it('hashPropertyName="custom_property_name"', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { persistedDocuments: { hashPropertyName: 'custom_property_name', }, }, }, }, emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(5); const persistedDocuments = result.find(file => file.filename === 'out1/persisted-documents.json'); expect(persistedDocuments.content).toMatchInlineSnapshot(` "{ "b61b879c1eb0040bce65d70c8adfb1ae9360f52f": "query A { a }", "c3ea9f3f937d47d72c70055ea55c7cf88a35e608": "query B { b }" }" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename?: 'Query', a?: string | null }; export type BQueryVariables = Exact<{ [key: string]: never; }>; export type BQuery = { __typename?: 'Query', b?: string | null }; export type CFragment = { __typename?: 'Query', c?: string | null } & { ' $fragmentName'?: 'CFragment' }; export const CFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"C"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Query"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"c"}}]}}]} as unknown as DocumentNode; export const ADocument = {"__meta__":{"custom_property_name":"b61b879c1eb0040bce65d70c8adfb1ae9360f52f"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"A"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode; export const BDocument = {"__meta__":{"custom_property_name":"c3ea9f3f937d47d72c70055ea55c7cf88a35e608"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"B"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode;" `); }); it('embed metadata in executable document node', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: [ /* GraphQL */ ` query aaa { a } `, /* GraphQL */ ` query bbb { b } `, ], generates: { 'out1/': { preset, presetConfig: { persistedDocuments: true, onExecutableDocumentNode(node) { return { cacheKeys: [node.definitions[0].name.value], }; }, }, }, }, emitLegacyCommonJSImports: false, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AaaQueryVariables = Exact<{ [key: string]: never; }>; export type AaaQuery = { __typename?: 'Query', a?: string | null }; export type BbbQueryVariables = Exact<{ [key: string]: never; }>; export type BbbQuery = { __typename?: 'Query', b?: string | null }; export const AaaDocument = {"__meta__":{"cacheKeys":["aaa"],"hash":"682f60dea844320c05fcb4fb6c4118015902c9a8"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"aaa"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode; export const BbbDocument = {"__meta__":{"cacheKeys":["bbb"],"hash":"2a8e0849914b13ebc13b112ba5a502678d757511"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"bbb"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode;" `); }); it('hashAlgorithm="sha256"', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { persistedDocuments: { hashAlgorithm: 'sha256', }, }, }, }, emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(5); const persistedDocuments = result.find(file => file.filename === 'out1/persisted-documents.json'); expect(persistedDocuments.content).toMatchInlineSnapshot(` "{ "7d0eedabb966107835cf307a0ebaf93b5d2cb8c30228611ffe3d27a53c211a0c": "query A { a }", "a62a11aa72041e38d8c12ef77e1e7c208d9605db60bb5abb1717e8af98e4b410": "query B { b }" }" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename?: 'Query', a?: string | null }; export type BQueryVariables = Exact<{ [key: string]: never; }>; export type BQuery = { __typename?: 'Query', b?: string | null }; export type CFragment = { __typename?: 'Query', c?: string | null } & { ' $fragmentName'?: 'CFragment' }; export const CFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"C"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Query"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"c"}}]}}]} as unknown as DocumentNode; export const ADocument = {"__meta__":{"hash":"7d0eedabb966107835cf307a0ebaf93b5d2cb8c30228611ffe3d27a53c211a0c"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"A"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode; export const BDocument = {"__meta__":{"hash":"a62a11aa72041e38d8c12ef77e1e7c208d9605db60bb5abb1717e8af98e4b410"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"B"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode;" `); }); // This test serves to demonstrate that the custom hash function can perform arbitrary logic // Removing whitespace has no real-world application but clearly shows the custom hash function is being used it('custom hash remove whitespace', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { persistedDocuments: { hashAlgorithm: (operation: string) => { return operation.replace(/\s/g, ''); }, }, }, }, }, emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(5); const persistedDocuments = result.find(file => file.filename === 'out1/persisted-documents.json'); expect(persistedDocuments.content).toMatchInlineSnapshot(` "{ "queryA{a}": "query A { a }", "queryB{b}": "query B { b }" }" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename?: 'Query', a?: string | null }; export type BQueryVariables = Exact<{ [key: string]: never; }>; export type BQuery = { __typename?: 'Query', b?: string | null }; export type CFragment = { __typename?: 'Query', c?: string | null } & { ' $fragmentName'?: 'CFragment' }; export const CFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"C"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Query"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"c"}}]}}]} as unknown as DocumentNode; export const ADocument = {"__meta__":{"hash":"queryA{a}"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"A"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode; export const BDocument = {"__meta__":{"hash":"queryB{b}"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"B"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode;" `); }); // Tests that the custom hash function can replicate the logic and behavior by re-implementing the existing hash function (for sha256) it('custom hash sha256', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { persistedDocuments: { hashAlgorithm: (operation: string) => { const shasum = crypto.createHash('sha256'); shasum.update(operation); return shasum.digest('hex'); }, }, }, }, }, emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(5); const persistedDocuments = result.find(file => file.filename === 'out1/persisted-documents.json'); expect(persistedDocuments.content).toMatchInlineSnapshot(` "{ "7d0eedabb966107835cf307a0ebaf93b5d2cb8c30228611ffe3d27a53c211a0c": "query A { a }", "a62a11aa72041e38d8c12ef77e1e7c208d9605db60bb5abb1717e8af98e4b410": "query B { b }" }" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename?: 'Query', a?: string | null }; export type BQueryVariables = Exact<{ [key: string]: never; }>; export type BQuery = { __typename?: 'Query', b?: string | null }; export type CFragment = { __typename?: 'Query', c?: string | null } & { ' $fragmentName'?: 'CFragment' }; export const CFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"C"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Query"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"c"}}]}}]} as unknown as DocumentNode; export const ADocument = {"__meta__":{"hash":"7d0eedabb966107835cf307a0ebaf93b5d2cb8c30228611ffe3d27a53c211a0c"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"A"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode; export const BDocument = {"__meta__":{"hash":"a62a11aa72041e38d8c12ef77e1e7c208d9605db60bb5abb1717e8af98e4b410"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"B"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode;" `); }); // Custom hash example used in `preset-client.mdx` docs it('custom hash docs sha512', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { a: String b: String c: String } `, ], documents: path.join(__dirname, 'fixtures/simple-uppercase-operation-name.ts'), generates: { 'out1/': { preset, presetConfig: { persistedDocuments: { hashAlgorithm: (operation: string) => { const shasum = crypto.createHash('sha512'); shasum.update(operation); return shasum.digest('hex'); }, }, }, }, }, emitLegacyCommonJSImports: false, }); expect(result).toHaveLength(5); const persistedDocuments = result.find(file => file.filename === 'out1/persisted-documents.json'); expect(persistedDocuments.content).toMatchInlineSnapshot(` "{ "a82d8b22f2bf805563146dc8ad80b2eb054845441539e3a5a69d1f534bb5bc0bd4f9470053b9f61b6aa1966cfc2f67406258102e5ee3a356a5d171506f3ede50": "query A { a }", "bdc3d5b1e0dc35d9d21f8baadf515c472850baf279c8dd266fb21e8b8b29758d2386329f19a93dc101f3a6dd1214f5214835451e7eaf4410408d5c89f2e20a09": "query B { b }" }" `); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { __typename?: 'Query'; a?: Maybe; b?: Maybe; c?: Maybe; }; export type AQueryVariables = Exact<{ [key: string]: never; }>; export type AQuery = { __typename?: 'Query', a?: string | null }; export type BQueryVariables = Exact<{ [key: string]: never; }>; export type BQuery = { __typename?: 'Query', b?: string | null }; export type CFragment = { __typename?: 'Query', c?: string | null } & { ' $fragmentName'?: 'CFragment' }; export const CFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"C"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Query"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"c"}}]}}]} as unknown as DocumentNode; export const ADocument = {"__meta__":{"hash":"a82d8b22f2bf805563146dc8ad80b2eb054845441539e3a5a69d1f534bb5bc0bd4f9470053b9f61b6aa1966cfc2f67406258102e5ee3a356a5d171506f3ede50"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"A"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"}}]}}]} as unknown as DocumentNode; export const BDocument = {"__meta__":{"hash":"bdc3d5b1e0dc35d9d21f8baadf515c472850baf279c8dd266fb21e8b8b29758d2386329f19a93dc101f3a6dd1214f5214835451e7eaf4410408d5c89f2e20a09"},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"B"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode;" `); }); }); it('correctly handle fragment references', async () => { const { result } = await executeCodegen({ schema: /* GraphQL */ ` type Query { a: A! } type A { b: String! a: A! } `, documents: [ /* GraphQL */ ` fragment AC on A { b } `, /* GraphQL */ ` fragment AA on A { b } `, /* GraphQL */ ` fragment AB on A { b ...AC ...AA } `, /* GraphQL */ ` query OI { a { ...AB ...AC } } `, ], generates: { 'out1/': { preset, plugins: [], }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type A = { __typename?: 'A'; a: A; b: Scalars['String']['output']; }; export type Query = { __typename?: 'Query'; a: A; }; export type AbFragment = ( { __typename?: 'A', b: string } & { ' $fragmentRefs'?: { 'AcFragment': AcFragment;'AaFragment': AaFragment } } ) & { ' $fragmentName'?: 'AbFragment' }; export type AaFragment = { __typename?: 'A', b: string } & { ' $fragmentName'?: 'AaFragment' }; export type OiQueryVariables = Exact<{ [key: string]: never; }>; export type OiQuery = { __typename?: 'Query', a: ( { __typename?: 'A' } & { ' $fragmentRefs'?: { 'AbFragment': AbFragment;'AcFragment': AcFragment } } ) }; export type AcFragment = { __typename?: 'A', b: string } & { ' $fragmentName'?: 'AcFragment' }; export const AcFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AC"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"A"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode; export const AaFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AA"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"A"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode; export const AbFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AB"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"A"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AC"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AA"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AC"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"A"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AA"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"A"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}}]} as unknown as DocumentNode; export const OiDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"OI"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"a"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AB"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AC"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AC"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"A"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AA"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"A"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AB"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"A"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"b"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AC"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AA"}}]}}]} as unknown as DocumentNode;" `); }); describe('handles @defer directive', () => { it('generates correct types and metadata', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { foo: Foo foos: [Foo] } type Foo { id: String value: String } `, ], documents: path.join(__dirname, 'fixtures/with-deferred-fragment.ts'), generates: { 'out1/': { preset, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Foo = { __typename?: 'Foo'; id?: Maybe; value?: Maybe; }; export type Query = { __typename?: 'Query'; foo?: Maybe; foos?: Maybe>>; }; export type FooQueryVariables = Exact<{ [key: string]: never; }>; export type FooQuery = { __typename?: 'Query', foo?: { __typename?: 'Foo' } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) | null }; export type FoosQueryVariables = Exact<{ [key: string]: never; }>; export type FoosQuery = { __typename?: 'Query', foos?: Array<{ __typename?: 'Foo' } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) | null> | null }; export type FooFragment = { __typename?: 'Foo', value?: string | null } & { ' $fragmentName'?: 'FooFragment' }; export type FooFragment = { __typename?: 'Foo', id?: string | null } & ({ __typename?: 'Foo', value?: string | null } | { __typename?: 'Foo', value?: never }) & { ' $fragmentName'?: 'FooFragment' }; export type FooNestedFragment = { __typename?: 'Foo', id?: string | null } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) & { ' $fragmentName'?: 'FooNestedFragment' }; export const FooFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const FooFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]} as unknown as DocumentNode; export const FooNestedFragmentDoc = {"__meta__":{"deferredFields":{"foo":["id"]}},"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"fooNested"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"foo"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}]}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]} as unknown as DocumentNode; export const FooDocument = {"__meta__":{"deferredFields":{"Foo":["value"]}},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Foo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"foo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"Foo"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}]}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const FoosDocument = {"__meta__":{"deferredFields":{"Foo":["value"]}},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Foos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"foos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"Foo"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}]}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode;" `); }); it('works with persisted documents', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { foo: Foo foos: [Foo] } type Foo { id: String value: String } `, ], documents: path.join(__dirname, 'fixtures/with-deferred-fragment.ts'), generates: { 'out1/': { preset, presetConfig: { persistedDocuments: true, }, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Foo = { __typename?: 'Foo'; id?: Maybe; value?: Maybe; }; export type Query = { __typename?: 'Query'; foo?: Maybe; foos?: Maybe>>; }; export type FooQueryVariables = Exact<{ [key: string]: never; }>; export type FooQuery = { __typename?: 'Query', foo?: { __typename?: 'Foo' } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) | null }; export type FoosQueryVariables = Exact<{ [key: string]: never; }>; export type FoosQuery = { __typename?: 'Query', foos?: Array<{ __typename?: 'Foo' } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) | null> | null }; export type FooFragment = { __typename?: 'Foo', value?: string | null } & { ' $fragmentName'?: 'FooFragment' }; export type FooFragment = { __typename?: 'Foo', id?: string | null } & ({ __typename?: 'Foo', value?: string | null } | { __typename?: 'Foo', value?: never }) & { ' $fragmentName'?: 'FooFragment' }; export type FooNestedFragment = { __typename?: 'Foo', id?: string | null } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) & { ' $fragmentName'?: 'FooNestedFragment' }; export const FooFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const FooFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]} as unknown as DocumentNode; export const FooNestedFragmentDoc = {"__meta__":{"deferredFields":{"foo":["id"]}},"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"fooNested"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"foo"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}]}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]} as unknown as DocumentNode; export const FooDocument = {"__meta__":{"hash":"39c47d2da0fb0e6867abbe2ec942d9858f2d76c7","deferredFields":{"Foo":["value"]}},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Foo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"foo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"Foo"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}]}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const FoosDocument = {"__meta__":{"hash":"8aba765173b2302b9857334e9959d97a2168dbc8","deferredFields":{"Foo":["value"]}},"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Foos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"foos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"Foo"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"}}]}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"Foo"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Foo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode;" `); }); it('works with documentMode: string', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { foo: Foo foos: [Foo] } type Foo { id: String value: String } `, ], documents: path.join(__dirname, 'fixtures/with-deferred-fragment.ts'), generates: { 'out1/': { preset, config: { documentMode: 'string', }, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Foo = { __typename?: 'Foo'; id?: Maybe; value?: Maybe; }; export type Query = { __typename?: 'Query'; foo?: Maybe; foos?: Maybe>>; }; export type FooQueryVariables = Exact<{ [key: string]: never; }>; export type FooQuery = { __typename?: 'Query', foo?: { __typename?: 'Foo' } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) | null }; export type FoosQueryVariables = Exact<{ [key: string]: never; }>; export type FoosQuery = { __typename?: 'Query', foos?: Array<{ __typename?: 'Foo' } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) | null> | null }; export type FooFragment = { __typename?: 'Foo', value?: string | null } & { ' $fragmentName'?: 'FooFragment' }; export type FooFragment = { __typename?: 'Foo', id?: string | null } & ({ __typename?: 'Foo', value?: string | null } | { __typename?: 'Foo', value?: never }) & { ' $fragmentName'?: 'FooFragment' }; export type FooNestedFragment = { __typename?: 'Foo', id?: string | null } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) & { ' $fragmentName'?: 'FooNestedFragment' }; export class TypedDocumentString extends String implements DocumentTypeDecoration { __apiType?: NonNullable['__apiType']>; private value: string; public __meta__?: Record | undefined; constructor(value: string, __meta__?: Record | undefined) { super(value); this.value = value; this.__meta__ = __meta__; } override toString(): string & DocumentTypeDecoration { return this.value; } } export const FooFragmentDoc = new TypedDocumentString(\` fragment Foo on Foo { value } \`, {"fragmentName":"Foo"}) as unknown as TypedDocumentString; export const FooFragmentDoc = new TypedDocumentString(\` fragment foo on Foo { id ... on Foo @defer { value } } \`, {"fragmentName":"foo"}) as unknown as TypedDocumentString; export const FooNestedFragmentDoc = new TypedDocumentString(\` fragment fooNested on Foo { id ...foo @defer } fragment Foo on Foo { value } fragment foo on Foo { id ... on Foo @defer { value } }\`, {"fragmentName":"fooNested","deferredFields":{"foo":["id"]}}) as unknown as TypedDocumentString; export const FooDocument = new TypedDocumentString(\` query Foo { foo { ...Foo @defer } } fragment Foo on Foo { value } fragment foo on Foo { id ... on Foo @defer { value } }\`, {"deferredFields":{"Foo":["value"]}}) as unknown as TypedDocumentString; export const FoosDocument = new TypedDocumentString(\` query Foos { foos { ...Foo @defer } } fragment Foo on Foo { value } fragment foo on Foo { id ... on Foo @defer { value } }\`, {"deferredFields":{"Foo":["value"]}}) as unknown as TypedDocumentString;" `); }); it('works with documentMode: string and persisted documents', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { foo: Foo foos: [Foo] } type Foo { id: String value: String } `, ], documents: path.join(__dirname, 'fixtures/with-deferred-fragment.ts'), generates: { 'out1/': { preset, presetConfig: { persistedDocuments: true, }, config: { documentMode: 'string', }, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Foo = { __typename?: 'Foo'; id?: Maybe; value?: Maybe; }; export type Query = { __typename?: 'Query'; foo?: Maybe; foos?: Maybe>>; }; export type FooQueryVariables = Exact<{ [key: string]: never; }>; export type FooQuery = { __typename?: 'Query', foo?: { __typename?: 'Foo' } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) | null }; export type FoosQueryVariables = Exact<{ [key: string]: never; }>; export type FoosQuery = { __typename?: 'Query', foos?: Array<{ __typename?: 'Foo' } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) | null> | null }; export type FooFragment = { __typename?: 'Foo', value?: string | null } & { ' $fragmentName'?: 'FooFragment' }; export type FooFragment = { __typename?: 'Foo', id?: string | null } & ({ __typename?: 'Foo', value?: string | null } | { __typename?: 'Foo', value?: never }) & { ' $fragmentName'?: 'FooFragment' }; export type FooNestedFragment = { __typename?: 'Foo', id?: string | null } & ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': Incremental } } ) & { ' $fragmentName'?: 'FooNestedFragment' }; export class TypedDocumentString extends String implements DocumentTypeDecoration { __apiType?: NonNullable['__apiType']>; private value: string; public __meta__?: Record | undefined; constructor(value: string, __meta__?: Record | undefined) { super(value); this.value = value; this.__meta__ = __meta__; } override toString(): string & DocumentTypeDecoration { return this.value; } } export const FooFragmentDoc = new TypedDocumentString(\` fragment Foo on Foo { value } \`, {"fragmentName":"Foo"}) as unknown as TypedDocumentString; export const FooFragmentDoc = new TypedDocumentString(\` fragment foo on Foo { id ... on Foo @defer { value } } \`, {"fragmentName":"foo"}) as unknown as TypedDocumentString; export const FooNestedFragmentDoc = new TypedDocumentString(\` fragment fooNested on Foo { id ...foo @defer } fragment Foo on Foo { value } fragment foo on Foo { id ... on Foo @defer { value } }\`, {"fragmentName":"fooNested","deferredFields":{"foo":["id"]}}) as unknown as TypedDocumentString; export const FooDocument = new TypedDocumentString(\` query Foo { foo { ...Foo @defer } } fragment Foo on Foo { value } fragment foo on Foo { id ... on Foo @defer { value } }\`, {"hash":"2687841b00fe0b3b4fd0dfa2e943f80936594f58","deferredFields":{"Foo":["value"]}}) as unknown as TypedDocumentString; export const FoosDocument = new TypedDocumentString(\` query Foos { foos { ...Foo @defer } } fragment Foo on Foo { value } fragment foo on Foo { id ... on Foo @defer { value } }\`, {"hash":"8db613cc1f12f64dbde9cd6fef167fd12246330d","deferredFields":{"Foo":["value"]}}) as unknown as TypedDocumentString;" `); }); }); describe('documentMode: "string"', () => { it('generates correct types', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { foo: Foo foos: [Foo] } type Foo { value: String } `, ], documents: path.join(__dirname, 'fixtures/with-fragment.ts'), generates: { 'out1/': { preset, config: { documentMode: 'string', }, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Foo = { __typename?: 'Foo'; value?: Maybe; }; export type Query = { __typename?: 'Query'; foo?: Maybe; foos?: Maybe>>; }; export type FooQueryVariables = Exact<{ [key: string]: never; }>; export type FooQuery = { __typename?: 'Query', foo?: ( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': FooFragment } } ) | null }; export type FoosQueryVariables = Exact<{ [key: string]: never; }>; export type FoosQuery = { __typename?: 'Query', foos?: Array<( { __typename?: 'Foo' } & { ' $fragmentRefs'?: { 'FooFragment': FooFragment } } ) | null> | null }; export type FooFragment = { __typename?: 'Foo', value?: string | null } & { ' $fragmentName'?: 'FooFragment' }; export class TypedDocumentString extends String implements DocumentTypeDecoration { __apiType?: NonNullable['__apiType']>; private value: string; public __meta__?: Record | undefined; constructor(value: string, __meta__?: Record | undefined) { super(value); this.value = value; this.__meta__ = __meta__; } override toString(): string & DocumentTypeDecoration { return this.value; } } export const FooFragmentDoc = new TypedDocumentString(\` fragment Foo on Foo { value } \`, {"fragmentName":"Foo"}) as unknown as TypedDocumentString; export const FooDocument = new TypedDocumentString(\` query Foo { foo { ...Foo } } fragment Foo on Foo { value }\`) as unknown as TypedDocumentString; export const FoosDocument = new TypedDocumentString(\` query Foos { foos { ...Foo } } fragment Foo on Foo { value }\`) as unknown as TypedDocumentString;" `); }); it('graphql overloads have a nice result type', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { foo: Foo foos: [Foo] } type Foo { value: String } `, ], documents: path.join(__dirname, 'fixtures/with-fragment.ts'), generates: { 'out1/': { preset, config: { documentMode: 'string', }, }, }, }); const gqlFile = result.find(file => file.filename === 'out1/gql.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import * as types from './graphql'; /** * Map of all GraphQL operations in the project. * * This map has several performance disadvantages: * 1. It is not tree-shakeable, so it will include all operations in the project. * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. * 3. It does not support dead code elimination, so it will add unused operations. * * Therefore it is highly recommended to use the babel or swc plugin for production. * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { "\\n query Foo {\\n foo {\\n ...Foo\\n }\\n }\\n": typeof types.FooDocument, "\\n query Foos {\\n foos {\\n ...Foo\\n }\\n }\\n": typeof types.FoosDocument, "\\n fragment Foo on Foo {\\n value\\n }\\n": typeof types.FooFragmentDoc, }; const documents: Documents = { "\\n query Foo {\\n foo {\\n ...Foo\\n }\\n }\\n": types.FooDocument, "\\n query Foos {\\n foos {\\n ...Foo\\n }\\n }\\n": types.FoosDocument, "\\n fragment Foo on Foo {\\n value\\n }\\n": types.FooFragmentDoc, }; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query Foo {\\n foo {\\n ...Foo\\n }\\n }\\n"): typeof import('./graphql').FooDocument; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n query Foos {\\n foos {\\n ...Foo\\n }\\n }\\n"): typeof import('./graphql').FoosDocument; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\\n fragment Foo on Foo {\\n value\\n }\\n"): typeof import('./graphql').FooFragmentDoc; export function graphql(source: string) { return (documents as any)[source] ?? {}; } " `); }); it('correctly resolves nested fragments', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` scalar Date type Query { video(id: ID!): Video! } interface Video { id: ID! title: String! } type Movie implements Video { id: ID! title: String! releaseDate: Date! collection: Collection } type Collection { id: ID! title: String! } type Episode implements Video { id: ID! title: String! show: Show! releaseDate: Date! } type Show { id: ID! title: String! releaseDate: Date! } `, ], documents: path.join(__dirname, 'fixtures/with-nested-fragment.ts'), generates: { 'out1/': { preset, config: { documentMode: 'string', }, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toBeSimilarStringTo(` export const VideoDocument = new TypedDocumentString(\` query Video($id: ID!) { video(id: $id) { ...DetailsFragment __typename } } fragment EpisodeFragment on Episode { id title show { id title } releaseDate __typename } fragment MovieFragment on Movie { id title collection { id } releaseDate __typename } fragment DetailsFragment on Video { title __typename ...MovieFragment ...EpisodeFragment }\`) as unknown as TypedDocumentString; `); }); it('correctly skips the typename addition for the root node for subscriptions', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` schema { query: Query mutation: Mutation subscription: Subscription } type Region { regionId: Int! regionDescription: String! } type Subscription { onRegionCreated: Region! } type Query { regions: [Region] } type Mutation { createRegion(regionDescription: String!): Region } `, ], documents: path.join(__dirname, 'fixtures/subscription-root-node.ts'), generates: { 'out1/': { preset, config: { documentMode: 'string', }, documentTransforms: [addTypenameSelectionDocumentTransform], }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toBeSimilarStringTo(` /* eslint-disable */ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Mutation = { __typename?: 'Mutation'; createRegion?: Maybe; }; export type MutationCreateRegionArgs = { regionDescription: Scalars['String']['input']; }; export type Query = { __typename?: 'Query'; regions?: Maybe>>; }; export type Region = { __typename?: 'Region'; regionDescription: Scalars['String']['output']; regionId: Scalars['Int']['output']; }; export type Subscription = { __typename?: 'Subscription'; onRegionCreated: Region; }; export type OnRegionCreatedSubscriptionVariables = Exact<{ [key: string]: never; }>; export type OnRegionCreatedSubscription = { __typename?: 'Subscription', onRegionCreated: { __typename: 'Region', regionId: number, regionDescription: string } }; export class TypedDocumentString extends String implements DocumentTypeDecoration { __apiType?: NonNullable['__apiType']>; private value: string; public __meta__?: Record | undefined; constructor(value: string, __meta__?: Record | undefined) { super(value); this.value = value; this.__meta__ = __meta__; } override toString(): string & DocumentTypeDecoration { return this.value; } } export const OnRegionCreatedDocument = new TypedDocumentString(\` subscription onRegionCreated { onRegionCreated { __typename regionId regionDescription } } \`) as unknown as TypedDocumentString; `); }); }); it('support enumsAsConst option', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { thing: Thing } type Thing { color: Color! } enum Color { RED BLUE } `, ], documents: path.join(__dirname, 'fixtures/enum.ts'), generates: { 'out1/': { preset, config: { enumsAsConst: true, }, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toBeSimilarStringTo(` /* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export const Color = { Blue: 'BLUE', Red: 'RED' } as const; export type Color = typeof Color[keyof typeof Color]; export type Query = { __typename?: 'Query'; thing?: Maybe; }; export type Thing = { __typename?: 'Thing'; color: Color; }; export type FavoriteColorQueryVariables = Exact<{ [key: string]: never; }>; export type FavoriteColorQuery = { __typename?: 'Query', thing?: { __typename?: 'Thing', color: Color } | null }; export const FavoriteColorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FavoriteColor"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}}]} as unknown as DocumentNode; `); }); it('support enumValues option', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` enum Color { RED BLUE } `, ], generates: { 'out1/': { preset, config: { enumValues: { Color: './fixtures/with-enum-values#MyColor', }, }, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toBeSimilarStringTo(`/* eslint-disable */ import { MyColor as Color } from './fixtures/with-enum-values'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export { Color };`); }); it('supports immutableTypes', async () => { const { result } = await executeCodegen({ schema: [ /* GraphQL */ ` type Query { user(id: ID!): User } type User { id: ID! name: String! friends: [User!]! } `, ], documents: [ /* GraphQL */ ` query Test_User { user(id: "user-001") { id name } } `, ], generates: { 'out1/': { preset, config: { immutableTypes: true, }, }, }, }); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } }; export type Query = { readonly __typename?: 'Query'; readonly user?: Maybe; }; export type QueryUserArgs = { id: Scalars['ID']['input']; }; export type User = { readonly __typename?: 'User'; readonly friends: ReadonlyArray; readonly id: Scalars['ID']['output']; readonly name: Scalars['String']['output']; }; export type Test_UserQueryVariables = Exact<{ [key: string]: never; }>; export type Test_UserQuery = { readonly __typename?: 'Query', readonly user?: { readonly __typename?: 'User', readonly id: string, readonly name: string } | null }; export const Test_UserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Test_User"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"StringValue","value":"user-001","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode;" `); }); }); ================================================ FILE: packages/presets/client/tests/fixtures/crlf-operation.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import gql from 'gql-tag'; //@ts-ignore const A = gql(/* GraphQL */ ` query a { a } `); //@ts-ignore const B = gql(/* GraphQL */ ` query b { b } `); //@ts-ignore const C = gql(/* GraphQL */ ` fragment C on Query { c } `); ================================================ FILE: packages/presets/client/tests/fixtures/duplicate-operation.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import gql from 'gql'; //@ts-ignore const A1 = gql` query a { a } `; //@ts-ignore const A2 = gql` query a { a } `; ================================================ FILE: packages/presets/client/tests/fixtures/enum.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import gql from 'gql-tag'; //@ts-ignore const A = gql(/* GraphQL */ ` query FavoriteColor { thing { color } } `); ================================================ FILE: packages/presets/client/tests/fixtures/reused-fragment.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-nocheck const SharedComponentFragment = graphql(` fragment SharedComponentFragment on User { id username } `); const EventHeaderComponentFragment = graphql(` fragment EventHeaderComponentFragment on Event { owner { ...SharedComponentFragment } } `); const EventQueryDocument = graphql(` query EventQuery($eventId: ID!) { event(id: $eventId) { ...EventHeaderComponentFragment attendees { ...SharedComponentFragment } } } `); ================================================ FILE: packages/presets/client/tests/fixtures/simple-lowercase-operation-name.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import gql from 'gql-tag'; //@ts-ignore const A = gql(/* GraphQL */ ` query a { a } `); //@ts-ignore const B = gql(/* GraphQL */ ` query b { b } `); //@ts-ignore const C = gql(/* GraphQL */ ` fragment C on Query { c } `); ================================================ FILE: packages/presets/client/tests/fixtures/simple-uppercase-operation-name.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import gql from 'gql-tag'; //@ts-ignore const A = gql(/* GraphQL */ ` query A { a } `); //@ts-ignore const B = gql(/* GraphQL */ ` query B { b } `); //@ts-ignore const C = gql(/* GraphQL */ ` fragment C on Query { c } `); ================================================ FILE: packages/presets/client/tests/fixtures/subscription-root-node.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import gql from 'gql-tag'; gql(` subscription onRegionCreated { onRegionCreated{ regionId regionDescription } } `); ================================================ FILE: packages/presets/client/tests/fixtures/union-fragment.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore const Query = gql(/* GraphQL */ ` query Foo { foo { ...Foo } } `); //@ts-ignore const Fragment = gql(/* GraphQL */ ` fragment Foo on Foo { __typename ... on Bar { stringValue } ... on Baz { intValue } } `); ================================================ FILE: packages/presets/client/tests/fixtures/with-deferred-fragment.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore const Query = gql(/* GraphQL */ ` query Foo { foo { ...Foo @defer } } `); //@ts-ignore const ListQuery = gql(/* GraphQL */ ` query Foos { foos { ...Foo @defer } } `); //@ts-ignore const Fragment = gql(/* GraphQL */ ` fragment Foo on Foo { value } `); //@ts-ignore const NestedFragment = gql(/* GraphQL */ ` fragment foo on Foo { id ... on Foo @defer { value } } `); //@ts-ignore const NestedFragmentWithFragment = gql(/* GraphQL */ ` fragment fooNested on Foo { id ...foo @defer } `); ================================================ FILE: packages/presets/client/tests/fixtures/with-enum-values.ts ================================================ export enum MyColor { RED, BLUE, GREEN, } ================================================ FILE: packages/presets/client/tests/fixtures/with-fragment.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore const Query = gql(/* GraphQL */ ` query Foo { foo { ...Foo } } `); //@ts-ignore const ListQuery = gql(/* GraphQL */ ` query Foos { foos { ...Foo } } `); //@ts-ignore const Fragment = gql(/* GraphQL */ ` fragment Foo on Foo { value } `); ================================================ FILE: packages/presets/client/tests/fixtures/with-nested-fragment.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore const episodeFragment = gql(/* GraphQL */ ` fragment EpisodeFragment on Episode { id title show { id title } releaseDate __typename } `); //@ts-ignore const movieFragment = gql(/* GraphQL */ ` fragment MovieFragment on Movie { id title collection { id } releaseDate __typename } `); //@ts-ignore const videoDetailsFragment = gql(/* GraphQL */ ` fragment DetailsFragment on Video { title __typename ...MovieFragment ...EpisodeFragment } `); //@ts-ignore const videoQueryDocument = gql(/* GraphQL */ ` query Video($id: ID!) { video(id: $id) { ...DetailsFragment __typename } } `); ================================================ FILE: packages/presets/client/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'client-preset', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/presets/graphql-modules/CHANGELOG.md ================================================ # @graphql-codegen/graphql-modules-preset ## 5.1.4 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-codegen/visitor-plugin-common@^6.2.3` ↗︎](https://www.npmjs.com/package/@graphql-codegen/visitor-plugin-common/v/6.2.3) (from `6.2.3`, in `dependencies`) - Updated dependency [`@graphql-tools/utils@^11.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/11.0.0) (from `^10.0.0`, in `dependencies`) - Updated dependencies [[`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072), [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072)]: - @graphql-codegen/plugin-helpers@6.1.1 - @graphql-codegen/visitor-plugin-common@6.2.4 ## 5.1.3 ### Patch Changes - Updated dependencies [[`6038634`](https://github.com/dotansimha/graphql-code-generator/commit/60386344081917f2884db933309821603a2be2bf)]: - @graphql-codegen/visitor-plugin-common@6.2.3 ## 5.1.2 ### Patch Changes - Updated dependencies [[`f588d91`](https://github.com/dotansimha/graphql-code-generator/commit/f588d91ac43ea0aa5931915ce980d2e6876bb59c)]: - @graphql-codegen/visitor-plugin-common@6.2.2 ## 5.1.1 ### Patch Changes - Updated dependencies [[`b995ed1`](https://github.com/dotansimha/graphql-code-generator/commit/b995ed13a49379ea05e0e313fac68b557527523a)]: - @graphql-codegen/visitor-plugin-common@6.2.1 ## 5.1.0 ### Minor Changes - [#10510](https://github.com/dotansimha/graphql-code-generator/pull/10510) [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670) Thanks [@nickmessing](https://github.com/nickmessing)! - add importExtension configuration option ### Patch Changes - Updated dependencies [[`f821e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f821e8ab9351f23a9f7e5d5e6fc69c8e8868cad8), [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670)]: - @graphql-codegen/visitor-plugin-common@6.2.0 - @graphql-codegen/plugin-helpers@6.1.0 ## 5.0.5 ### Patch Changes - Updated dependencies [[`51a1a72`](https://github.com/dotansimha/graphql-code-generator/commit/51a1a7280578d43681391df11d320a8416c0b41d)]: - @graphql-codegen/visitor-plugin-common@6.1.2 ## 5.0.4 ### Patch Changes - Updated dependencies [[`6715330`](https://github.com/dotansimha/graphql-code-generator/commit/67153304646694d75aee24afd70c3fce12e9f1f2)]: - @graphql-codegen/visitor-plugin-common@6.1.1 ## 5.0.3 ### Patch Changes - Updated dependencies [[`8258f1f`](https://github.com/dotansimha/graphql-code-generator/commit/8258f1f6012c106d02ef28bca9ec424f70c4aa26)]: - @graphql-codegen/visitor-plugin-common@6.1.0 ## 5.0.2 ### Patch Changes - Updated dependencies [[`accdab6`](https://github.com/dotansimha/graphql-code-generator/commit/accdab69106605241933e9d66d64dc7077656f30)]: - @graphql-codegen/visitor-plugin-common@6.0.1 ## 5.0.1 ### Patch Changes - [#10447](https://github.com/dotansimha/graphql-code-generator/pull/10447) [`5dad86e`](https://github.com/dotansimha/graphql-code-generator/commit/5dad86e4753369e288fba5821722507d88afb3dc) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix \_\_isTypeOf wrongly picked on objects that are not implementing types or union members ## 5.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/visitor-plugin-common@6.0.0 - @graphql-codegen/plugin-helpers@6.0.0 ## 4.0.17 ### Patch Changes - [#10314](https://github.com/dotansimha/graphql-code-generator/pull/10314) [`d94ae3d`](https://github.com/dotansimha/graphql-code-generator/commit/d94ae3dc71f84ab2b1ce8733cf42342bb27fa951) Thanks [@acharkov](https://github.com/acharkov)! - Fix generated imports for graphql-modules-preset: .js extension is used. ## 4.0.16 ### Patch Changes - Updated dependencies [[`f6909d1`](https://github.com/dotansimha/graphql-code-generator/commit/f6909d1797c15b79a0afb7ec089471763a485bfc)]: - @graphql-codegen/visitor-plugin-common@5.8.0 ## 4.0.15 ### Patch Changes - Updated dependencies [[`d8566c0`](https://github.com/dotansimha/graphql-code-generator/commit/d8566c015943ea4dbcaeaf57d3d8406553ae230a)]: - @graphql-codegen/visitor-plugin-common@5.7.1 ## 4.0.14 ### Patch Changes - Updated dependencies [[`6d7c1d7`](https://github.com/dotansimha/graphql-code-generator/commit/6d7c1d7c0a4662acdc0efafd4234229ad0a8dd3c)]: - @graphql-codegen/visitor-plugin-common@5.7.0 ## 4.0.13 ### Patch Changes - Updated dependencies [[`60dd72f`](https://github.com/dotansimha/graphql-code-generator/commit/60dd72fb103fd7fd70b4e1def98da29588865517)]: - @graphql-codegen/visitor-plugin-common@5.6.1 ## 4.0.12 ### Patch Changes - Updated dependencies [[`1617e3c`](https://github.com/dotansimha/graphql-code-generator/commit/1617e3cf38f3059cc5ea88b540033f521f03725a), [`fa64fbf`](https://github.com/dotansimha/graphql-code-generator/commit/fa64fbf8a44e1cee7ae17806dcd178dc7350c4ba)]: - @graphql-codegen/visitor-plugin-common@5.6.0 ## 4.0.11 ### Patch Changes - Updated dependencies [[`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc), [`a235051`](https://github.com/dotansimha/graphql-code-generator/commit/a23505180ac2f275a55ece27162ec9bfcdc52e03)]: - @graphql-codegen/visitor-plugin-common@5.5.0 - @graphql-codegen/plugin-helpers@5.1.0 ## 4.0.10 ### Patch Changes - Updated dependencies [[`3f4f546`](https://github.com/dotansimha/graphql-code-generator/commit/3f4f5466ff168ad822b9a00d83d3779078e6d8c4)]: - @graphql-codegen/visitor-plugin-common@5.4.0 ## 4.0.9 ### Patch Changes - Updated dependencies [[`79fee3c`](https://github.com/dotansimha/graphql-code-generator/commit/79fee3cada20d683d250aad5aa5fef9d6ed9f4d2)]: - @graphql-codegen/visitor-plugin-common@5.3.1 ## 4.0.8 ### Patch Changes - Updated dependencies [[`808ada5`](https://github.com/dotansimha/graphql-code-generator/commit/808ada595d83d39cad045da5824cac6378e9eca3), [`14ce39e`](https://github.com/dotansimha/graphql-code-generator/commit/14ce39e41dfee38c652be736664177fa2b1df421)]: - @graphql-codegen/visitor-plugin-common@5.3.0 ## 4.0.7 ### Patch Changes - Updated dependencies [[`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`156cc2b`](https://github.com/dotansimha/graphql-code-generator/commit/156cc2b9a2a5129beba121cfa987b04e29899431), [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e), [`b49457b`](https://github.com/dotansimha/graphql-code-generator/commit/b49457b5f29328d2dc23c642788a2e697cb8966e)]: - @graphql-codegen/plugin-helpers@5.0.4 - @graphql-codegen/visitor-plugin-common@5.2.0 ## 4.0.6 ### Patch Changes - Updated dependencies [[`920b443`](https://github.com/dotansimha/graphql-code-generator/commit/920b443a401b8cc4811f64ec5b25fc7b4ae32b53), [`ed9c205`](https://github.com/dotansimha/graphql-code-generator/commit/ed9c205d15d7f14ed73e54aecf40e4fad5664e9d)]: - @graphql-codegen/visitor-plugin-common@5.1.0 ## 4.0.5 ### Patch Changes - Updated dependencies [[`53f270a`](https://github.com/dotansimha/graphql-code-generator/commit/53f270acfa1da992e0f9d2e50921bb588392f8a5)]: - @graphql-codegen/visitor-plugin-common@5.0.0 ## 4.0.4 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/visitor-plugin-common@4.1.2 - @graphql-codegen/plugin-helpers@5.0.3 ## 4.0.3 ### Patch Changes - Updated dependencies [[`7718a8113`](https://github.com/dotansimha/graphql-code-generator/commit/7718a8113dc6282475cb738f1e28698b8221fa2f)]: - @graphql-codegen/visitor-plugin-common@4.1.1 ## 4.0.2 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975), [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 - @graphql-codegen/visitor-plugin-common@4.1.0 ## 4.0.1 ### Patch Changes - Updated dependencies [[`2276708d0`](https://github.com/dotansimha/graphql-code-generator/commit/2276708d0ea2aab4942136923651226de4aabe5a)]: - @graphql-codegen/visitor-plugin-common@4.0.1 ## 4.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/10.0.0) (from `^9.0.0`, in `dependencies`) - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`3848a2b73`](https://github.com/dotansimha/graphql-code-generator/commit/3848a2b73339fe9f474b31647b71e75b9ca52a96), [`ba84a3a27`](https://github.com/dotansimha/graphql-code-generator/commit/ba84a3a2758d94dac27fcfbb1bafdf3ed7c32929), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`50471e651`](https://github.com/dotansimha/graphql-code-generator/commit/50471e6514557db827cd26157262401c6c600a8c), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c), [`ca02ad172`](https://github.com/dotansimha/graphql-code-generator/commit/ca02ad172a0e8f52570fdef4271ec286d883236d), [`e1dc75f3c`](https://github.com/dotansimha/graphql-code-generator/commit/e1dc75f3c598bf7f83138ca533619716fc73f823), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0), [`5950f5a68`](https://github.com/dotansimha/graphql-code-generator/commit/5950f5a6843cdd92b9d5b8ced3a97b68eadf9f30), [`5aa95aa96`](https://github.com/dotansimha/graphql-code-generator/commit/5aa95aa969993043ba5e9d5dabebd7127ea5e22c)]: - @graphql-codegen/plugin-helpers@5.0.0 - @graphql-codegen/visitor-plugin-common@4.0.0 ## 3.1.3 ### Patch Changes - Updated dependencies [[`386cf9044`](https://github.com/dotansimha/graphql-code-generator/commit/386cf9044a41d87ed45069b22d26b30f4b262a85), [`402cb8ac0`](https://github.com/dotansimha/graphql-code-generator/commit/402cb8ac0f0c347b186d295c4b69c19e25a65d00)]: - @graphql-codegen/visitor-plugin-common@3.1.1 ## 3.1.2 ### Patch Changes - Updated dependencies [[`e56790104`](https://github.com/dotansimha/graphql-code-generator/commit/e56790104ae56d6c5b48ef71823345bd09d3b835), [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087), [`acb647e4e`](https://github.com/dotansimha/graphql-code-generator/commit/acb647e4efbddecf732b6e55dc47ac40c9bdaf08), [`9f4d9c5a4`](https://github.com/dotansimha/graphql-code-generator/commit/9f4d9c5a479d34da25df8e060a8c2b3b162647dd)]: - @graphql-codegen/visitor-plugin-common@3.1.0 - @graphql-codegen/plugin-helpers@4.2.0 ## 3.1.1 ### Patch Changes - Updated dependencies [[`ba0610bbd`](https://github.com/dotansimha/graphql-code-generator/commit/ba0610bbd4578d8a82078014766f56d8ae5fcf7a), [`4b49f6fbe`](https://github.com/dotansimha/graphql-code-generator/commit/4b49f6fbed802907b460bfb7b6e9a85f88c555bc), [`b343626c9`](https://github.com/dotansimha/graphql-code-generator/commit/b343626c978b9ee0f14e314cea6c01ae3dad057c)]: - @graphql-codegen/visitor-plugin-common@3.0.2 ## 3.1.0 ### Minor Changes - [#8723](https://github.com/dotansimha/graphql-code-generator/pull/8723) [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15) Thanks [@kazekyo](https://github.com/kazekyo)! - Introduce a new feature called DocumentTransform. DocumentTransform is a functionality that allows you to modify `documents` before they are processed by plugins. You can use functions passed to the `documentTransforms` option to make changes to GraphQL documents. To use this feature, you can write `documentTransforms` as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { // Make some changes to the documents return documents } } ] } } } export default config ``` For instance, to remove a `@localOnlyDirective` directive from `documents`, you can write the following code: ```js import type { CodegenConfig } from '@graphql-codegen/cli' import { visit } from 'graphql' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { return documents.map(documentFile => { documentFile.document = visit(documentFile.document, { Directive: { leave(node) { if (node.name.value === 'localOnlyDirective') return null } } }) return documentFile }) } } ] } } } export default config ``` DocumentTransform can also be specified by file name. You can create a custom file for a specific transformation and pass it to `documentTransforms`. Let's create the document transform as a file: ```js module.exports = { transform: ({ documents }) => { // Make some changes to the documents return documents } } ``` Then, you can specify the file name as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: ['./my-document-transform.js'] } } } export default config ``` ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`6b6fe3cbc`](https://github.com/dotansimha/graphql-code-generator/commit/6b6fe3cbcc7de748754703adce0f62f3e070a098), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 - @graphql-codegen/visitor-plugin-common@3.0.1 ## 3.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - [#8871](https://github.com/dotansimha/graphql-code-generator/pull/8871) [`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5) Thanks [@B2o5T](https://github.com/B2o5T)! - eslint fixes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/visitor-plugin-common@3.0.0 - @graphql-codegen/plugin-helpers@4.0.0 ## 2.5.12 ### Patch Changes - Updated dependencies [[`a98198524`](https://github.com/dotansimha/graphql-code-generator/commit/a9819852443884b43de7c15040ccffc205f9177a)]: - @graphql-codegen/visitor-plugin-common@2.13.8 ## 2.5.11 ### Patch Changes - Updated dependencies [[`eb454d06c`](https://github.com/dotansimha/graphql-code-generator/commit/eb454d06c977f11f7d4a7b0b07eb80f8fd590560)]: - @graphql-codegen/visitor-plugin-common@2.13.7 ## 2.5.10 ### Patch Changes - [#8771](https://github.com/dotansimha/graphql-code-generator/pull/8771) [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.8.0`, in `dependencies`) - Updated dependencies [[`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7), [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316)]: - @graphql-codegen/plugin-helpers@3.1.2 - @graphql-codegen/visitor-plugin-common@2.13.6 ## 2.5.9 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81), [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a)]: - @graphql-codegen/plugin-helpers@3.1.1 - @graphql-codegen/visitor-plugin-common@2.13.5 ## 2.5.8 ### Patch Changes - [#8686](https://github.com/dotansimha/graphql-code-generator/pull/8686) [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`change-case-all@1.0.15` ↗︎](https://www.npmjs.com/package/change-case-all/v/1.0.15) (from `1.0.14`, in `dependencies`) - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 - @graphql-codegen/visitor-plugin-common@2.13.4 ## 2.5.7 ### Patch Changes - Updated dependencies [[`62f655452`](https://github.com/dotansimha/graphql-code-generator/commit/62f6554520955dd675e11c920f35ef9bf0aaeffe)]: - @graphql-codegen/visitor-plugin-common@2.13.3 ## 2.5.6 ### Patch Changes - Updated dependencies [[`ef4c2c9c2`](https://github.com/dotansimha/graphql-code-generator/commit/ef4c2c9c233c68830f10eb4c167c7cceead27122)]: - @graphql-codegen/visitor-plugin-common@2.13.2 ## 2.5.5 ### Patch Changes - Updated dependencies [[`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127)]: - @graphql-codegen/visitor-plugin-common@2.13.1 - @graphql-codegen/plugin-helpers@2.7.2 ## 2.5.4 ### Patch Changes - Updated dependencies [[`a46b8d99c`](https://github.com/dotansimha/graphql-code-generator/commit/a46b8d99c797283d773ec14163c62be9c84d4c2b)]: - @graphql-codegen/visitor-plugin-common@2.13.0 ## 2.5.3 ### Patch Changes - [#8486](https://github.com/dotansimha/graphql-code-generator/pull/8486) [`08add4e88`](https://github.com/dotansimha/graphql-code-generator/commit/08add4e88af8fd05172cbb8f7973952155c43b4a) Thanks [@jycouet](https://github.com/jycouet)! - handle global config.useTypeImports in graphql-modules ## 2.5.2 ### Patch Changes - Updated dependencies [[`1bd7f771c`](https://github.com/dotansimha/graphql-code-generator/commit/1bd7f771ccb949a5a37395c7c57cb41c19340714)]: - @graphql-codegen/visitor-plugin-common@2.12.2 ## 2.5.1 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` - Updated dependencies [[`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f), [`47d0a57e2`](https://github.com/dotansimha/graphql-code-generator/commit/47d0a57e27dd0d2334670bfc6c81c45e00ff4e74)]: - @graphql-codegen/visitor-plugin-common@2.12.1 - @graphql-codegen/plugin-helpers@2.6.2 ## 2.5.0 ### Minor Changes - [#6796](https://github.com/dotansimha/graphql-code-generator/pull/6796) [`8b6e8e664`](https://github.com/dotansimha/graphql-code-generator/commit/8b6e8e6648f2d95cc40873cfc008a545d8a9c46f) Thanks [@kamilkisiela](https://github.com/kamilkisiela)! - Introduce requireRootResolvers flag ## 2.4.2 ### Patch Changes - Updated dependencies [2cbcbb371] - @graphql-codegen/visitor-plugin-common@2.12.0 - @graphql-codegen/plugin-helpers@2.6.0 ## 2.4.1 ### Patch Changes - 525ad580b: Revert breaking change for Next.js applications that are incapable of resolving an import with a `.js` extension. - Updated dependencies [525ad580b] - @graphql-codegen/visitor-plugin-common@2.11.1 ## 2.4.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) ### Patch Changes - Updated dependencies [68bb30e19] - Updated dependencies [d84afec09] - Updated dependencies [a4fe5006b] - Updated dependencies [8e44df58b] - @graphql-codegen/visitor-plugin-common@2.11.0 - @graphql-codegen/plugin-helpers@2.5.0 ## 2.3.14 ### Patch Changes - Updated dependencies [aa1e6eafd] - Updated dependencies [a42fcbfe4] - Updated dependencies [8b10f22be] - @graphql-codegen/visitor-plugin-common@2.10.0 ## 2.3.13 ### Patch Changes - Updated dependencies [d16bebacb] - @graphql-codegen/visitor-plugin-common@2.9.1 ## 2.3.12 ### Patch Changes - Updated dependencies [c3d7b7226] - @graphql-codegen/visitor-plugin-common@2.9.0 ## 2.3.11 ### Patch Changes - Updated dependencies [f1fb77bd4] - @graphql-codegen/visitor-plugin-common@2.8.0 ## 2.3.10 ### Patch Changes - Updated dependencies [9a5f31cb6] - @graphql-codegen/visitor-plugin-common@2.7.6 ## 2.3.9 ### Patch Changes - Updated dependencies [2966686e9] - @graphql-codegen/visitor-plugin-common@2.7.5 ## 2.3.8 ### Patch Changes - Updated dependencies [337fd4f77] - @graphql-codegen/visitor-plugin-common@2.7.4 ## 2.3.7 ### Patch Changes - Updated dependencies [54718c039] - @graphql-codegen/visitor-plugin-common@2.7.3 ## 2.3.6 ### Patch Changes - Updated dependencies [11d05e361] - @graphql-codegen/visitor-plugin-common@2.7.2 ## 2.3.5 ### Patch Changes - Updated dependencies [fd55e2039] - @graphql-codegen/visitor-plugin-common@2.7.1 ## 2.3.4 ### Patch Changes - Updated dependencies [1479233df] - @graphql-codegen/visitor-plugin-common@2.7.0 ## 2.3.3 ### Patch Changes - Updated dependencies [c8ef37ae0] - Updated dependencies [754a33715] - Updated dependencies [bef4376d5] - Updated dependencies [be7cb3a82] - @graphql-codegen/visitor-plugin-common@2.6.0 - @graphql-codegen/plugin-helpers@2.4.0 ## 2.3.2 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects - Updated dependencies [6002feb3d] - @graphql-codegen/visitor-plugin-common@2.5.2 - @graphql-codegen/plugin-helpers@2.3.2 ## 2.3.1 ### Patch Changes - Updated dependencies [a9f1f1594] - Updated dependencies [9ea6621ec] - @graphql-codegen/visitor-plugin-common@2.5.1 ## 2.3.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ### Patch Changes - Updated dependencies [97ddb487a] - @graphql-codegen/visitor-plugin-common@2.5.0 - @graphql-codegen/plugin-helpers@2.3.0 ## 2.2.0 ### Minor Changes - efae660d1: Added an option to allow to skip generating code related to graphql-modules library ## 2.1.6 ### Patch Changes - Updated dependencies [ad02cb9b8] - @graphql-codegen/visitor-plugin-common@2.4.0 ## 2.1.5 ### Patch Changes - Updated dependencies [b9e85adae] - Updated dependencies [7c60e5acc] - Updated dependencies [3c2c847be] - @graphql-codegen/visitor-plugin-common@2.3.0 - @graphql-codegen/plugin-helpers@2.2.0 ## 2.1.4 ### Patch Changes - Updated dependencies [0b090e31a] - @graphql-codegen/visitor-plugin-common@2.2.1 ## 2.1.3 ### Patch Changes - Updated dependencies [d6c2d4c09] - Updated dependencies [feeae1c66] - Updated dependencies [5086791ac] - @graphql-codegen/visitor-plugin-common@2.2.0 ## 2.1.2 ### Patch Changes - f32521da3: Duplication of TS interfaces when GraphQL type definition and type extension are in the same module - Updated dependencies [6470e6cc9] - Updated dependencies [263570e50] - Updated dependencies [35199dedf] - @graphql-codegen/visitor-plugin-common@2.1.2 - @graphql-codegen/plugin-helpers@2.1.1 ## 2.1.1 ### Patch Changes - Updated dependencies [aabeff181] - @graphql-codegen/visitor-plugin-common@2.1.1 ## 2.1.0 ### Minor Changes - 440172cfe: support ESM ### Patch Changes - Updated dependencies [290170262] - Updated dependencies [24185985a] - Updated dependencies [39773f59b] - Updated dependencies [440172cfe] - @graphql-codegen/visitor-plugin-common@2.1.0 - @graphql-codegen/plugin-helpers@2.1.0 ## 2.0.1 ### Patch Changes - edd029e87: fix(graphql-modules-preset): do not parse SDL and use extendedSources that have parsed document already ## 2.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ### Patch Changes - Updated dependencies [d80efdec4] - Updated dependencies [d80efdec4] - Updated dependencies [b0cb13df4] - @graphql-codegen/visitor-plugin-common@2.0.0 - @graphql-codegen/plugin-helpers@2.0.0 ## 1.2.10 ### Patch Changes - Updated dependencies [df19a4ed] - Updated dependencies [470336a1] - Updated dependencies [9005cc17] - @graphql-codegen/visitor-plugin-common@1.22.0 - @graphql-codegen/plugin-helpers@1.18.8 ## 1.2.9 ### Patch Changes - Updated dependencies [6762aff5] - @graphql-codegen/visitor-plugin-common@1.21.3 ## 1.2.8 ### Patch Changes - Updated dependencies [6aaecf1c] - @graphql-codegen/visitor-plugin-common@1.21.2 ## 1.2.7 ### Patch Changes - Updated dependencies [cf1e5abc] - @graphql-codegen/visitor-plugin-common@1.21.1 ## 1.2.6 ### Patch Changes - Updated dependencies [dfd25caf] - Updated dependencies [8da7dff6] - @graphql-codegen/visitor-plugin-common@1.21.0 - @graphql-codegen/plugin-helpers@1.18.7 ## 1.2.5 ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error - Updated dependencies [d9212aa0] - Updated dependencies [f0b5ea53] - Updated dependencies [097bea2f] - @graphql-codegen/visitor-plugin-common@1.20.0 - @graphql-codegen/plugin-helpers@1.18.5 ## 1.2.4 ### Patch Changes - 23862e7e: fix(naming-convention): revert and pin change-case-all dependency for workaround #3256 - Updated dependencies [23862e7e] - @graphql-codegen/visitor-plugin-common@1.19.1 - @graphql-codegen/plugin-helpers@1.18.4 ## 1.2.3 ### Patch Changes - 7615c6cd: Revery enum-resolvers since it's causing issues ## 1.2.2 ### Patch Changes - f7a94f9d: Include enum resolvers - 3cba8833: Fixed issue with preset breaking when pattern doesn't match - 29b75b1e: enhance(namingConvention): use change-case-all instead of individual packages for naming convention - Updated dependencies [e947f8e3] - Updated dependencies [29b75b1e] - Updated dependencies [d4942d04] - Updated dependencies [1f6f3db6] - Updated dependencies [29b75b1e] - @graphql-codegen/visitor-plugin-common@1.19.0 - @graphql-codegen/plugin-helpers@1.18.3 ## 1.2.1 ### Patch Changes - c7cb4195: fix(graphql-modules-preset): apply naming convention to scalar config references in module typings - Updated dependencies [63be0f40] - Updated dependencies [190482a1] - Updated dependencies [4444348d] - Updated dependencies [142b32b3] - Updated dependencies [42213fa0] - @graphql-codegen/visitor-plugin-common@1.18.1 ## 1.2.0 ### Minor Changes - f1b99b90: Added support for generating module types as `d.ts` ### Patch Changes - Updated dependencies [64293437] - Updated dependencies [fd5843a7] - Updated dependencies [d75051f5] - @graphql-codegen/visitor-plugin-common@1.17.22 ## 1.1.0 ### Minor Changes - 6b708b69: Added `importBaseTypesFrom` flag to allow customizations of the import for the base types ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies - Updated dependencies [1183d173] - @graphql-codegen/visitor-plugin-common@1.17.20 - @graphql-codegen/plugin-helpers@1.18.2 ## 1.0.0 ### Major Changes - faa13973: New Plugin! ### Patch Changes - Updated dependencies [faa13973] - @graphql-codegen/visitor-plugin-common@1.17.18 ================================================ FILE: packages/presets/graphql-modules/package.json ================================================ { "name": "@graphql-codegen/graphql-modules-preset", "version": "5.1.4", "description": "GraphQL Code Generator preset for modularized schema", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/presets/graphql-modules" }, "license": "MIT", "scripts": { "prepack": "bob prepack" }, "devDependencies": { "@types/parse-filepath": "1.0.2" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.1", "@graphql-codegen/visitor-plugin-common": "^6.2.4", "@graphql-tools/utils": "^11.0.0", "parse-filepath": "^1.0.2", "change-case-all": "1.0.15", "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/presets/graphql-modules/src/builder.ts ================================================ import { BaseVisitor } from '@graphql-codegen/visitor-plugin-common'; import { pascalCase } from 'change-case-all'; import { DocumentNode, EnumTypeDefinitionNode, EnumTypeExtensionNode, GraphQLSchema, InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode, InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, isScalarType, Kind, ObjectTypeDefinitionNode, ObjectTypeExtensionNode, TypeDefinitionNode, TypeExtensionNode, visit, } from 'graphql'; import { ModulesConfig } from './config.js'; import { buildBlock, collectUsedTypes, concatByKey, createObject, indent, pushUnique, unique, uniqueByKey, withQuotes, } from './utils.js'; type RegistryKeys = 'objects' | 'inputs' | 'interfaces' | 'scalars' | 'unions' | 'enums'; type Registry = Record; const registryKeys: RegistryKeys[] = ['objects', 'inputs', 'interfaces', 'scalars', 'unions', 'enums']; const resolverKeys: Array> = ['scalars', 'objects', 'enums']; const withIsTypeOfKeys: Array<'objects'> = ['objects']; export function buildModule( name: string, doc: DocumentNode, { importNamespace, importPath, encapsulate, requireRootResolvers, shouldDeclare, rootTypes, schema, baseVisitor, useGraphQLModules, useTypeImports = false, }: { importNamespace: string; importPath: string; encapsulate: ModulesConfig['encapsulateModuleTypes']; requireRootResolvers: ModulesConfig['requireRootResolvers']; shouldDeclare: boolean; rootTypes: string[]; baseVisitor: BaseVisitor; schema?: GraphQLSchema; useGraphQLModules: boolean; useTypeImports?: boolean; } ): string { const picks: Record> = createObject(registryKeys, () => ({})); const defined: Registry = createObject(registryKeys, () => []); const extended: Registry = createObject(registryKeys, () => []); const withIsTypeOf: { objects: string[] } = createObject(withIsTypeOfKeys, () => []); // List of types used in objects, fields, arguments etc const usedTypes = collectUsedTypes(doc); visit(doc, { ObjectTypeDefinition(node) { collectTypeDefinition(node); }, ObjectTypeExtension(node) { collectTypeExtension(node); }, InputObjectTypeDefinition(node) { collectTypeDefinition(node); }, InputObjectTypeExtension(node) { collectTypeExtension(node); }, InterfaceTypeDefinition(node) { collectTypeDefinition(node); }, InterfaceTypeExtension(node) { collectTypeExtension(node); }, ScalarTypeDefinition(node) { collectTypeDefinition(node); }, UnionTypeDefinition(node) { collectTypeDefinition(node); }, UnionTypeExtension(node) { collectTypeExtension(node); }, EnumTypeDefinition(node) { collectTypeDefinition(node); }, EnumTypeExtension(node) { collectTypeExtension(node); }, }); // Defined and Extended types const visited: Registry = createObject(registryKeys, key => concatByKey(defined, extended, key)); // Types that are not defined or extended in a module, they come from other modules const external: Registry = createObject(registryKeys, key => uniqueByKey(extended, defined, key)); // // // // Prints // // // // An actual output const imports = [`import${useTypeImports ? ' type' : ''} * as ${importNamespace} from "${importPath}";`]; if (useGraphQLModules) { imports.push(`import${useTypeImports ? ' type' : ''} * as gm from "graphql-modules";`); } let content = [ printDefinedFields(), printDefinedEnumValues(), printDefinedInputFields(), printSchemaTypes(usedTypes), printScalars(visited), printResolveSignaturesPerType(visited), printResolversType(visited), useGraphQLModules ? printResolveMiddlewareMap() : undefined, ] .filter(Boolean) .join('\n\n'); if (encapsulate === 'namespace') { content = `${shouldDeclare ? 'declare' : 'export'} namespace ${baseVisitor.convertName(name, { suffix: 'Module', useTypesPrefix: false, useTypesSuffix: false, })} {\n` + (shouldDeclare ? `${indent(2)(imports.join('\n'))}\n` : '') + indent(2)(content) + '\n}'; } return [...(shouldDeclare ? [] : imports), content].filter(Boolean).join('\n'); /** * A dictionary of fields to pick from an object */ function printDefinedFields() { return buildBlock({ name: `interface DefinedFields`, lines: [...visited.objects, ...visited.interfaces].map( typeName => `${typeName}: ${printPicks(typeName, { ...picks.objects, ...picks.interfaces, })};` ), }); } /** * A dictionary of values to pick from an enum */ function printDefinedEnumValues() { return buildBlock({ name: `interface DefinedEnumValues`, lines: visited.enums.map(typeName => `${typeName}: ${printPicks(typeName, picks.enums)};`), }); } function encapsulateTypeName(typeName: string): string { if (encapsulate === 'prefix') { return `${pascalCase(name)}_${typeName}`; } return typeName; } /** * A dictionary of fields to pick from an input */ function printDefinedInputFields() { return buildBlock({ name: `interface DefinedInputFields`, lines: visited.inputs.map(typeName => `${typeName}: ${printPicks(typeName, picks.inputs)};`), }); } /** * Prints signatures of schema types with picks */ function printSchemaTypes(types: string[]) { return types .filter(type => !visited.scalars.includes(type)) .map(printExportType) .join('\n'); } function printResolveSignaturesPerType(registry: Registry) { return [ [...registry.objects, ...registry.interfaces] .map(name => printResolverType( name, 'DefinedFields', // In case of enabled `requireRootResolvers` flag, the preset has to produce a non-optional properties. requireRootResolvers && rootTypes.includes(name), !rootTypes.includes(name) && defined.objects.includes(name) && withIsTypeOf.objects.includes(name) ? ` | '__isTypeOf'` : '' ) ) .join('\n'), ].join('\n'); } function printScalars(registry: Registry) { if (!registry.scalars.length) { return ''; } return [ `export type ${encapsulateTypeName('Scalars')} = Pick<${importNamespace}.Scalars, ${registry.scalars .map(withQuotes) .join(' | ')}>;`, ...registry.scalars.map(scalar => { const convertedName = baseVisitor.convertName(scalar, { suffix: 'ScalarConfig', }); return `export type ${encapsulateTypeName(convertedName)} = ${importNamespace}.${convertedName};`; }), ].join('\n'); } /** * Aggregation of type resolver signatures */ function printResolversType(registry: Registry) { const lines: string[] = []; for (const kind in registry) { const k = kind as RegistryKeys; if (Object.prototype.hasOwnProperty.call(registry, k) && resolverKeys.includes(k as any)) { const types = registry[k]; for (const typeName of types) { if (k === 'enums') { continue; } if (k === 'scalars') { lines.push(`${typeName}?: ${encapsulateTypeName(importNamespace)}.Resolvers['${typeName}'];`); } else { // In case of enabled `requireRootResolvers` flag, the preset has to produce a non-optional property. const fieldModifier = requireRootResolvers && rootTypes.includes(typeName) ? '' : '?'; lines.push(`${typeName}${fieldModifier}: ${encapsulateTypeName(typeName)}Resolvers;`); } } } } return buildBlock({ name: `export interface ${encapsulateTypeName('Resolvers')}`, lines, }); } /** * Signature for a map of resolve middlewares */ function printResolveMiddlewareMap() { const wildcardField = printResolveMiddlewareRecord(withQuotes('*')); const blocks: string[] = [buildBlock({ name: `${withQuotes('*')}?:`, lines: [wildcardField] })]; // Type.Field for (const typeName in picks.objects) { if (Object.prototype.hasOwnProperty.call(picks.objects, typeName)) { const fields = picks.objects[typeName]; const lines = [wildcardField].concat(fields.map(field => printResolveMiddlewareRecord(field))); blocks.push( buildBlock({ name: `${typeName}?:`, lines, }) ); } } return buildBlock({ name: `export interface ${encapsulateTypeName('MiddlewareMap')}`, lines: blocks, }); } function printResolveMiddlewareRecord(path: string): string { return `${path}?: gm.Middleware[];`; } function printResolverType(typeName: string, picksTypeName: string, requireFieldsResolvers = false, extraKeys = '') { const typeSignature = `Pick<${importNamespace}.${baseVisitor.convertName(typeName, { suffix: 'Resolvers', })}, ${picksTypeName}['${typeName}']${extraKeys}>`; return `export type ${encapsulateTypeName(`${typeName}Resolvers`)} = ${ requireFieldsResolvers ? `Required<${typeSignature}>` : typeSignature };`; } function printPicks(typeName: string, records: Record): string { return records[typeName].filter(unique).map(withQuotes).join(' | '); } function printTypeBody(typeName: string): string { const coreType = `${importNamespace}.${baseVisitor.convertName(typeName, { useTypesSuffix: true, useTypesPrefix: true, })}`; if (external.enums.includes(typeName) || external.objects.includes(typeName)) { if (schema && isScalarType(schema.getType(typeName))) { return `${importNamespace}.Scalars['${typeName}']`; } return coreType; } if (defined.enums.includes(typeName) && picks.enums[typeName]) { return `DefinedEnumValues['${typeName}']`; } if (defined.objects.includes(typeName) && picks.objects[typeName]) { return `Pick<${coreType}, DefinedFields['${typeName}']>`; } if (defined.interfaces.includes(typeName) && picks.interfaces[typeName]) { return `Pick<${coreType}, DefinedFields['${typeName}']>`; } if (defined.inputs.includes(typeName) && picks.inputs[typeName]) { return `Pick<${coreType}, DefinedInputFields['${typeName}']>`; } return coreType; } function printExportType(typeName: string): string { return `export type ${encapsulateTypeName(typeName)} = ${printTypeBody(typeName)};`; } // // // // Utils // // // function collectFields( node: | ObjectTypeDefinitionNode | ObjectTypeExtensionNode | InterfaceTypeDefinitionNode | InterfaceTypeExtensionNode | InputObjectTypeDefinitionNode | InputObjectTypeExtensionNode, picksObj: Record ) { const name = node.name.value; if (node.fields) { picksObj[name] ||= []; for (const field of node.fields) { picksObj[name].push(field.name.value); } } } function collectValuesFromEnum(node: EnumTypeDefinitionNode | EnumTypeExtensionNode) { const name = node.name.value; if (node.values) { picks.enums[name] ||= []; for (const field of node.values) { picks.enums[name].push(field.name.value); } } } function collectTypeDefinition(node: TypeDefinitionNode) { const name = node.name.value; switch (node.kind) { case Kind.OBJECT_TYPE_DEFINITION: { defined.objects.push(name); collectFields(node, picks.objects); if (node.interfaces?.length > 0) { withIsTypeOf.objects.push(name); } break; } case Kind.ENUM_TYPE_DEFINITION: { defined.enums.push(name); collectValuesFromEnum(node); break; } case Kind.INPUT_OBJECT_TYPE_DEFINITION: { defined.inputs.push(name); collectFields(node, picks.inputs); break; } case Kind.SCALAR_TYPE_DEFINITION: { defined.scalars.push(name); break; } case Kind.INTERFACE_TYPE_DEFINITION: { defined.interfaces.push(name); collectFields(node, picks.interfaces); break; } case Kind.UNION_TYPE_DEFINITION: { defined.unions.push(name); for (const namedType of node.types || []) { pushUnique(withIsTypeOf.objects, namedType.name.value); } break; } } } function collectTypeExtension(node: TypeExtensionNode) { const name = node.name.value; switch (node.kind) { case Kind.OBJECT_TYPE_EXTENSION: { collectFields(node, picks.objects); // Do not include root types as extensions // so we can use them in DefinedFields if (rootTypes.includes(name)) { pushUnique(defined.objects, name); return; } pushUnique(extended.objects, name); if (node.interfaces?.length > 0) { pushUnique(withIsTypeOf.objects, name); } break; } case Kind.ENUM_TYPE_EXTENSION: { collectValuesFromEnum(node); pushUnique(extended.enums, name); break; } case Kind.INPUT_OBJECT_TYPE_EXTENSION: { collectFields(node, picks.inputs); pushUnique(extended.inputs, name); break; } case Kind.INTERFACE_TYPE_EXTENSION: { collectFields(node, picks.interfaces); pushUnique(extended.interfaces, name); break; } case Kind.UNION_TYPE_EXTENSION: { pushUnique(extended.unions, name); break; } } } } ================================================ FILE: packages/presets/graphql-modules/src/config.ts ================================================ export type ModulesConfig = { /** * @name baseTypesPath * @type string * @description Required, should point to the base schema types file. * The key of the output is used a base path for this file. * * @example * ```ts filename="codegen.ts" {10} * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * preset: 'modules', * plugins: ['typescript-resolvers'], * presetConfig: { * baseTypesPath: 'types.ts' * }, * }, * }, * }; * export default config; * ``` */ baseTypesPath: string; /** * @name importBaseTypesFrom * @type string * @description Overrides the package import for the base types. Use this if you are within a monorepo, and you wish * to import the base types directly from a different package, and not from a relative path. * */ importBaseTypesFrom?: string; /** * @name cwd * @type string * @description Optional, override the `cwd` of the execution. We are using `cwd` to figure out the imports between files. Use this if your execution path is not your project root directory. * @default process.cwd() * * @example * ```ts filename="codegen.ts" {10} * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * preset: 'modules', * plugins: ['typescript-resolvers'], * presetConfig: { * baseTypesPath: 'types.ts', * cwd: '/some/path' * }, * }, * }, * }; * export default config; * ``` */ cwd?: string; /** * @name importTypesNamespace * @type string * @description Optional, override the name of the import namespace used to import from the `baseTypesPath` file. * @default Types * * @example * ```ts filename="codegen.ts" {10} * import type { CodegenConfig } from '@graphql-codegen/cli'; * * const config: CodegenConfig = { * // ... * generates: { * 'path/to/file.ts': { * preset: 'modules', * plugins: ['typescript-resolvers'], * presetConfig: { * baseTypesPath: 'types.ts', * importTypesNamespace: 'core' * }, * }, * }, * }; * export default config; * ``` */ importTypesNamespace?: string; /** * @name filename * @type string * @description Required, sets the file name for the generated files. * */ filename: string; /** * @name encapsulateModuleTypes * @type string * @default namespace * @description Configure how to encapsulate the module types, to avoid confusion. * * `namespace` (default): will wrap all types in a TypeScript namespace, using the module name. * `prefix`: will prefix all types from a specific module with the module name. * `none`: will skip encapsulation, and generate type as-is. * */ encapsulateModuleTypes: 'prefix' | 'namespace' | 'none'; /** * @name requireRootResolvers * @type boolean * @default false * @description Generate resolvers of root types (Query, Mutation and Subscription) as non-optional. * * @example * ```yaml * generates: * src/: * preset: modules * presetConfig: * baseTypesPath: types.ts * filename: types.ts * requireRootResolvers: true * plugins: * - typescript-resolvers * ``` */ requireRootResolvers?: boolean; /** * @name useGraphQLModules * @type boolean * @default true * @description By default, the generated types will generate some code specific to `graphql-modules` library. * * If you are not using GraphQL-Modules, you can disable this feature by setting this to `false`. */ useGraphQLModules?: boolean; }; ================================================ FILE: packages/presets/graphql-modules/src/index.ts ================================================ import { join, relative, resolve } from 'path'; import { normalizeImportExtension, Types } from '@graphql-codegen/plugin-helpers'; import { BaseVisitor, getConfigValue } from '@graphql-codegen/visitor-plugin-common'; import { concatAST, isScalarType } from 'graphql'; import { buildModule } from './builder.js'; import { ModulesConfig } from './config.js'; import { groupSourcesByModule, isGraphQLPrimitive, normalize, stripFilename } from './utils.js'; export const preset: Types.OutputPreset = { buildGeneratesSection: options => { const { baseOutputDir } = options; const { baseTypesPath, encapsulateModuleTypes } = options.presetConfig; const useGraphQLModules = getConfigValue(options?.presetConfig.useGraphQLModules, true); const requireRootResolvers = getConfigValue(options?.presetConfig.requireRootResolvers, false); const useTypeImports = getConfigValue(options?.config.useTypeImports, false) || false; const cwd = resolve(options.presetConfig.cwd || process.cwd()); const importTypesNamespace = options.presetConfig.importTypesNamespace || 'Types'; if (!baseTypesPath) { throw new Error( `Preset "graphql-modules" requires you to specify "baseTypesPath" configuration and point it to your base types file (generated by "typescript" plugin)!` ); } if (!options.schemaAst?.extensions.sources) { throw new Error(`Preset "graphql-modules" requires to use GraphQL SDL`); } const extensions: any = options.schemaAst!.extensions; const sourcesByModuleMap = groupSourcesByModule(extensions.extendedSources, baseOutputDir); const modules = Object.keys(sourcesByModuleMap); const baseVisitor = new BaseVisitor(options.config, {}); // One file with an output from all plugins const baseOutput: Types.GenerateOptions = { filename: resolve(cwd, baseOutputDir, baseTypesPath), schema: options.schema, documents: options.documents, plugins: [ ...options.plugins, { 'modules-exported-scalars': {}, }, ], pluginMap: { ...options.pluginMap, 'modules-exported-scalars': { plugin: schema => { const typeMap = schema.getTypeMap(); return Object.keys(typeMap) .map(t => { if (t && typeMap[t] && isScalarType(typeMap[t]) && !isGraphQLPrimitive(t)) { const convertedName = baseVisitor.convertName(t); return `export type ${convertedName} = Scalars["${t}"];`; } return null; }) .filter(Boolean) .join('\n'); }, }, }, config: { ...options.config, enumsAsTypes: true, }, schemaAst: options.schemaAst!, documentTransforms: options.documentTransforms, }; const importExtension = normalizeImportExtension({ emitLegacyCommonJSImports: options.config.emitLegacyCommonJSImports, importExtension: options.config.importExtension, }); const baseTypesFilename = baseTypesPath.replace( /\.(js|ts|d.ts)$/, // we need extension if ESM modules are used importExtension ); const baseTypesDir = stripFilename(baseOutput.filename); // One file per each module const outputs: Types.GenerateOptions[] = modules.map(moduleName => { const filename = resolve(cwd, baseOutputDir, moduleName, options.presetConfig.filename); const dirpath = stripFilename(filename); const relativePath = relative(dirpath, baseTypesDir); const importPath = options.presetConfig.importBaseTypesFrom || normalize(join(relativePath, baseTypesFilename)); const sources = sourcesByModuleMap[moduleName]; const moduleDocument = concatAST(sources.map(source => source.document)); const shouldDeclare = filename.endsWith('.d.ts'); return { filename, schema: options.schema, documents: [], plugins: [ ...options.plugins.filter(p => typeof p === 'object' && !!p.add), { 'graphql-modules-plugin': {}, }, ], pluginMap: { ...options.pluginMap, 'graphql-modules-plugin': { plugin: schema => buildModule(moduleName, moduleDocument, { importNamespace: importTypesNamespace, importPath, encapsulate: encapsulateModuleTypes || 'namespace', requireRootResolvers, shouldDeclare, schema, baseVisitor, useGraphQLModules, rootTypes: [ schema.getQueryType()?.name, schema.getMutationType()?.name, schema.getSubscriptionType()?.name, ].filter(Boolean), useTypeImports, }), }, }, config: options.config, schemaAst: options.schemaAst, documentTransforms: options.documentTransforms, }; }); return [baseOutput].concat(outputs); }, }; export default preset; ================================================ FILE: packages/presets/graphql-modules/src/utils.ts ================================================ import { Source } from '@graphql-tools/utils'; import { DefinitionNode, DocumentNode, FieldDefinitionNode, InputValueDefinitionNode, Kind, NamedTypeNode, TypeNode, } from 'graphql'; import parse from 'parse-filepath'; const sep = '/'; /** * Searches every node to collect used types */ export function collectUsedTypes(doc: DocumentNode): string[] { const used: string[] = []; for (const node of doc.definitions) { findRelated(node); } function markAsUsed(type: string) { pushUnique(used, type); } function findRelated(node: DefinitionNode | FieldDefinitionNode | InputValueDefinitionNode | NamedTypeNode) { if (node.kind === Kind.OBJECT_TYPE_DEFINITION || node.kind === Kind.OBJECT_TYPE_EXTENSION) { // Object markAsUsed(node.name.value); if (node.fields) { for (const n of node.fields) { findRelated(n); } } if (node.interfaces) { for (const n of node.interfaces) { findRelated(n); } } } else if (node.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION || node.kind === Kind.INPUT_OBJECT_TYPE_EXTENSION) { // Input markAsUsed(node.name.value); if (node.fields) { for (const n of node.fields) { findRelated(n); } } } else if (node.kind === Kind.INTERFACE_TYPE_DEFINITION || node.kind === Kind.INTERFACE_TYPE_EXTENSION) { // Interface markAsUsed(node.name.value); if (node.fields) { for (const n of node.fields) { findRelated(n); } } if (node.interfaces) { for (const n of node.interfaces) { findRelated(n); } } } else if (node.kind === Kind.UNION_TYPE_DEFINITION || node.kind === Kind.UNION_TYPE_EXTENSION) { // Union markAsUsed(node.name.value); if (node.types) { for (const n of node.types) { findRelated(n); } } } else if (node.kind === Kind.ENUM_TYPE_DEFINITION || node.kind === Kind.ENUM_TYPE_EXTENSION) { // Enum markAsUsed(node.name.value); } else if (node.kind === Kind.SCALAR_TYPE_DEFINITION || node.kind === Kind.SCALAR_TYPE_EXTENSION) { // Scalar if (!isGraphQLPrimitive(node.name.value)) { markAsUsed(node.name.value); } } else if (node.kind === Kind.INPUT_VALUE_DEFINITION) { // Argument findRelated(resolveTypeNode(node.type)); } else if (node.kind === Kind.FIELD_DEFINITION) { // Field findRelated(resolveTypeNode(node.type)); if (node.arguments) { for (const n of node.arguments) { findRelated(n); } } } else if ( node.kind === Kind.NAMED_TYPE && // Named type !isGraphQLPrimitive(node.name.value) ) { markAsUsed(node.name.value); } } return used; } export function resolveTypeNode(node: TypeNode): NamedTypeNode { if (node.kind === Kind.LIST_TYPE) { return resolveTypeNode(node.type); } if (node.kind === Kind.NON_NULL_TYPE) { return resolveTypeNode(node.type); } return node; } export function isGraphQLPrimitive(name: string): boolean { return ['String', 'Boolean', 'ID', 'Float', 'Int'].includes(name); } export function unique(val: T, i: number, all: T[]): boolean { return i === all.indexOf(val); } export function withQuotes(val: string): string { return `'${val}'`; } export function indent(size: number) { const space = new Array(size).fill(' ').join(''); function indentInner(val: string): string { return val .split('\n') .map(line => `${space}${line}`) .join('\n'); } return indentInner; } export function buildBlock({ name, lines }: { name: string; lines: string[] }): string { if (!lines.length) { return ''; } return [`${name} {`, ...lines.map(indent(2)), '};'].join('\n'); } const getRelativePath = function (filepath: string, basePath: string) { const normalizedFilepath = normalize(filepath); const normalizedBasePath = ensureStartsWithSeparator(normalize(ensureEndsWithSeparator(basePath))); const [, relativePath] = normalizedFilepath.split(normalizedBasePath); return relativePath; }; export function groupSourcesByModule(sources: Source[], basePath: string): Record { const grouped: Record = {}; for (const source of sources) { const relativePath = getRelativePath(source.location, basePath); if (relativePath) { // PERF: we could guess the module by matching source.location with a list of already resolved paths const mod = extractModuleDirectory(source.location, basePath); grouped[mod] ||= []; grouped[mod].push(source); } } return grouped; } function extractModuleDirectory(filepath: string, basePath: string): string { const relativePath = getRelativePath(filepath, basePath); const [moduleDirectory] = relativePath.split(sep); return moduleDirectory; } export function stripFilename(path: string) { const parsedPath = parse(path); return normalize(parsedPath.dir); } export function normalize(path: string) { return path.replace(/\\/g, '/'); } function ensureEndsWithSeparator(path: string) { return path.endsWith(sep) ? path : path + sep; } function ensureStartsWithSeparator(path: string) { return path.startsWith('.') ? path.replace(/^(..\/)|(.\/)/, '/') : path.startsWith('/') ? path : '/' + path; } /** * Pushes an item to a list only if the list doesn't include the item */ export function pushUnique(list: T[], item: T): void { if (!list.includes(item)) { list.push(item); } } export function concatByKey, K extends keyof T>(left: T, right: T, key: K) { // Remove duplicate, if an element is in right & left, it will be only once in the returned array. return [...new Set([...left[key], ...right[key]])]; } export function uniqueByKey, K extends keyof T>(left: T, right: T, key: K) { return left[key].filter(item => !right[key].includes(item)); } export function createObject(keys: K[], valueFn: (key: K) => T) { const obj: Record = {} as any; for (const key of keys) { obj[key] = valueFn(key); } return obj; } ================================================ FILE: packages/presets/graphql-modules/tests/__snapshots__/builder.spec.ts.snap ================================================ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`encapsulate: should wrap correctly with namespace 1`] = ` "import * as core from "../types"; import * as gm from "graphql-modules"; export namespace TestModule { interface DefinedFields { Article: 'id' | 'title' | 'text' | 'author' | 'comments' | 'url'; Query: 'articles' | 'articleById' | 'articlesByUser'; User: 'articles'; Node: 'id'; }; interface DefinedEnumValues { UserKind: 'ADMIN' | 'WRITER' | 'REGULAR'; }; interface DefinedInputFields { NewArticle: 'title' | 'text'; }; export type Article = Pick; export type User = core.User; export type Comment = core.Comment; export type Node = Pick; export type ArticleOrUser = core.ArticleOrUser; export type NewArticle = Pick; export type Query = Pick; export type UserKind = DefinedEnumValues['UserKind']; export type Scalars = Pick; export type DateTimeScalarConfig = core.DateTimeScalarConfig; export type UrlScalarConfig = core.UrlScalarConfig; export type ArticleResolvers = Pick; export type QueryResolvers = Pick; export type UserResolvers = Pick; export type NodeResolvers = Pick; export interface Resolvers { Article?: ArticleResolvers; Query?: QueryResolvers; User?: UserResolvers; DateTime?: core.Resolvers['DateTime']; URL?: core.Resolvers['URL']; }; export interface MiddlewareMap { '*'?: { '*'?: gm.Middleware[]; }; Article?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; title?: gm.Middleware[]; text?: gm.Middleware[]; author?: gm.Middleware[]; comments?: gm.Middleware[]; url?: gm.Middleware[]; }; User?: { '*'?: gm.Middleware[]; articles?: gm.Middleware[]; }; Query?: { '*'?: gm.Middleware[]; articles?: gm.Middleware[]; articleById?: gm.Middleware[]; articlesByUser?: gm.Middleware[]; }; }; }" `; exports[`encapsulate: should wrap correctly with prefix 1`] = ` "import * as core from "../types"; import * as gm from "graphql-modules"; interface DefinedFields { Article: 'id' | 'title' | 'text' | 'author' | 'comments' | 'url'; Query: 'articles' | 'articleById' | 'articlesByUser'; User: 'articles'; Node: 'id'; }; interface DefinedEnumValues { UserKind: 'ADMIN' | 'WRITER' | 'REGULAR'; }; interface DefinedInputFields { NewArticle: 'title' | 'text'; }; export type Test_Article = Pick; export type Test_User = core.User; export type Test_Comment = core.Comment; export type Test_Node = Pick; export type Test_ArticleOrUser = core.ArticleOrUser; export type Test_NewArticle = Pick; export type Test_Query = Pick; export type Test_UserKind = DefinedEnumValues['UserKind']; export type Test_Scalars = Pick; export type Test_DateTimeScalarConfig = core.DateTimeScalarConfig; export type Test_UrlScalarConfig = core.UrlScalarConfig; export type Test_ArticleResolvers = Pick; export type Test_QueryResolvers = Pick; export type Test_UserResolvers = Pick; export type Test_NodeResolvers = Pick; export interface Test_Resolvers { Article?: Test_ArticleResolvers; Query?: Test_QueryResolvers; User?: Test_UserResolvers; DateTime?: Test_core.Resolvers['DateTime']; URL?: Test_core.Resolvers['URL']; }; export interface Test_MiddlewareMap { '*'?: { '*'?: gm.Middleware[]; }; Article?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; title?: gm.Middleware[]; text?: gm.Middleware[]; author?: gm.Middleware[]; comments?: gm.Middleware[]; url?: gm.Middleware[]; }; User?: { '*'?: gm.Middleware[]; articles?: gm.Middleware[]; }; Query?: { '*'?: gm.Middleware[]; articles?: gm.Middleware[]; articleById?: gm.Middleware[]; articlesByUser?: gm.Middleware[]; }; };" `; ================================================ FILE: packages/presets/graphql-modules/tests/__snapshots__/integration.spec.ts.snap ================================================ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Integration > dotanions module should export DefinedFields, Schema Types with Picks and resolvers 1`] = ` "import * as Types from "../global-types"; import * as gm from "graphql-modules"; interface DefinedFields { Paypal: 'id' | 'url'; CreditCard: 'id' | 'cardNumber' | 'cardOwner'; Donation: 'id' | 'sender' | 'recipient' | 'amount'; Mutation: 'donate'; User: 'paymentOptions'; }; interface DefinedInputFields { DonationInput: 'user' | 'amount' | 'paymentOption'; }; export type Paypal = Pick; export type CreditCard = Pick; export type PaymentOption = Types.PaymentOption; export type User = Types.User; export type Donation = Pick; export type DonationInput = Pick; export type Mutation = Pick; export type PaypalResolvers = Pick; export type CreditCardResolvers = Pick; export type DonationResolvers = Pick; export type MutationResolvers = Pick; export type UserResolvers = Pick; export interface Resolvers { Paypal?: PaypalResolvers; CreditCard?: CreditCardResolvers; Donation?: DonationResolvers; Mutation?: MutationResolvers; User?: UserResolvers; }; export interface MiddlewareMap { '*'?: { '*'?: gm.Middleware[]; }; Paypal?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; url?: gm.Middleware[]; }; CreditCard?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; cardNumber?: gm.Middleware[]; cardOwner?: gm.Middleware[]; }; User?: { '*'?: gm.Middleware[]; paymentOptions?: gm.Middleware[]; }; Donation?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; sender?: gm.Middleware[]; recipient?: gm.Middleware[]; amount?: gm.Middleware[]; }; Mutation?: { '*'?: gm.Middleware[]; donate?: gm.Middleware[]; }; };" `; ================================================ FILE: packages/presets/graphql-modules/tests/builder.spec.ts ================================================ import '@graphql-codegen/testing'; import { BaseVisitor } from '@graphql-codegen/visitor-plugin-common'; import { parse } from 'graphql'; import { buildModule } from '../src/builder.js'; const ROOT_TYPES = ['Query']; const testDoc = parse(/* GraphQL */ ` scalar DateTime scalar URL type Article { id: ID! title: String! text: String! author: User! comments: [Comment!] url: URL! } interface Node { id: ID! } union ArticleOrUser = Article | User input NewArticle { title: String! text: String! } extend type User { articles: [Article!] } extend type Query { articles: [Article!] articleById(id: ID!): Article articlesByUser(userId: ID!): [Article!] } enum UserKind { ADMIN WRITER REGULAR } `); const baseVisitor = new BaseVisitor({}, {}); test('should generate interface field resolvers', () => { const output = buildModule( 'test', parse(/* GraphQL */ ` interface BaseUser { id: ID! email: String! } type User implements BaseUser { id: ID! email: String! } type Query { me: BaseUser! } `), { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, } ); expect(output).toContain(`BaseUser: 'id' | 'email';`); expect(output).toContain(`export type BaseUser = Pick;`); expect(output).toContain(`export type BaseUserResolvers = Pick;`); }); test('should not generate graphql-modules code when useGraphQLModules=false', () => { const output = buildModule( 'test', parse(/* GraphQL */ ` interface BaseUser { id: ID! email: String! } type User implements BaseUser { id: ID! email: String! } type Query { me: BaseUser! } `), { importPath: '../types', importNamespace: 'core', encapsulate: 'none', shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: false, requireRootResolvers: false, } ); expect(output).not.toContain(`graphql-modules`); expect(output).not.toContain(`gm.`); }); test('should generate interface extensions field resolvers ', () => { const output = buildModule( 'test', parse(/* GraphQL */ ` extend interface BaseUser { newField: String! } type Query { me: BaseUser! } `), { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, } ); expect(output).toContain(`BaseUser: 'newField';`); expect(output).toContain(`export type BaseUser = core.BaseUser`); expect(output).toContain(`export type BaseUserResolvers = Pick;`); }); test('should include import statement', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toBeSimilarStringTo(` import * as core from "../types"; `); }); test('should include import type statement', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, useTypeImports: true, }); expect(output).toBeSimilarStringTo(` import type * as core from "../types"; `); }); test('should work with naming conventions', () => { const output = buildModule('test', parse(`type query_root { test: ID! } schema { query: query_root }`), { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toContain(`Pick { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'namespace', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toBeSimilarStringTo(`export namespace TestModule {`); expect(output).toMatchSnapshot(); }); test('encapsulate: should wrap correctly with a declared namespace', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'namespace', requireRootResolvers: false, shouldDeclare: true, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toBeSimilarStringTo(`declare namespace TestModule {`); }); test('encapsulate: should wrap correctly with prefix', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'prefix', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toMatchSnapshot(); expect(output).toContain(`export type Test_Article`); expect(output).toContain(`export type Test_User`); expect(output).toContain(`export type Test_Scalars`); expect(output).toContain(`export type Test_ArticleResolvers`); expect(output).toContain(`export interface Test_Resolvers`); expect(output).toContain(`export interface Test_MiddlewareMap`); expect(output).toContain(`interface DefinedFields {`); expect(output).toContain(`interface DefinedEnumValues {`); expect(output).toContain(`interface DefinedInputFields {`); expect(output).not.toBeSimilarStringTo(`export namespace Test {`); }); test('should pick fields from defined and extended types', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toBeSimilarStringTo(` interface DefinedFields { Article: 'id' | 'title' | 'text' | 'author' | 'comments' | 'url'; Query: 'articles' | 'articleById' | 'articlesByUser'; User: 'articles'; Node: 'id'; }; `); expect(output).toBeSimilarStringTo(` interface DefinedEnumValues { UserKind: 'ADMIN' | 'WRITER' | 'REGULAR'; }; `); expect(output).toBeSimilarStringTo(` interface DefinedInputFields { NewArticle: 'title' | 'text'; }; `); }); test('should reexport used types but not defined in module', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toBeSimilarStringTo(` export type User = core.User; `); expect(output).toBeSimilarStringTo(` export type Comment = core.Comment; `); }); test('should export partial types, only those defined in module or root types', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toBeSimilarStringTo(` export type Article = Pick; `); expect(output).toBeSimilarStringTo(` export type Query = Pick; `); expect(output).toBeSimilarStringTo(` export type UserKind = DefinedEnumValues['UserKind']; `); expect(output).toBeSimilarStringTo(` export type NewArticle = Pick; `); expect(output).toBeSimilarStringTo(` export type Node = Pick; `); expect(output).toBeSimilarStringTo(` export type ArticleOrUser = core.ArticleOrUser; `); }); test('should export partial types of scalars, only those defined in module or root types', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toBeSimilarStringTo(` export type Scalars = Pick; `); // DateTime type should not be generated expect(output).not.toBeSimilarStringTo(` export type DateTime = `); }); test('should use and export resolver signatures of types defined or extended in a module', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toBeSimilarStringTo(` export type ArticleResolvers = Pick; `); expect(output).toBeSimilarStringTo(` export type QueryResolvers = Pick; `); expect(output).toBeSimilarStringTo(` export type UserResolvers = Pick; `); expect(output).toBeSimilarStringTo(` export type DateTimeScalarConfig = core.DateTimeScalarConfig; `); expect(output).toBeSimilarStringTo(` export type UrlScalarConfig = core.UrlScalarConfig; `); // Interfaces should not have resolvers // We want Object types to have __isTypeOf expect(output).toBeSimilarStringTo(` export type NodeResolvers `); // Unions should not have resolvers // We want Object types to have __isTypeOf expect(output).not.toBeSimilarStringTo(` export type ArticleOrUserResolvers `); }); test('should not generate resolver signatures of types that are not defined or extened by a module', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).not.toContain('CommentResolvers'); }); test('should generate an aggregation of individual resolver signatures', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toBeSimilarStringTo(` export interface Resolvers { Article?: ArticleResolvers; Query?: QueryResolvers; User?: UserResolvers; DateTime?: core.Resolvers['DateTime']; URL?: core.Resolvers['URL']; }; `); }); test('should generate a signature for ResolveMiddleware (with widlcards)', () => { const output = buildModule('test', testDoc, { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, }); expect(output).toContain(`import * as gm from "graphql-modules";`); expect(output).toBeSimilarStringTo(` export interface MiddlewareMap { '*'?: { '*'?: gm.Middleware[]; }; Article?: { '*'?: gm.Middleware[]; id?: gm.Middleware[]; title?: gm.Middleware[]; text?: gm.Middleware[]; author?: gm.Middleware[]; comments?: gm.Middleware[]; url?: gm.Middleware[]; }; User?: { '*'?: gm.Middleware[]; articles?: gm.Middleware[]; }; Query?: { '*'?: gm.Middleware[]; articles?: gm.Middleware[]; articleById?: gm.Middleware[]; articlesByUser?: gm.Middleware[]; }; }; `); }); test('only picks __isTypeOf from implementing types (of Interfaces) and union members', () => { const output = buildModule( 'test', parse(/* GraphQL */ ` type Query { me: User pet: Pet offer: Offer } type User { id: ID! username: String! } interface Pet { id: ID! name: String! } type Cat implements Pet { id: ID! name: String! canScratch: Boolean! } type Dog implements Pet { id: ID! name: String! canBark: Boolean! } type Elephant { id: ID! } extend type Elephant implements Pet { name: String! hasTrunk: Boolean! } union Offer = Discount | Coupon type Discount { id: ID! name: String! } type Coupon { id: ID! name: String! } `), { importPath: '../types', importNamespace: 'core', encapsulate: 'none', requireRootResolvers: false, shouldDeclare: false, rootTypes: ROOT_TYPES, baseVisitor, useGraphQLModules: true, } ); // User does not pick `__isTypeOf` because it is not a union member, or implementing types expect(output).toBeSimilarStringTo(` export type UserResolvers = Pick; `); // Cat picks `__isTypeOf` because it is an implementing type of Pet expect(output).toBeSimilarStringTo(` export type CatResolvers = Pick; `); // Dog picks `__isTypeOf` because it is an implementing type of Pet expect(output).toBeSimilarStringTo(` export type DogResolvers = Pick; `); // Elephant picks `__isTypeOf` because it is an implementing type of Pet, via `extend type ` expect(output).toBeSimilarStringTo(` export type ElephantResolvers = Pick; `); // Discount picks `__isTypeOf` because it is a union member expect(output).toBeSimilarStringTo(` export type DiscountResolvers = Pick; `); // Coupon picks `__isTypeOf` because it is a union member expect(output).toBeSimilarStringTo(` export type CouponResolvers = Pick; `); }); ================================================ FILE: packages/presets/graphql-modules/tests/integration.spec.ts ================================================ import '@graphql-codegen/testing'; import { normalize } from 'path'; import { executeCodegen } from '@graphql-codegen/cli'; const options = { generates: { './tests/test-files/modules': { schema: './tests/test-files/modules/*/types/*.graphql', plugins: ['typescript', 'typescript-resolvers'], preset: 'graphql-modules' as const, presetConfig: { baseTypesPath: 'global-types.ts', filename: 'module-types.ts', encapsulateModuleTypes: 'none', }, }, }, }; describe('Integration', () => { // In this test, we make sure executeCodegen passes on a list of Sources as an extension // This is very important test('should generate a base output and 4 for modules', async () => { const { result } = await executeCodegen(options); expect(result.length).toBe(5); expect(normalize(result[0].filename)).toMatch(normalize(`/modules/global-types.ts`)); expect(normalize(result[1].filename)).toMatch(normalize(`/modules/blog/module-types.ts`)); expect(normalize(result[2].filename)).toMatch(normalize(`/modules/common/module-types.ts`)); expect(normalize(result[3].filename)).toMatch(normalize(`/modules/dotanions/module-types.ts`)); expect(normalize(result[4].filename)).toMatch(normalize(`/modules/users/module-types.ts`)); }); test('should not duplicate type even if type and extend type are in the same module', async () => { const { result } = await executeCodegen(options); const userResolversStr = `export type UserResolvers = Pick;`; const nbOfTimeUserResolverFound = result[4].content.split(userResolversStr).length - 1; expect(nbOfTimeUserResolverFound).toBe(1); }); test('should allow to override importBaseTypesFrom correctly', async () => { const { result } = await executeCodegen({ generates: { './tests/test-files/modules': { schema: './tests/test-files/modules/*/types/*.graphql', plugins: ['typescript', 'typescript-resolvers'], preset: 'graphql-modules', presetConfig: { importBaseTypesFrom: '@types', baseTypesPath: 'global-types.ts', filename: 'module-types.ts', encapsulateModuleTypes: 'none', }, }, }, }); const importStatement = `import * as Types from "@types";`; expect(result.length).toBe(5); expect(result[1].content).toMatch(importStatement); expect(result[2].content).toMatch(importStatement); expect(result[3].content).toMatch(importStatement); expect(result[4].content).toMatch(importStatement); }); test('should import with respect of useTypeImports config correctly', async () => { const { result } = await executeCodegen({ generates: { './tests/test-files/modules': { schema: './tests/test-files/modules/*/types/*.graphql', plugins: ['typescript', 'typescript-resolvers'], preset: 'graphql-modules', presetConfig: { importBaseTypesFrom: '@types', baseTypesPath: 'global-types.ts', filename: 'module-types.ts', encapsulateModuleTypes: 'none', }, }, }, config: { useTypeImports: true, }, }); const importStatement = `import type * as Types from "@types";`; expect(result.length).toBe(5); expect(result[1].content).toMatch(importStatement); expect(result[2].content).toMatch(importStatement); expect(result[3].content).toMatch(importStatement); expect(result[4].content).toMatch(importStatement); }); test('should allow to disable graphql-modules', async () => { const { result } = await executeCodegen({ generates: { './tests/test-files/modules': { schema: './tests/test-files/modules/*/types/*.graphql', plugins: ['typescript', 'typescript-resolvers'], preset: 'graphql-modules', presetConfig: { importBaseTypesFrom: '@types', baseTypesPath: 'global-types.ts', filename: 'module-types.ts', encapsulateModuleTypes: 'none', useGraphQLModules: false, }, }, }, }); for (const record of result) { expect(record).not.toContain(`graphql-modules`); expect(record).not.toContain(`gm.`); } }); test('each module-types should include a relative import to glob-types module', async () => { const { result } = await executeCodegen(options); const importStatement = `import * as Types from "../global-types";`; expect(result.length).toBe(5); expect(result[1].content).toMatch(importStatement); expect(result[2].content).toMatch(importStatement); expect(result[3].content).toMatch(importStatement); expect(result[4].content).toMatch(importStatement); }); test('each module-types should export Resolvers', async () => { const { result } = await executeCodegen(options); const exportStatemment = `export interface Resolvers `; expect(result.length).toBe(5); expect(result[1].content).toMatch(exportStatemment); expect(result[2].content).toMatch(exportStatemment); expect(result[3].content).toMatch(exportStatemment); expect(result[4].content).toMatch(exportStatemment); }); test('dotanions module should export DefinedFields, Schema Types with Picks and resolvers', async () => { const { result } = await executeCodegen(options); expect(result.length).toBe(5); expect(result[3].content).toMatchSnapshot(); }); test('should NOT produce required root-level resolvers in Resolvers interface by default', async () => { const { result } = await executeCodegen(options); const usersModuleOutput = result.find(o => o.filename.includes('users'))!; expect(usersModuleOutput).toBeDefined(); expect(usersModuleOutput.content).toContain( `export type QueryResolvers = Pick;` ); expect(usersModuleOutput.content).toContain('Query?: QueryResolvers;'); }); test('should produce required root-level resolvers in Resolvers interface when requireRootResolvers flag is enabled', async () => { const optionsCopy = Object.assign({} as any, options); optionsCopy.generates['./tests/test-files/modules'].presetConfig = { ...optionsCopy.generates['./tests/test-files/modules'].presetConfig, requireRootResolvers: true, useGraphQLModules: false, }; const { result } = await executeCodegen(optionsCopy); const usersModuleOutput = result.find(o => o.filename.includes('users'))!; expect(usersModuleOutput).toBeDefined(); // Only Query related properties should be required expect(usersModuleOutput.content).toBeSimilarStringTo(` export type UserResolvers = Pick; export type QueryResolvers = Required>; `); expect(usersModuleOutput.content).toBeSimilarStringTo(` export interface Resolvers { User?: UserResolvers; Query: QueryResolvers; }; `); }); test('import paths for ESM should have correct extension', async () => { const emitLegacyCommonJSImports = { ...options, emitLegacyCommonJSImports: false, }; const { result } = await executeCodegen(emitLegacyCommonJSImports); const esmImportStatement = `import * as Types from "../global-types.js";`; expect(result.length).toBe(5); expect(result[1].content).toMatch(esmImportStatement); expect(result[2].content).toMatch(esmImportStatement); expect(result[3].content).toMatch(esmImportStatement); expect(result[4].content).toMatch(esmImportStatement); }); test('import paths should use importExtension when set to .mjs', async () => { const withImportExtension = { ...options, importExtension: '.mjs' as const, }; const { result } = await executeCodegen(withImportExtension); const importStatement = `import * as Types from "../global-types.mjs";`; expect(result.length).toBe(5); expect(result[1].content).toMatch(importStatement); expect(result[2].content).toMatch(importStatement); expect(result[3].content).toMatch(importStatement); expect(result[4].content).toMatch(importStatement); }); test('import paths should use importExtension when set to empty string', async () => { const withImportExtension = { ...options, importExtension: '' as const, }; const { result } = await executeCodegen(withImportExtension); const importStatement = `import * as Types from "../global-types";`; expect(result.length).toBe(5); expect(result[1].content).toMatch(importStatement); expect(result[2].content).toMatch(importStatement); expect(result[3].content).toMatch(importStatement); expect(result[4].content).toMatch(importStatement); }); test('importExtension should override emitLegacyCommonJSImports', async () => { const withBothOptions = { ...options, importExtension: '.mjs' as const, emitLegacyCommonJSImports: false, }; const { result } = await executeCodegen(withBothOptions); const importStatement = `import * as Types from "../global-types.mjs";`; expect(result.length).toBe(5); // Should use .mjs from importExtension, not .js from emitLegacyCommonJSImports expect(result[1].content).toMatch(importStatement); expect(result[2].content).toMatch(importStatement); expect(result[3].content).toMatch(importStatement); expect(result[4].content).toMatch(importStatement); }); test('importExtension set to empty string should override emitLegacyCommonJSImports: false', async () => { const withBothOptions = { ...options, importExtension: '' as const, emitLegacyCommonJSImports: false, }; const { result } = await executeCodegen(withBothOptions); const importStatement = `import * as Types from "../global-types";`; expect(result.length).toBe(5); // Should use empty string from importExtension, not .js from emitLegacyCommonJSImports expect(result[1].content).toMatch(importStatement); expect(result[2].content).toMatch(importStatement); expect(result[3].content).toMatch(importStatement); expect(result[4].content).toMatch(importStatement); }); }); ================================================ FILE: packages/presets/graphql-modules/tests/test-files/modules/blog/types/blog.graphql ================================================ type Article { id: ID! title: String! text: String! author: User! } extend type Query { articles: [Article!] articleById(id: ID!): Article articlesByUser(userId: ID!): [Article!] } ================================================ FILE: packages/presets/graphql-modules/tests/test-files/modules/common/types/common.graphql ================================================ type Query { ping: Int } type Mutation { pong: Int } ================================================ FILE: packages/presets/graphql-modules/tests/test-files/modules/dotanions/types/donations.graphql ================================================ type Paypal { id: ID! url: String! } type CreditCard { id: ID! cardNumber: Int! cardOwner: String! } union PaymentOption = Paypal | CreditCard extend type User { paymentOptions: [PaymentOption!] } type Donation { id: ID! sender: User! recipient: User! amount: Float! } input DonationInput { user: ID! amount: Float! paymentOption: ID! } extend type Mutation { donate(donation: DonationInput): Donation } ================================================ FILE: packages/presets/graphql-modules/tests/test-files/modules/users/types/ext_user.graphql ================================================ extend type User { age: Int } ================================================ FILE: packages/presets/graphql-modules/tests/test-files/modules/users/types/users.graphql ================================================ type User { id: ID! firstName: String! lastName: String! } extend type Query { users: [User!] userById(id: ID!): User } ================================================ FILE: packages/presets/graphql-modules/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'graphql-modules-preset', setupFiles: './vitest.setup.ts', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/presets/graphql-modules/vitest.setup.ts ================================================ import { vi } from 'vitest'; vi.spyOn(process, 'cwd').mockImplementation(() => __dirname); ================================================ FILE: packages/presets/swc-plugin/.gitignore ================================================ /target ^target/ target swc_plugin.wasm *.wasm ================================================ FILE: packages/presets/swc-plugin/Cargo.toml ================================================ [package] name = "swc-plugin" version = "0.2.0" edition = "2021" description = "SWC plugin for https://the-guild.dev/graphql/codegen/plugins/presets/preset-client" license = "MIT" publish = false [lib] crate-type = ["cdylib"] [profile.release] # This removes more dead code codegen-units = 1 lto = true # Optimize for size opt-level = "s" # Optimize for performance, this is default so you don't need to specify it # opt-level = "z" # Strip debug symbols strip = "symbols" [dependencies] graphql-parser = "0.4.0" pathdiff = "0.2.1" serde = "1" serde_json = "1.0.105" swc_core = { version = "0.109.*", features = ["ecma_plugin_transform", "ecma_visit", "ecma_utils", "ecma_parser", "common", "testing" ] } # .cargo/config defines few alias to build plugin. # cargo build-wasi generates wasm-wasi32 binary # cargo build-wasm32 generates wasm32-unknown-unknown binary. ================================================ FILE: packages/presets/swc-plugin/README.md ================================================ # `@graphql-codegen/client-preset-swc-plugin` When using the [`@graphql-codegen/client-preset`](https://the-guild.dev/graphql/codegen/plugins/presets/preset-client) on large scale projects might want to enable code splitting or tree shaking on the `client-preset` generated files. This is because instead of using the map which contains all GraphQL operations in the project, we can use the specific generated document types. This plugin works for [SWC](https://swc.rs) only. ### Installation ```bash yarn add -D @graphql-codegen/client-preset-swc-plugin ``` ### Usage You will need to provide the `artifactDirectory` path that should be the same as the one configured in your `codegen.ts` #### Vite ```ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react-swc' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ react({ plugins: [ ['@graphql-codegen/client-preset-swc-plugin', { artifactDirectory: './src/gql', gqlTagName: 'graphql' }] ] }) ] }) ``` #### Next.js ```ts const nextConfig = { // ... experimental: { swcPlugins: [ ['@graphql-codegen/client-preset-swc-plugin', { artifactDirectory: './src/gql', gqlTagName: 'graphql' }] ] } } ``` #### `.swcrc` ```json5 { // ... jsc: { // ... experimental: { plugins: [ ['@graphql-codegen/client-preset-swc-plugin', { artifactDirectory: './src/gql', gqlTagName: 'graphql' }] ] } } } ``` ### Release To publish a new version ensure you have done the following: - Update the version in `package.json` - Update the `CHANGELOG.md` with the new version and changes - Commit the changes - From GitHub Actions, run the `Rust plugin` workflow ================================================ FILE: packages/presets/swc-plugin/package.json ================================================ { "name": "@graphql-codegen/client-preset-swc-plugin", "version": "0.2.0", "description": "A SWC plugin for https://the-guild.dev/graphql/codegen/plugins/presets/preset-client", "license": "MIT", "bob": false, "keywords": [ "swc-plugin", "graphql-codegen", "preset-client" ], "main": "swc_plugin.wasm", "scripts": { "build-wasm": "cargo build --target wasm32-wasi --release && cp target/wasm32-wasi/release/swc_plugin.wasm ./", "debug": "cargo build --target wasm32-wasi && cp target/wasm32-wasi/debug/swc_plugin.wasm ./" }, "homepage": "https://the-guild.dev/graphql/codegen/plugins/presets/preset-client", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/presets/client/swc-plugin" }, "bugs": { "url": "https://github.com/dotansimha/graphql-code-generator/issues" }, "files": [ "swc_plugin.wasm" ], "type": "module", "engines": { "node": ">=16" } } ================================================ FILE: packages/presets/swc-plugin/src/lib.rs ================================================ use graphql_parser::query::parse_query; use pathdiff::diff_paths; use serde::Deserialize; use std::path::{Path, PathBuf}; use swc_core::{ common::Span, ecma::{ ast::*, utils::quote_ident, visit::{as_folder, FoldWith, VisitMut, VisitMutWith}, }, plugin::{ errors::HANDLER, metadata::TransformPluginMetadataContextKind, plugin_transform, proxies::TransformPluginProgramMetadata, }, }; fn capetalize(s: &str) -> String { format!("{}{}", (&s[..1].to_string()).to_uppercase(), &s[1..]) } #[cfg(test)] mod tests; pub struct GraphQLCodegenOptions { pub filename: String, pub cwd: String, pub artifact_directory: String, pub gql_tag_name: String, } pub struct GraphQLVisitor { options: GraphQLCodegenOptions, graphql_operations_or_fragments_to_import: Vec, } impl GraphQLVisitor { pub fn new(options: GraphQLCodegenOptions) -> Self { GraphQLVisitor { options, graphql_operations_or_fragments_to_import: Vec::new(), } } fn handle_error(&self, details: &str, span: Span) { let message = format!( "@graphql-codegen/client-preset-swc-plugin details: {}", details ); HANDLER.with(|handler| handler.struct_span_err(span, &message).emit()); } fn get_relative_import_path(&self, path_end: &str) -> String { // using PathBuf to add the relative path to the artifact directory let mut file_full_path = PathBuf::from(&self.options.cwd); file_full_path.push(&self.options.filename); let file_s_dirname = file_full_path.parent().unwrap(); // The resolved artifact directory as seen from the current running SWC plugin working directory let resolved_artifact_directory = if Path::new(&self.options.artifact_directory).is_relative() { let mut cwd = PathBuf::from(&self.options.cwd); cwd.push(&self.options.artifact_directory); cwd.to_string_lossy().to_string() } else { self.options.artifact_directory.to_string() }; let mut relative = diff_paths(resolved_artifact_directory, file_s_dirname).unwrap(); let start_of_path = "./"; // e.g. add 'graphql' to relative path relative.push(path_end); let platform_specific_path = start_of_path.to_string() + relative.to_str().unwrap(); platform_specific_path.replace('\\', "/") } } pub fn create_graphql_codegen_visitor(options: GraphQLCodegenOptions) -> impl VisitMut { GraphQLVisitor::new(options) } impl VisitMut for GraphQLVisitor { fn visit_mut_var_decl(&mut self, e: &mut VarDecl) { e.visit_mut_children_with(self); for decl in e.decls.iter_mut() { if let Some(init) = &mut decl.init { if let Expr::Call(CallExpr { callee, args, .. }) = &mut **init { if args.is_empty() { return; } match callee.as_expr() { Some(expr_box) => match &**expr_box { Expr::Ident(ident) => { if &ident.sym != self.options.gql_tag_name.as_str() { return; } } _ => return, }, _ => return, } let quasis = match &*args[0].expr { Expr::Tpl(tpl) => &tpl.quasis, _ => return, }; let raw = match &quasis[0].cooked { Some(cooked) => cooked, None => return, }; let graphql_ast = match parse_query::<&str>(raw) { Ok(ast) => ast, Err(e) => { // Currently the parser outputs a string like: "query parse error", so we add "GraphQL" to the beginning let error = format!("GraphQL {}", e); self.handle_error(error.as_str(), quasis[0].span); return; } }; let first_definition = match graphql_ast.definitions.get(0) { Some(definition) => definition, None => return, }; let operation_name = match first_definition { graphql_parser::query::Definition::Fragment(fragment) => { fragment.name.to_string() + "FragmentDoc" } graphql_parser::query::Definition::Operation(op) => match op { graphql_parser::query::OperationDefinition::Query(query) => { match query.name { Some(name) => name.to_string() + "Document", None => return, } } graphql_parser::query::OperationDefinition::Mutation(mutation) => { match mutation.name { Some(name) => name.to_string() + "Document", None => return, } } graphql_parser::query::OperationDefinition::Subscription( subscription, ) => match subscription.name { Some(name) => name.to_string() + "Document", None => return, }, _ => return, }, }; self.graphql_operations_or_fragments_to_import .push(capetalize(&operation_name)); // now change the call expression to a Identifier let new_expr = Expr::Ident(quote_ident!(capetalize(&operation_name))); *init = Box::new(new_expr); } } } } fn visit_mut_module(&mut self, module: &mut Module) { // First visit all its children, collect the GraphQL document names, and then add the necessary imports module.visit_mut_children_with(self); if self.graphql_operations_or_fragments_to_import.is_empty() { return; } let platform_specific_path = self.get_relative_import_path("graphql"); for operation_or_fragment_name in &self.graphql_operations_or_fragments_to_import { module.body.insert( 0, ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { span: Default::default(), specifiers: vec![ImportSpecifier::Named(ImportNamedSpecifier { span: Default::default(), local: quote_ident!(operation_or_fragment_name.to_string()), imported: None, is_type_only: false, })], src: Box::new(Str::from(platform_specific_path.to_string())), type_only: false, asserts: None, })), ) } } } fn gql_default() -> String { "gql".to_string() } #[allow(non_snake_case)] #[derive(Deserialize)] struct PluginOptions { artifactDirectory: String, #[serde(default = "gql_default")] gqlTagName: String, } #[plugin_transform] pub fn process_transform(program: Program, metadata: TransformPluginProgramMetadata) -> Program { let filename = metadata .get_context(&TransformPluginMetadataContextKind::Filename) .unwrap_or_default(); let cwd = metadata .get_context(&TransformPluginMetadataContextKind::Cwd) .unwrap_or_default(); let plugin_config: PluginOptions = serde_json::from_str( &metadata .get_transform_plugin_config() .expect("Failed to get plugin config for @graphql-codegen/client-preset-swc-plugin"), ) .expect("Invalid configuration for @graphql-codegen/client-preset-swc-plugin"); let artifact_directory = plugin_config.artifactDirectory; if artifact_directory.is_empty() { panic!("artifactDirectory is not present in the config for @graphql-codegen/client-preset-swc-plugin"); } let visitor = create_graphql_codegen_visitor(GraphQLCodegenOptions { filename, cwd, artifact_directory, gql_tag_name: plugin_config.gqlTagName, }); program.fold_with(&mut as_folder(visitor)) } ================================================ FILE: packages/presets/swc-plugin/src/tests.rs ================================================ use std::path::PathBuf; use swc_core::{ ecma::{ parser::{Syntax, TsConfig}, transforms::testing::{test, test_fixture}, visit::as_folder, }, testing, }; use super::*; fn get_test_code_visitor() -> GraphQLVisitor { GraphQLVisitor::new(GraphQLCodegenOptions { filename: "test.ts".to_string(), cwd: "/home/faketestproject".to_string(), artifact_directory: "./src/gql".to_string(), gql_tag_name: "gql".to_string(), }) } #[testing::fixture("tests/fixtures/simple-uppercase-operation-name.ts")] fn import_files_from_same_directory(input_path: PathBuf) { let cwd = std::env::current_dir().unwrap(); let relative_file_path = diff_paths(&input_path, &cwd).unwrap(); let output_path = input_path.with_extension("js"); test_fixture( Syntax::Typescript(TsConfig { tsx: input_path.to_string_lossy().ends_with(".tsx"), ..Default::default() }), &|_metadata| { as_folder(GraphQLVisitor::new(GraphQLCodegenOptions { filename: relative_file_path.to_string_lossy().to_string(), cwd: cwd.to_string_lossy().to_string(), artifact_directory: "./tests/fixtures".to_string(), gql_tag_name: "gql".to_string(), })) }, &input_path, &output_path, Default::default(), ); } #[testing::fixture("tests/fixtures/simple-uppercase-operation-name.ts")] fn import_files_from_other_directory(input_path: PathBuf) { // Let's do the same test as for the babel plugin, assume we are in the tests folder let mut cwd = std::env::current_dir().unwrap(); cwd.push("tests"); let relative_file_path = diff_paths(&input_path, &cwd).unwrap(); let output_path = input_path.with_extension("other-dir.js"); test_fixture( Syntax::Typescript(TsConfig { tsx: input_path.to_string_lossy().ends_with(".tsx"), ..Default::default() }), &|_metadata| { as_folder(GraphQLVisitor::new(GraphQLCodegenOptions { filename: relative_file_path.to_string_lossy().to_string(), cwd: cwd.to_string_lossy().to_string(), artifact_directory: cwd.to_string_lossy().to_string(), gql_tag_name: "gql".to_string(), })) }, &input_path, &output_path, Default::default(), ); } test!( Default::default(), |_| as_folder(get_test_code_visitor()), expect_normal_declarations_to_not_panic_and_to_be_ignored, // Example from Next.js' server.js r#"const emitter = (0, _mitt).default(); const looseToArray = (input)=>[].slice.call(input); const targetTag = document.querySelector(`style[data-n-href="${href}"]`);"#, r#"const emitter = (0, _mitt).default(); const looseToArray = (input)=>[].slice.call(input); const targetTag = document.querySelector(`style[data-n-href="${href}"]`);"# ); ================================================ FILE: packages/presets/swc-plugin/tests/fixtures/simple-uppercase-operation-name.js ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import { CFragmentDoc } from "./graphql"; import { BDocument } from "./graphql"; import { ADocument } from "./graphql"; import gql from "gql-tag"; //@ts-ignore const A = ADocument; //@ts-ignore const B = BDocument; //@ts-ignore const C = CFragmentDoc; ================================================ FILE: packages/presets/swc-plugin/tests/fixtures/simple-uppercase-operation-name.other-dir.js ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import { CFragmentDoc } from "./../graphql"; import { BDocument } from "./../graphql"; import { ADocument } from "./../graphql"; import gql from "gql-tag"; //@ts-ignore const A = ADocument; //@ts-ignore const B = BDocument; //@ts-ignore const C = CFragmentDoc; ================================================ FILE: packages/presets/swc-plugin/tests/fixtures/simple-uppercase-operation-name.ts ================================================ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-ignore import gql from "gql-tag"; //@ts-ignore const A = gql(/* GraphQL */ ` query A { a } `); //@ts-ignore const B = gql(/* GraphQL */ ` query B { b } `); //@ts-ignore const C = gql(/* GraphQL */ ` fragment C on Query { c } `); ================================================ FILE: packages/utils/graphql-codegen-testing/CHANGELOG.md ================================================ # @graphql-codegen/testing ## 4.0.4 ### Patch Changes - [#10622](https://github.com/dotansimha/graphql-code-generator/pull/10622) [`369b2c1`](https://github.com/dotansimha/graphql-code-generator/commit/369b2c1934a74a3ca7f49d8972608f5ec341d17b) Thanks [@eddeee888](https://github.com/eddeee888)! - Force publish to fix failed publish 4.0.2 ## 4.0.2 ### Patch Changes - [#10614](https://github.com/dotansimha/graphql-code-generator/pull/10614) [`4780d57`](https://github.com/dotansimha/graphql-code-generator/commit/4780d57377392da71e3665f7b8cffe7cbcb98309) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix usage issue due to ESM/CJS incompatibility ## 4.0.1 ### Patch Changes - [#10313](https://github.com/dotansimha/graphql-code-generator/pull/10313) [`ace5c41`](https://github.com/dotansimha/graphql-code-generator/commit/ace5c4176ce4bc8328d3066a8111ca8ce3a34ca6) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`jest-diff@^23.0.0 || ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 || ^30.0.0` ↗︎](https://www.npmjs.com/package/jest-diff/v/23.0.0) (from `^23.0.0 || ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0`, in `peerDependencies`) ## 4.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Bump depdendencies major versions: - nock v14 - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Patch Changes - Updated dependencies [[`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2), [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2)]: - @graphql-codegen/plugin-helpers@6.0.0 ## 3.0.4 ### Patch Changes - [#10070](https://github.com/dotansimha/graphql-code-generator/pull/10070) [`5fb302c`](https://github.com/dotansimha/graphql-code-generator/commit/5fb302c9ee8fc7af01c03e63a1c33ea1997fca16) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`nock@13.5.4` ↗︎](https://www.npmjs.com/package/nock/v/13.5.4) (from `13.5.3`, in `dependencies`) ## 3.0.3 ### Patch Changes - [#9627](https://github.com/dotansimha/graphql-code-generator/pull/9627) [`422e2a7`](https://github.com/dotansimha/graphql-code-generator/commit/422e2a78f4ebe158e5e4a5f3248e0d03e88b69d6) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`nock@13.3.6` ↗︎](https://www.npmjs.com/package/nock/v/13.3.6) (from `13.3.1`, in `dependencies`) - [#9851](https://github.com/dotansimha/graphql-code-generator/pull/9851) [`217ed56`](https://github.com/dotansimha/graphql-code-generator/commit/217ed565a2f722f76ce90a3ce5d14117d3e9993f) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`nock@13.5.3` ↗︎](https://www.npmjs.com/package/nock/v/13.5.3) (from `13.3.6`, in `dependencies`) ## 3.0.2 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release - Updated dependencies [[`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653)]: - @graphql-codegen/plugin-helpers@5.0.3 ## 3.0.1 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`jest-diff@^23.0.0 || ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0` ↗︎](https://www.npmjs.com/package/jest-diff/v/23.0.0) (from `^23.0.0 || ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0`, in `peerDependencies`) - Updated dependencies [[`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975)]: - @graphql-codegen/plugin-helpers@5.0.2 ## 3.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - [#9407](https://github.com/dotansimha/graphql-code-generator/pull/9407) [`bec804225`](https://github.com/dotansimha/graphql-code-generator/commit/bec8042256e1718e7867b9d5c038eb7d22e72774) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`nock@13.3.1` ↗︎](https://www.npmjs.com/package/nock/v/13.3.1) (from `13.3.0`, in `dependencies`) - Updated dependencies [[`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2), [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2), [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4), [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0)]: - @graphql-codegen/plugin-helpers@5.0.0 ## 2.0.2 ### Patch Changes - [#9228](https://github.com/dotansimha/graphql-code-generator/pull/9228) [`a5ec5af36`](https://github.com/dotansimha/graphql-code-generator/commit/a5ec5af36cd77f4ec86773a899aa5ebd16d4ff9f) Thanks [@eddeee888](https://github.com/eddeee888)! - Add complex test cases for resolvers tests - Updated dependencies [[`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29), [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087)]: - @graphql-codegen/plugin-helpers@4.2.0 ## 2.0.1 ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) - Updated dependencies [[`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491), [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c), [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15)]: - @graphql-codegen/plugin-helpers@4.1.0 ## 2.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - Updated dependencies [[`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5), [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d)]: - @graphql-codegen/plugin-helpers@4.0.0 ## 1.18.3 ### Patch Changes - [#8836](https://github.com/dotansimha/graphql-code-generator/pull/8836) [`4fa0a566e`](https://github.com/dotansimha/graphql-code-generator/commit/4fa0a566e1b5253c303ea2a4b5cbbf7c12ca3677) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`nock@13.3.0` ↗︎](https://www.npmjs.com/package/nock/v/13.3.0) (from `13.2.9`, in `dependencies`) ## 1.18.2 ### Patch Changes - [`46f75304a`](https://github.com/dotansimha/graphql-code-generator/commit/46f75304a69a13e8b5f58303f65c81b30a2ad96a) Thanks [@saihaj](https://github.com/saihaj)! - fix the version of `@graphql-codegen/plugin-helpers@3.1.1` - Updated dependencies [[`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81)]: - @graphql-codegen/plugin-helpers@3.1.1 ## 1.18.1 ### Patch Changes - Updated dependencies [[`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22), [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482), [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84)]: - @graphql-codegen/plugin-helpers@3.0.0 ## 1.18.0 ### Minor Changes - [#8556](https://github.com/dotansimha/graphql-code-generator/pull/8556) [`64e553c3f`](https://github.com/dotansimha/graphql-code-generator/commit/64e553c3f62618a2aedf122d292e2700fd93d6e1) Thanks [@charlypoly](https://github.com/charlypoly)! - `mockGraphQLServer`, resolvers common testing helpers and fixtures, typing updates ================================================ FILE: packages/utils/graphql-codegen-testing/package.json ================================================ { "name": "@graphql-codegen/testing", "version": "4.0.4", "description": "GraphQL Codegen Testing Utils", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "scripts": { "lint": "eslint **/*.ts" }, "repository": "git@github.com:dotansimha/graphql-code-generator.git", "author": "Dotan Simha ", "license": "MIT", "bugs": { "url": "https://github.com/dotansimha/graphql-code-generator/issues" }, "homepage": "https://github.com/dotansimha/graphql-code-generator#readme", "peerDependencies": { "jest-diff": "^23.0.0 || ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 || ^30.0.0", "typescript": ">=3.0.0" }, "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", "common-tags": "^1.8.0", "lz-string": "^1.4.4", "graphql-helix": "1.13.0", "nock": "^14.0.0", "tslib": "~2.6.0" }, "devDependencies": { "@types/lz-string": "1.3.34" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "bob": { "check": false }, "engines": { "node": ">=16" } } ================================================ FILE: packages/utils/graphql-codegen-testing/src/index.ts ================================================ import { expect } from 'vitest'; import { oneLine, stripIndent } from 'common-tags'; import { diff } from 'jest-diff'; interface CustomMatchers { /** * Normalizes whitespace and performs string comparisons */ toBeSimilarStringTo(expected: string): R; } declare module 'vitest' { // eslint-disable-next-line @typescript-eslint/no-empty-object-type interface Matchers extends CustomMatchers {} } function compareStrings(a: string, b: string): boolean { return a.includes(b); } /** Ignore whitespace, trailing commas, and leading pipes */ function similarize(str: string): string { return ( oneLine`${str}` // Trim trailing commas .replace(/\s*,(\s*[)}])/g, '$1') // Remove leading pipes .replace(/([<:,=(])\s*(?:\|\s*)?/g, '$1') // Remove spaces around brackets and semicolons .replace(/\s*([[\](){}<>;])\s*/g, '$1') // Replace multiple spaces with a single space .replace(/\s\s+/g, ' ') ); } expect.extend({ toBeSimilarStringTo(received: string, expected: string) { const strippedReceived = similarize(received); const strippedExpected = similarize(expected); if (compareStrings(strippedReceived, strippedExpected)) { return { message: () => `expected ${received} not to be a string containing (ignoring indents) ${expected}`, pass: true, }; } const diffString = diff(stripIndent`${expected}`, stripIndent`${received}`, { expand: this.expand, }); const hasExpect = diffString?.includes('- Expect'); const message = hasExpect ? `Difference:\n\n${diffString}` : `expected ${received} to be a string containing (ignoring indents) ${expected}`; return { message: () => message, pass: false, }; }, }); export * from './mock-graphql-server.js'; export * from './resolvers-common.js'; export * from './typescript.js'; ================================================ FILE: packages/utils/graphql-codegen-testing/src/mock-graphql-server.ts ================================================ import { GraphQLSchema } from 'graphql'; import { getGraphQLParameters, processRequest as processGraphQLHelixRequest } from 'graphql-helix'; import nock from 'nock'; export function mockGraphQLServer({ schema, host, path, intercept, method = 'POST', }: { schema: GraphQLSchema; host: string; path: string | RegExp | ((path: string) => boolean); intercept?: (obj: nock.ReplyFnContext) => void; method?: string; }) { const handler = async function (this: nock.ReplyFnContext, uri: string, body: any) { if (intercept) { intercept(this); } const uriObj = new URL(host + uri); const queryObj: any = {}; for (const [key, val] of uriObj.searchParams.entries()) { queryObj[key] = val; } // Create a generic Request object that can be consumed by Graphql Helix's API const request = { body, headers: this.req.headers, method, query: queryObj, }; // Extract the GraphQL parameters from the request const { operationName, query, variables } = getGraphQLParameters(request); // Validate and execute the query const result = await processGraphQLHelixRequest({ operationName, query, variables, request, schema, }); // processRequest returns one of three types of results depending on how the server should respond // 1) RESPONSE: a regular JSON payload // 2) MULTIPART RESPONSE: a multipart response (when @stream or @defer directives are used) // 3) PUSH: a stream of events to push back down the client for a subscription if (result.type === 'RESPONSE') { const headers = {}; // We set the provided status and headers and just the send the payload back to the client for (const { name, value } of result.headers) { headers[name] = value; } return [result.status, result.payload, headers]; } return [500, 'Not implemented']; }; switch (method) { case 'GET': return nock(host).get(path).reply(handler); case 'POST': return nock(host).post(path).reply(handler); } return null; } ================================================ FILE: packages/utils/graphql-codegen-testing/src/resolvers-common.ts ================================================ import { mergeOutputs, Types } from '@graphql-codegen/plugin-helpers'; import { validateTs } from '@graphql-codegen/testing'; import { plugin as tsPlugin } from '@graphql-codegen/typescript'; import { buildSchema } from 'graphql'; export const resolversTestingSchema = buildSchema(/* GraphQL */ ` type MyType { foo: String! @authenticated otherType: MyOtherType withArgs(arg: String, arg2: String!): String unionChild: ChildUnion } type Child { bar: String! parent: MyType } type MyOtherType { bar: String! } union ChildUnion = Child | MyOtherType type Query { something: MyType! } type Subscription { somethingChanged: MyOtherType } interface Node { id: ID! } type SomeNode implements Node { id: ID! } interface AnotherNode { id: ID! } interface WithChild { unionChild: ChildUnion node: AnotherNode } interface WithChildren { unionChildren: [ChildUnion!]! nodes: [AnotherNode!]! } type AnotherNodeWithChild implements AnotherNode & WithChild { id: ID! unionChild: ChildUnion interfaceChild: Node } type AnotherNodeWithAll implements AnotherNode & WithChild & WithChildren { id: ID! unionChild: ChildUnion unionChildren: [ChildUnion!]! interfaceChild: Node interfaceChildren: [Node!]! } union MyUnion = MyType | MyOtherType scalar MyScalar directive @myDirective(arg: Int!, arg2: String!, arg3: Boolean!) on FIELD directive @authenticated on FIELD_DEFINITION `); export const resolversTestingValidate = async ( content: Types.PluginOutput, config: any = {}, pluginSchema = resolversTestingSchema, additionalCode = '' ) => { const mergedContent = mergeOutputs([ await tsPlugin(pluginSchema, [], config, { outputFile: '' }), content, additionalCode, ]); validateTs(mergedContent); return mergedContent; }; ================================================ FILE: packages/utils/graphql-codegen-testing/src/typescript.ts ================================================ import { dirname, join, resolve } from 'path'; import { Types } from '@graphql-codegen/plugin-helpers'; import * as LZString from 'lz-string'; // lz-string is a package which has CJS/ESM issues. So, we cannot do `import { something } from 'lz-string'` import { CompilerOptions, createCompilerHost, createProgram, createSourceFile, Diagnostic, flattenDiagnosticMessageText, JsxEmit, ModuleKind, ModuleResolutionKind, ScriptKind, ScriptTarget, ScriptTarget as ScriptTargetType, } from 'typescript'; export function validateTs( pluginOutput: Types.PluginOutput, options: CompilerOptions = { noEmitOnError: true, noImplicitAny: true, moduleResolution: ModuleResolutionKind.NodeJs, experimentalDecorators: true, emitDecoratorMetadata: true, target: ScriptTarget.ES5, typeRoots: [resolve(require.resolve('typescript'), '../../../@types/')], jsx: JsxEmit.React, allowJs: true, skipLibCheck: true, lib: [ join(dirname(require.resolve('typescript')), 'lib.es5.d.ts'), join(dirname(require.resolve('typescript')), 'lib.es6.d.ts'), join(dirname(require.resolve('typescript')), 'lib.dom.d.ts'), join(dirname(require.resolve('typescript')), 'lib.scripthost.d.ts'), join(dirname(require.resolve('typescript')), 'lib.es2015.d.ts'), join(dirname(require.resolve('typescript')), 'lib.esnext.d.ts'), ], module: ModuleKind.ESNext, }, isTsx = false, isStrict = false, suspenseErrors: string[] = [], compileProgram = false ): void { if (process.env.SKIP_VALIDATION) { return; } if (isStrict) { options.strictNullChecks = true; options.strict = true; options.strictBindCallApply = true; options.strictPropertyInitialization = true; options.alwaysStrict = true; options.strictFunctionTypes = true; } const contents: string = typeof pluginOutput === 'string' ? pluginOutput : [...new Set([...(pluginOutput.prepend || []), pluginOutput.content, ...(pluginOutput.append || [])])].join( '\n' ); const testFile = `test-file.${isTsx ? 'tsx' : 'ts'}`; const errors: string[] = []; if (compileProgram) { const host = createCompilerHost(options); const program = createProgram([testFile], options, { ...host, getSourceFile: ( fileName: string, languageVersion: ScriptTargetType, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean ) => { if (fileName === testFile) { return createSourceFile(fileName, contents, options.target); } return host.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); }, writeFile() {}, useCaseSensitiveFileNames() { return false; }, getCanonicalFileName(filename) { return filename; }, getCurrentDirectory() { return ''; }, getNewLine() { return '\n'; }, }); const emitResult = program.emit(); const allDiagnostics = emitResult.diagnostics; for (const diagnostic of allDiagnostics) { if (diagnostic.file) { const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); const message = flattenDiagnosticMessageText(diagnostic.messageText, '\n'); errors.push(`${line + 1},${character + 1}: ${message} -> ${contents.split('\n')[line]}`); } else { errors.push(String(flattenDiagnosticMessageText(diagnostic.messageText, '\n'))); } } } else { const result = createSourceFile( testFile, contents, ScriptTarget.ES2016, false, isTsx ? ScriptKind.TSX : undefined ) as { parseDiagnostics?: Diagnostic[] }; const allDiagnostics = result.parseDiagnostics; if (allDiagnostics && allDiagnostics.length > 0) { for (const diagnostic of allDiagnostics) { if (diagnostic.file) { const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!); const message = flattenDiagnosticMessageText(diagnostic.messageText, '\n'); errors.push(`${line + 1},${character + 1}: ${message} -> ${contents.split('\n')[line]}`); } else { errors.push(String(flattenDiagnosticMessageText(diagnostic.messageText, '\n'))); } } } } const relevantErrors = errors.filter(e => { if (e.includes('Cannot find module')) { return false; } for (const suspenseError of suspenseErrors) { if (e.includes(suspenseError)) { return false; } } return true; }); if (relevantErrors && relevantErrors.length > 0) { if (relevantErrors.length === 1) { throw new Error(relevantErrors[0]); } throw new AggregateError(relevantErrors, relevantErrors.join('\n')); } } export function compileTs( contents: string, options: CompilerOptions = { noEmitOnError: true, noImplicitAny: true, moduleResolution: ModuleResolutionKind.NodeJs, allowSyntheticDefaultImports: true, experimentalDecorators: true, emitDecoratorMetadata: true, target: ScriptTarget.ES5, typeRoots: [resolve(require.resolve('typescript'), '../../../@types/')], jsx: JsxEmit.Preserve, allowJs: true, lib: [ join(dirname(require.resolve('typescript')), 'lib.es5.d.ts'), join(dirname(require.resolve('typescript')), 'lib.es6.d.ts'), join(dirname(require.resolve('typescript')), 'lib.dom.d.ts'), join(dirname(require.resolve('typescript')), 'lib.scripthost.d.ts'), join(dirname(require.resolve('typescript')), 'lib.es2015.d.ts'), join(dirname(require.resolve('typescript')), 'lib.esnext.asynciterable.d.ts'), ], module: ModuleKind.ESNext, }, isTsx = false, openPlayground = false ): void { if (process.env.SKIP_VALIDATION) { return; } try { const testFile = `test-file.${isTsx ? 'tsx' : 'ts'}`; const host = createCompilerHost(options); const program = createProgram([testFile], options, { ...host, getSourceFile: ( fileName: string, languageVersion: ScriptTargetType, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean ) => { if (fileName === testFile) { return createSourceFile(fileName, contents, options.target); } return host.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); }, writeFile() {}, useCaseSensitiveFileNames() { return false; }, getCanonicalFileName(filename) { return filename; }, getCurrentDirectory() { return ''; }, getNewLine() { return '\n'; }, }); const emitResult = program.emit(); const allDiagnostics = emitResult.diagnostics; const errors: string[] = []; for (const diagnostic of allDiagnostics) { if (diagnostic.file) { const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); const message = flattenDiagnosticMessageText(diagnostic.messageText, '\n'); errors.push(`${line + 1},${character + 1}: ${message} -> ${contents.split('\n')[line]}`); } else { errors.push(String(flattenDiagnosticMessageText(diagnostic.messageText, '\n'))); } } const relevantErrors = errors.filter(e => !e.includes('Cannot find module')); if (relevantErrors && relevantErrors.length > 0) { throw new Error(relevantErrors.join('\n')); } } catch (e) { if (openPlayground) { const compressedCode = LZString.compressToEncodedURIComponent(contents); open('http://www.typescriptlang.org/play/#code/' + compressedCode); } throw e; } } ================================================ FILE: packages/utils/graphql-codegen-testing/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'graphql-codegen-testing', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: packages/utils/plugins-helpers/CHANGELOG.md ================================================ # @graphql-codegen/plugin-helpers ## 6.2.0 ### Minor Changes - [#10617](https://github.com/dotansimha/graphql-code-generator/pull/10617) [`8c4db2a`](https://github.com/dotansimha/graphql-code-generator/commit/8c4db2abd0578d7b1c9b4197dfa41dae3ef6252b) Thanks [@ikusakov2](https://github.com/ikusakov2)! - Allow GraphQLSchema to be passed directly to generate({schema: ...}) function ## 6.1.1 ### Patch Changes - [#10619](https://github.com/dotansimha/graphql-code-generator/pull/10619) [`cdf5dc5`](https://github.com/dotansimha/graphql-code-generator/commit/cdf5dc56c5591cfe031e02cbc31deff761a40072) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^11.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/11.0.0) (from `^10.0.0`, in `dependencies`) ## 6.1.0 ### Minor Changes - [#10510](https://github.com/dotansimha/graphql-code-generator/pull/10510) [`9e70bcb`](https://github.com/dotansimha/graphql-code-generator/commit/9e70bcbf5390e815a6844f1965b04056e5d8e670) Thanks [@nickmessing](https://github.com/nickmessing)! - add importExtension configuration option ## 6.0.0 ### Major Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGES: Do not generate \_\_isTypeOf for non-implementing types or non-union members - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Remove deprecated option `watchConfig` - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Ensure Federation Interfaces have `__resolveReference` if they are resolvable entities BREAKING CHANGES: Deprecate `onlyResolveTypeForInterfaces` because majority of use cases cannot implement resolvers in Interfaces. BREAKING CHANGES: Deprecate `generateInternalResolversIfNeeded.__resolveReference` because types do not have `__resolveReference` if they are not Federation entities or are not resolvable. Users should not have to manually set this option. This option was put in to wait for this major version. - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - BREAKING CHANGE: Improve Federation Entity's resolvers' parent param type: These types were using reference types inline. This makes it hard to handle mappers. The Parent type now all comes from ParentResolverTypes to make handling mappers and parent types simpler. - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix `mappers` usage with Federation `mappers` was previously used as `__resolveReference`'s first param (usually called "reference"). However, this is incorrect because `reference` interface comes directly from `@key` and `@requires` directives. This patch fixes the issue by creating a new `FederationTypes` type and use it as the base for federation entity types when being used to type entity references. BREAKING CHANGES: No longer generate `UnwrappedObject` utility type, as this was used to support the wrong previously generated type. - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Drop Node 18 support ### Minor Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Add `allowPartialOutputs` flag to partially write successful generation to files ### Patch Changes - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Update @requires type - [#10218](https://github.com/dotansimha/graphql-code-generator/pull/10218) [`140298a`](https://github.com/dotansimha/graphql-code-generator/commit/140298a33b257a0b7958e361971b5bc97bbc01c2) Thanks [@eddeee888](https://github.com/eddeee888)! - Fix fields or object types marked with @external being wrongly generated ## 5.1.1 ### Patch Changes - [#10150](https://github.com/dotansimha/graphql-code-generator/pull/10150) [`e324382`](https://github.com/dotansimha/graphql-code-generator/commit/e3243824cfe0d7ab463cf0d5a6455715510959be) Thanks [@ArminWiebigke](https://github.com/ArminWiebigke)! - Allow functions to be passed as valid values for `UrlSchemaOptions.customFetch`. This was already possible, but the type definitions did not reflect that correctly. ## 5.1.0 ### Minor Changes - [#9989](https://github.com/dotansimha/graphql-code-generator/pull/9989) [`55a1e9e`](https://github.com/dotansimha/graphql-code-generator/commit/55a1e9e63830df17ed40602ea7e322bbf48b17bc) Thanks [@eddeee888](https://github.com/eddeee888)! - Add `generateInternalResolversIfNeeded` option This option can be used to generate more correct types for internal resolvers. For example, only generate `__resolveReference` if the federation object has a resolvable `@key`. In the future, this option can be extended to support other internal resolvers e.g. `__isTypeOf` is only generated for implementing types and union members. ## 5.0.4 ### Patch Changes - [#9961](https://github.com/dotansimha/graphql-code-generator/pull/9961) [`dfc5310`](https://github.com/dotansimha/graphql-code-generator/commit/dfc5310ab476bed6deaefc608f311ff368722f7e) Thanks [@eddeee888](https://github.com/eddeee888)! - Update plugin output type to allow option `meta` field ## 5.0.3 ### Patch Changes - [#9813](https://github.com/dotansimha/graphql-code-generator/pull/9813) [`4e69568`](https://github.com/dotansimha/graphql-code-generator/commit/4e6956899c96f8954cea8d5bbe32aa35a70cc653) Thanks [@saihaj](https://github.com/saihaj)! - bumping for a release ## 5.0.2 ### Patch Changes - [#9811](https://github.com/dotansimha/graphql-code-generator/pull/9811) [`d8364e045`](https://github.com/dotansimha/graphql-code-generator/commit/d8364e045a46ca6e8173583b5108d161c6832975) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates: - Updated dependency [`tslib@~2.6.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.6.0) (from `~2.5.0`, in `dependencies`) ## 5.0.1 ### Patch Changes - [#9523](https://github.com/dotansimha/graphql-code-generator/pull/9523) [`bb1e0e96e`](https://github.com/dotansimha/graphql-code-generator/commit/bb1e0e96ed9d519684630cd7ea53869b48b4632e) Thanks [@tnyo43](https://github.com/tnyo43)! - add noSilentErrors option to the config type ## 5.0.0 ### Major Changes - [`bb66c2a31`](https://github.com/dotansimha/graphql-code-generator/commit/bb66c2a31985c1375912ccd6b2b02933f313c9c0) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Require Node.js `>= 16`. Drop support for Node.js 14 ### Patch Changes - [#9449](https://github.com/dotansimha/graphql-code-generator/pull/9449) [`4d9ea1a5a`](https://github.com/dotansimha/graphql-code-generator/commit/4d9ea1a5a94cd3458c1bd868ce1ab1cb806257f2) Thanks [@n1ru4l](https://github.com/n1ru4l)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/10.0.0) (from `^9.0.0`, in `dependencies`) - [#9332](https://github.com/dotansimha/graphql-code-generator/pull/9332) [`f46803a8c`](https://github.com/dotansimha/graphql-code-generator/commit/f46803a8c70840280529a52acbb111c865712af2) Thanks [@eddeee888](https://github.com/eddeee888)! - Update GitHub loader TypeScript type and usage docs - [#9360](https://github.com/dotansimha/graphql-code-generator/pull/9360) [`63827fabe`](https://github.com/dotansimha/graphql-code-generator/commit/63827fabede76b2380d40392aba2a3ccb099f0c4) Thanks [@beerose](https://github.com/beerose)! - Add handleAsSDL property to UrlSchemaOptions type ## 4.2.0 ### Minor Changes - [#9151](https://github.com/dotansimha/graphql-code-generator/pull/9151) [`b7dacb21f`](https://github.com/dotansimha/graphql-code-generator/commit/b7dacb21fb0ed1173d1e45120dc072e29231ed29) Thanks [@'./user/schema.mappers#UserMapper',](https://github.com/'./user/schema.mappers#UserMapper',)! - Add `watchPattern` config option for `generates` sections. By default, `watch` mode automatically watches all GraphQL schema and document files. This means when a change is detected, Codegen CLI is run. A user may want to run Codegen CLI when non-schema and non-document files are changed. Each `generates` section now has a `watchPattern` option to allow more file patterns to be added to the list of patterns to watch. In the example below, mappers are exported from `schema.mappers.ts` files. We want to re-run Codegen if the content of `*.mappers.ts` files change because they change the generated types file. To solve this, we can add mapper file patterns to watch using the glob pattern used for schema and document files. ```ts // codegen.ts const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { mappers: { Book: './book/schema.mappers#BookMapper', }, } watchPattern: 'src/schema/**/*.mappers.ts', // Watches mapper files in `watch` mode. Use an array for multiple patterns e.g. `['src/*.pattern1.ts','src/*.pattern2.ts']` }, }, }; ``` Then, run Codegen CLI in `watch` mode: ```shell yarn graphql-codegen --watch ``` Now, updating `*.mappers.ts` files re-runs Codegen! 🎉 Note: `watchPattern` is only used in `watch` mode i.e. running CLI with `--watch` flag. ### Patch Changes - [`f104619ac`](https://github.com/dotansimha/graphql-code-generator/commit/f104619acd27c9d62a06bc577737500880731087) Thanks [@saihaj](https://github.com/saihaj)! - Resolve issue with nesting fields in `@provides` directive being prevented ## 4.1.0 ### Minor Changes - [#8893](https://github.com/dotansimha/graphql-code-generator/pull/8893) [`a118c307a`](https://github.com/dotansimha/graphql-code-generator/commit/a118c307a35bbb97b7cbca0f178a88276032a26c) Thanks [@n1ru4l](https://github.com/n1ru4l)! - mark `plugins` in config optional - [#8723](https://github.com/dotansimha/graphql-code-generator/pull/8723) [`a3309e63e`](https://github.com/dotansimha/graphql-code-generator/commit/a3309e63efed880e6f74ce6fcbf82dd3d7857a15) Thanks [@kazekyo](https://github.com/kazekyo)! - Introduce a new feature called DocumentTransform. DocumentTransform is a functionality that allows you to modify `documents` before they are processed by plugins. You can use functions passed to the `documentTransforms` option to make changes to GraphQL documents. To use this feature, you can write `documentTransforms` as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { // Make some changes to the documents return documents } } ] } } } export default config ``` For instance, to remove a `@localOnlyDirective` directive from `documents`, you can write the following code: ```js import type { CodegenConfig } from '@graphql-codegen/cli' import { visit } from 'graphql' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: [ { transform: ({ documents }) => { return documents.map(documentFile => { documentFile.document = visit(documentFile.document, { Directive: { leave(node) { if (node.name.value === 'localOnlyDirective') return null } } }) return documentFile }) } } ] } } } export default config ``` DocumentTransform can also be specified by file name. You can create a custom file for a specific transformation and pass it to `documentTransforms`. Let's create the document transform as a file: ```js module.exports = { transform: ({ documents }) => { // Make some changes to the documents return documents } } ``` Then, you can specify the file name as follows: ```ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'https://localhost:4000/graphql', documents: ['src/**/*.tsx'], generates: { './src/gql/': { preset: 'client', documentTransforms: ['./my-document-transform.js'] } } } export default config ``` ### Patch Changes - [#8879](https://github.com/dotansimha/graphql-code-generator/pull/8879) [`8206b268d`](https://github.com/dotansimha/graphql-code-generator/commit/8206b268dfb485a748fd7783a163cb0ee9931491) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`tslib@~2.5.0` ↗︎](https://www.npmjs.com/package/tslib/v/2.5.0) (from `~2.4.0`, in `dependencies`) ## 4.0.0 ### Major Changes - [#8885](https://github.com/dotansimha/graphql-code-generator/pull/8885) [`fd0b0c813`](https://github.com/dotansimha/graphql-code-generator/commit/fd0b0c813015cae4f6f6bda5f4c5515e544eb76d) Thanks [@n1ru4l](https://github.com/n1ru4l)! - drop Node.js 12 support ### Patch Changes - [#8871](https://github.com/dotansimha/graphql-code-generator/pull/8871) [`fc79b65d4`](https://github.com/dotansimha/graphql-code-generator/commit/fc79b65d4914fd25ae6bd5d58ebc7ded573a08a5) Thanks [@B2o5T](https://github.com/B2o5T)! - eslint fixes ## 3.1.2 ### Patch Changes - [#8771](https://github.com/dotansimha/graphql-code-generator/pull/8771) [`ed87c782b`](https://github.com/dotansimha/graphql-code-generator/commit/ed87c782bf3292bfbee772c6962d6cbc43a9abe7) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`@graphql-tools/utils@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/utils/v/9.0.0) (from `^8.8.0`, in `dependencies`) - [#8718](https://github.com/dotansimha/graphql-code-generator/pull/8718) [`6c6b6f2df`](https://github.com/dotansimha/graphql-code-generator/commit/6c6b6f2df88a3a37b437a25320dab5590f033316) Thanks [@AaronBuxbaum](https://github.com/AaronBuxbaum)! - Add `globalGqlIdentifierName` to the types ## 3.1.1 ### Patch Changes - [`307a5d350`](https://github.com/dotansimha/graphql-code-generator/commit/307a5d350643dd065d228b04ef3b4bd70cac0e81) Thanks [@saihaj](https://github.com/saihaj)! - Something went wrong in old relesae so this will ensure we have a good bump on all packages ## 3.1.0 ### Minor Changes - [#8662](https://github.com/dotansimha/graphql-code-generator/pull/8662) [`c0183810f`](https://github.com/dotansimha/graphql-code-generator/commit/c0183810f0178aec6f49ab8a6f35f7adc4d9f13e) Thanks [@jantimon](https://github.com/jantimon)! - the life cycle hook beforeOneFileWrite is now able to modify the generated content ## 3.0.0 ### Major Changes - [#8652](https://github.com/dotansimha/graphql-code-generator/pull/8652) [`c802a0c0b`](https://github.com/dotansimha/graphql-code-generator/commit/c802a0c0b775cfabc5ace3e7fb6655540c6c4d84) Thanks [@jantimon](https://github.com/jantimon)! - improve typings for life cycle hooks ### Patch Changes - [#8686](https://github.com/dotansimha/graphql-code-generator/pull/8686) [`a6c2097f4`](https://github.com/dotansimha/graphql-code-generator/commit/a6c2097f4789c0cce4296ce349790ce29943ed22) Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates: - Updated dependency [`change-case-all@1.0.15` ↗︎](https://www.npmjs.com/package/change-case-all/v/1.0.15) (from `1.0.14`, in `dependencies`) - [#8661](https://github.com/dotansimha/graphql-code-generator/pull/8661) [`f79a00e8a`](https://github.com/dotansimha/graphql-code-generator/commit/f79a00e8ae073eab426ca08795c924e716123482) Thanks [@jantimon](https://github.com/jantimon)! - refactor hook execution ## 2.7.2 ### Patch Changes - [#8525](https://github.com/dotansimha/graphql-code-generator/pull/8525) [`63dc8f205`](https://github.com/dotansimha/graphql-code-generator/commit/63dc8f2054e27b944f7d8dc59db8afa85760a127) Thanks [@charlypoly](https://github.com/charlypoly)! - remove `DetailledError`, not supported by Listr renderer ## 2.7.1 ### Patch Changes - [#8368](https://github.com/dotansimha/graphql-code-generator/pull/8368) [`4113b1bd3`](https://github.com/dotansimha/graphql-code-generator/commit/4113b1bd39f3d32759c68a292e8492a0dd4f7371) Thanks [@charlypoly](https://github.com/charlypoly)! - fix(cli): support ApolloEngine loader in TypeScript config ## 2.7.0 ### Minor Changes - [#8301](https://github.com/dotansimha/graphql-code-generator/pull/8301) [`2ed21a471`](https://github.com/dotansimha/graphql-code-generator/commit/2ed21a471f8de58ecafebf4bf64b3c32cee24d2f) Thanks [@charlypoly](https://github.com/charlypoly)! - Introduces support for TypeScript config file and a new preset lifecycle (required for `client-preset`) ## 2.6.2 ### Patch Changes - [#8189](https://github.com/dotansimha/graphql-code-generator/pull/8189) [`b408f8238`](https://github.com/dotansimha/graphql-code-generator/commit/b408f8238c00bbb4cd448501093856c06cfde50f) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Fix CommonJS TypeScript resolution with `moduleResolution` `node16` or `nodenext` ## 2.6.1 ### Patch Changes - 6a2e328e6: feat(cli): `--verbose` and `--debug` flags ## 2.6.0 ### Minor Changes - 2cbcbb371: Add new flag to emit legacy common js imports. Default it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065). You can use the option in your config: ```yaml schema: 'schema.graphql' documents: - 'src/**/*.graphql' emitLegacyCommonJSImports: true ``` Alternative you can use the CLI to set this option: ```bash $ codegen --config-file=config.yml --emit-legacy-common-js-imports ``` ## 2.5.0 ### Minor Changes - d84afec09: Support TypeScript ESM modules (`"module": "node16"` and `"moduleResolution": "node16"`). [More information on the TypeScript Release Notes.](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#ecmascript-module-support-in-node-js) - 8e44df58b: Add new config option to not exit with non-zero exit code when there are no documents. You can use this option in your config: ```yaml schema: 'schema.graphql' documents: - 'src/**/*.graphql' ignoreNoDocuments: true ``` Alternative you can use the CLI to set this option: ```bash $ codegen --config-file=config.yml --ignore-no-documents ``` ### Patch Changes - a4fe5006b: Fix TS type error on strictNullChecks: true Fix the compiler error: ``` node_modules/@graphql-codegen/plugin-helpers/oldVisit.d.ts:5:75 - error TS2339: Property 'enter' does not exist on type '{ readonly enter?: ASTVisitFn | undefined; readonly leave: ASTReducerFn; } | { readonly enter?: ASTVisitFn | undefined; readonly leave: ASTReducerFn<...>; } | ... 41 more ... | undefined'. 5 enter?: Partial>; ~~~~~~~ node_modules/@graphql-codegen/plugin-helpers/oldVisit.d.ts:6:75 - error TS2339: Property 'leave' does not exist on type '{ readonly enter?: ASTVisitFn | undefined; readonly leave: ASTReducerFn; } | { readonly enter?: ASTVisitFn | undefined; readonly leave: ASTReducerFn<...>; } | ... 41 more ... | undefined'. 6 leave?: Partial>; ~~~~~~~ Found 2 errors in the same file, starting at: node_modules/@graphql-codegen/plugin-helpers/oldVisit.d.ts:5 ``` Only happens when TS compiler options `strictNullChecks: true` and `skipLibCheck: false`. `Partial` includes `{}`, therefore `NewVisitor[keyof NewVisitor]` includes `undefined`, and indexing `undefined` is error. Eliminate `undefined` by wrapping it inside `NonNullable<...>`. Related #7519 ## 2.4.2 ### Patch Changes - a521216d6: broken links within documentation ## 2.4.1 ### Patch Changes - cb9adeb96: Cache validation of documents ## 2.4.0 ### Minor Changes - 754a33715: Performance Profiler --profile ## 2.3.2 ### Patch Changes - 6002feb3d: Fix exports in package.json files for react-native projects ## 2.3.1 ### Patch Changes - bcc5636fc: fix wrong dependency version range ## 2.3.0 ### Minor Changes - 97ddb487a: feat: GraphQL v16 compatibility ## 2.2.0 ### Minor Changes - 7c60e5acc: feat(core): ability to skip some specific validation rules with skipDocumentsValidation option ## 2.1.1 ### Patch Changes - 6470e6cc9: fix(plugin-helpers): remove unnecessary import - 35199dedf: Fix module not found bug in resolveExternalModuleAndFn ## 2.1.0 ### Minor Changes - 39773f59b: enhance(plugins): use getDocumentNodeFromSchema and other utilities from @graphql-tools/utils - 440172cfe: support ESM ### Patch Changes - 24185985a: bump graphql-tools package versions ## 2.0.0 ### Major Changes - b0cb13df4: Update to latest `graphql-tools` and `graphql-config` version. ‼️ ‼️ ‼️ Please note ‼️ ‼️ ‼️: This is a breaking change since Node 10 is no longer supported in `graphql-tools`, and also no longer supported for Codegen packages. ## 1.18.8 ### Patch Changes - 470336a1: don't require plugins for for config if preset provides plugin. Instead the preset should throw if no plugins were provided. ## 1.18.7 ### Patch Changes - dfd25caf: chore(deps): bump graphql-tools versions ## 1.18.6 ### Patch Changes - 637338cb: fix: make lifecycle hooks definition a partial ## 1.18.5 ### Patch Changes - d9212aa0: fix(visitor-plugin-common): guard for a runtime type error ## 1.18.4 ### Patch Changes - 23862e7e: fix(naming-convention): revert and pin change-case-all dependency for workaround #3256 ## 1.18.3 ### Patch Changes - 29b75b1e: enhance(namingConvention): use change-case-all instead of individual packages for naming convention ## 1.18.2 ### Patch Changes - 1183d173: Bump all packages to resolve issues with shared dependencies ## 1.18.1 ### Patch Changes - eaf45d1f: fix issue with inline fragment without typeCondition ## 1.18.0 ### Minor Changes - 857c603c: Adds the --errors-only flag to the cli to print errors only. ## 1.17.9 ### Patch Changes - da8bdd17: Allow hooks to be defined as partial object ## 1.17.8 ### Patch Changes - 1d7c6432: Bump all packages to allow "^" in deps and fix compatibility issues - 1d7c6432: Bump versions of @graphql-tools/ packages to fix issues with loading schemas and SDL comments ================================================ FILE: packages/utils/plugins-helpers/package.json ================================================ { "name": "@graphql-codegen/plugin-helpers", "version": "6.2.0", "description": "GraphQL Code Generator common utils and types", "repository": { "type": "git", "url": "https://github.com/dotansimha/graphql-code-generator.git", "directory": "packages/utils/plugins-helpers" }, "license": "MIT", "scripts": { "lint": "eslint **/*.ts", "test": "vitest --no-watch" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" }, "dependencies": { "@graphql-tools/utils": "^11.0.0", "change-case-all": "1.0.15", "common-tags": "1.8.2", "import-from": "4.0.0", "lodash": "~4.17.0", "tslib": "~2.6.0" }, "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "exports": { ".": { "require": { "types": "./dist/typings/index.d.cts", "default": "./dist/cjs/index.js" }, "import": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" }, "default": { "types": "./dist/typings/index.d.ts", "default": "./dist/esm/index.js" } }, "./package.json": "./package.json" }, "typings": "dist/typings/index.d.ts", "typescript": { "definition": "dist/typings/index.d.ts" }, "publishConfig": { "directory": "dist", "access": "public" }, "type": "module", "devDependencies": { "@graphql-tools/apollo-engine-loader": "8.0.1" }, "engines": { "node": ">=16" } } ================================================ FILE: packages/utils/plugins-helpers/src/federation.ts ================================================ import { astFromInterfaceType, astFromObjectType, getRootTypeNames, MapperKind, mapSchema } from '@graphql-tools/utils'; import type { FieldDefinitionResult } from '@graphql-codegen/visitor-plugin-common'; import { DefinitionNode, DirectiveNode, FieldDefinitionNode, GraphQLFieldConfigMap, GraphQLInterfaceType, GraphQLObjectType, GraphQLSchema, InterfaceTypeDefinitionNode, isObjectType, ObjectTypeDefinitionNode, OperationDefinitionNode, parse, StringValueNode, } from 'graphql'; import { oldVisit } from './index.js'; import { getBaseType } from './utils.js'; /** * Federation Spec */ export const federationSpec = parse(/* GraphQL */ ` scalar _FieldSet directive @external on FIELD_DEFINITION directive @requires(fields: _FieldSet!) on FIELD_DEFINITION directive @provides(fields: _FieldSet!) on FIELD_DEFINITION directive @key(fields: _FieldSet!) on OBJECT | INTERFACE `); /** * ReferenceSelectionSet * @description Each is a collection of fields that are available in a reference payload (originated from the Router) * @example * - resolvable fields marked with `@key` * - fields declared in `@provides` * - fields declared in `@requires` */ interface DirectiveSelectionSet { name: string; selection: boolean | DirectiveSelectionSet[]; } type ReferenceSelectionSet = Record; // TODO: handle nested interface TypeMeta { hasResolveReference: boolean; resolvableKeyDirectives: readonly DirectiveNode[]; /** * referenceSelectionSets * @description Each element can be `ReferenceSelectionSet[]`. * Elements at the root level are combined with `&` and nested elements are combined with `|`. * * @example: * - [[A, B], [C], [D]] -> (A | B) & C & D * - [[A, B], [C, D], [E]] -> (A | B) & (C | D) & E */ referenceSelectionSets: { directive: '@key' | '@requires'; selectionSets: ReferenceSelectionSet[] }[]; referenceSelectionSetsString: string; } export type FederationMeta = { [typeName: string]: TypeMeta }; /** * Adds `__resolveReference` in each ObjectType and InterfaceType involved in Federation. * We do this to utilise the existing FieldDefinition logic of the plugin, which includes many logic: * - mapper * - return type * @param schema */ export function addFederationReferencesToSchema(schema: GraphQLSchema): { transformedSchema: GraphQLSchema; federationMeta: FederationMeta; } { const setFederationMeta = ({ meta, typeName, update, }: { meta: FederationMeta; typeName: string; update: TypeMeta; }): void => { meta[typeName] = { ...(meta[typeName] || ({ hasResolveReference: false, resolvableKeyDirectives: [], referenceSelectionSets: [], referenceSelectionSetsString: '', } satisfies TypeMeta)), ...update, }; }; const getReferenceSelectionSets = ({ resolvableKeyDirectives, fields, }: { resolvableKeyDirectives: readonly DirectiveNode[]; fields: GraphQLFieldConfigMap; }): TypeMeta['referenceSelectionSets'] => { const referenceSelectionSets: TypeMeta['referenceSelectionSets'] = []; // @key() @key() - "primary keys" in Federation // A reference may receive one primary key combination at a time, so they will be combined with `|` const primaryKeys = resolvableKeyDirectives.map(extractReferenceSelectionSet); referenceSelectionSets.push({ directive: '@key', selectionSets: [...primaryKeys] }); const requiresPossibleTypes: ReferenceSelectionSet[] = []; for (const fieldNode of Object.values(fields)) { // Look for @requires and see what the service needs and gets const directives = getDirectivesByName('requires', fieldNode.astNode); for (const directive of directives) { const requires = extractReferenceSelectionSet(directive); requiresPossibleTypes.push(requires); } } referenceSelectionSets.push({ directive: '@requires', selectionSets: requiresPossibleTypes }); return referenceSelectionSets; }; /** * Function to find all combinations of selection sets and push them into the `result` * This is used for `@requires` directive because depending on the operation selection set, different * combination of fields are sent from the router. * * @example * Input: [ * { a: true }, * { b: true }, * { c: true }, * { d: true}, * ] * Output: [ * { a: true }, * { a: true, b: true }, * { a: true, c: true }, * { a: true, d: true }, * { a: true, b: true, c: true }, * { a: true, b: true, d: true }, * { a: true, c: true, d: true }, * { a: true, b: true, c: true, d: true } * * { b: true }, * { b: true, c: true }, * { b: true, d: true }, * { b: true, c: true, d: true } * * { c: true }, * { c: true, d: true }, * * { d: true }, * ] * ``` */ function findAllSelectionSetCombinations( selectionSets: ReferenceSelectionSet[], result: ReferenceSelectionSet[] ): void { if (selectionSets.length === 0) { return; } for (let baseIndex = 0; baseIndex < selectionSets.length; baseIndex++) { const base = selectionSets.slice(0, baseIndex + 1); const rest = selectionSets.slice(baseIndex + 1, selectionSets.length); const currentSelectionSet = base.reduce((acc, selectionSet) => { acc = { ...acc, ...selectionSet }; return acc; }, {}); if (baseIndex === 0) { result.push(currentSelectionSet); } for (const selectionSet of rest) { result.push({ ...currentSelectionSet, ...selectionSet }); } } const next = selectionSets.slice(1, selectionSets.length); if (next.length > 0) { findAllSelectionSetCombinations(next, result); } } const printReferenceSelectionSets = ({ typeName, baseFederationType, referenceSelectionSets, }: { typeName: string; baseFederationType: string; referenceSelectionSets: TypeMeta['referenceSelectionSets']; }): string => { const referenceSelectionSetStrings = referenceSelectionSets.reduce( (acc, { directive, selectionSets: originalSelectionSets }) => { const result: string[] = []; let selectionSets = originalSelectionSets; if (directive === '@requires') { selectionSets = []; findAllSelectionSetCombinations(originalSelectionSets, selectionSets); if (selectionSets.length > 0) { result.push('Record'); } } for (const referenceSelectionSet of selectionSets) { result.push(`GraphQLRecursivePick<${baseFederationType}, ${JSON.stringify(referenceSelectionSet)}>`); } if (result.length === 0) { return acc; } if (result.length === 1) { acc.push(result.join(' | ')); return acc; } acc.push(`( ${result.join('\n | ')} )`); return acc; }, [] ); return `\n ( { __typename: '${typeName}' }\n & ${referenceSelectionSetStrings.join('\n & ')} )`; }; const federationMeta: FederationMeta = {}; const transformedSchema = mapSchema(schema, { [MapperKind.INTERFACE_TYPE]: type => { const node = astFromInterfaceType(type, schema); const federationDetails = checkTypeFederationDetails(node, schema); if (federationDetails && federationDetails.resolvableKeyDirectives.length > 0) { const typeConfig = type.toConfig(); typeConfig.fields = { [resolveReferenceFieldName]: { type, }, ...typeConfig.fields, }; const referenceSelectionSets = getReferenceSelectionSets({ resolvableKeyDirectives: federationDetails.resolvableKeyDirectives, fields: typeConfig.fields, }); const referenceSelectionSetsString = printReferenceSelectionSets({ typeName: type.name, baseFederationType: `FederationTypes['${type.name}']`, // FIXME: run convertName on FederationTypes referenceSelectionSets, }); setFederationMeta({ meta: federationMeta, typeName: type.name, update: { hasResolveReference: true, resolvableKeyDirectives: federationDetails.resolvableKeyDirectives, referenceSelectionSets, referenceSelectionSetsString, }, }); return new GraphQLInterfaceType(typeConfig); } return type; }, [MapperKind.OBJECT_TYPE]: type => { const node = astFromObjectType(type, schema); const federationDetails = checkTypeFederationDetails(node, schema); if (federationDetails && federationDetails.resolvableKeyDirectives.length > 0) { const typeConfig = type.toConfig(); const referenceSelectionSets = getReferenceSelectionSets({ resolvableKeyDirectives: federationDetails.resolvableKeyDirectives, fields: typeConfig.fields, }); typeConfig.fields = { [resolveReferenceFieldName]: { type, }, ...typeConfig.fields, }; const referenceSelectionSetsString = printReferenceSelectionSets({ typeName: type.name, baseFederationType: `FederationTypes['${type.name}']`, // FIXME: run convertName on FederationTypes referenceSelectionSets, }); setFederationMeta({ meta: federationMeta, typeName: type.name, update: { hasResolveReference: true, resolvableKeyDirectives: federationDetails.resolvableKeyDirectives, referenceSelectionSets, referenceSelectionSetsString, }, }); return new GraphQLObjectType(typeConfig); } return type; }, }); return { transformedSchema, federationMeta, }; } /** * Removes Federation Spec from GraphQL Schema * @param schema * @param config */ export function removeFederation(schema: GraphQLSchema): GraphQLSchema { return mapSchema(schema, { [MapperKind.QUERY]: queryType => { const queryTypeConfig = queryType.toConfig(); delete queryTypeConfig.fields._entities; delete queryTypeConfig.fields._service; return new GraphQLObjectType(queryTypeConfig); }, [MapperKind.UNION_TYPE]: unionType => { const unionTypeName = unionType.name; if (unionTypeName === '_Entity' || unionTypeName === '_Any') { return null; } return unionType; }, [MapperKind.OBJECT_TYPE]: objectType => { if (objectType.name === '_Service') { return null; } return objectType; }, }); } const resolveReferenceFieldName = '__resolveReference'; export class ApolloFederation { private enabled = false; private schema: GraphQLSchema; private providesMap: Record; /** * `fieldsToGenerate` is a meta object where the keys are object type names * and the values are fields that must be generated for that object. */ private fieldsToGenerate: Record; protected meta: FederationMeta = {}; constructor({ enabled, schema, meta }: { enabled: boolean; schema: GraphQLSchema; meta: FederationMeta }) { this.enabled = enabled; this.schema = schema; this.providesMap = this.createMapOfProvides(); this.fieldsToGenerate = {}; this.meta = meta; } /** * Excludes types definde by Federation * @param typeNames List of type names */ filterTypeNames(typeNames: string[]): string[] { return this.enabled ? typeNames.filter(t => t !== '_FieldSet') : typeNames; } /** * Excludes `__resolveReference` fields * @param fieldNames List of field names */ filterFieldNames(fieldNames: string[]): string[] { return this.enabled ? fieldNames.filter(t => t !== resolveReferenceFieldName) : fieldNames; } /** * Decides if directive should not be generated * @param name directive's name */ skipDirective(name: string): boolean { return this.enabled && ['external', 'requires', 'provides', 'key'].includes(name); } /** * Decides if scalar should not be generated * @param name directive's name */ skipScalar(name: string): boolean { return this.enabled && name === '_FieldSet'; } /** * findFieldNodesToGenerate * @description Function to find field nodes to generate. * In a normal setup, all fields must be generated. * However, in a Federatin setup, a field should not be generated if: * - The field is marked as `@external` and there is no `@provides` path to the field * - The parent object is marked as `@external` and there is no `@provides` path to the field */ findFieldNodesToGenerate({ node, }: { node: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode; }): readonly FieldDefinitionNode[] { const nodeName = node.name.value; if (this.fieldsToGenerate[nodeName]) { return this.fieldsToGenerate[nodeName]; } const fieldNodes = ((node.fields || []) as unknown as FieldDefinitionResult[]).map(field => field.node); if (!this.enabled) { return fieldNodes; } // If the object is marked with `@external`, fields to generate are those with `@provides` if (this.isExternal(node)) { const fieldNodesWithProvides = fieldNodes.reduce((acc, fieldNode) => { if (this.hasProvides(node, fieldNode.name.value)) { acc.push(fieldNode); return acc; } return acc; }, []); this.fieldsToGenerate[nodeName] = fieldNodesWithProvides; return fieldNodesWithProvides; } // If the object is not marked with `@external`, fields to generate are: // - the fields without `@external` // - the `@external` fields with `@provides` const fieldNodesWithoutExternalOrHasProvides = fieldNodes.reduce((acc, fieldNode) => { if (!this.isExternal(fieldNode)) { acc.push(fieldNode); return acc; } if (this.isExternal(fieldNode) && this.hasProvides(node, fieldNode.name.value)) { acc.push(fieldNode); return acc; } return acc; }, []); this.fieldsToGenerate[nodeName] = fieldNodesWithoutExternalOrHasProvides; return fieldNodesWithoutExternalOrHasProvides; } isResolveReferenceField(fieldNode: FieldDefinitionNode): boolean { const name = typeof fieldNode.name === 'string' ? fieldNode.name : fieldNode.name.value; return this.enabled && name === resolveReferenceFieldName; } addFederationTypeGenericIfApplicable({ genericTypes, typeName, federationTypesType, }: { genericTypes: string[]; typeName: string; federationTypesType: string; }): void { if (!this.getMeta()[typeName]) { return; } const typeRef = `${federationTypesType}['${typeName}']`; genericTypes.push(`FederationReferenceType extends ${typeRef} = ${typeRef}`); } getMeta() { return this.meta; } private isExternal(node: FieldDefinitionNode | ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode): boolean { return getDirectivesByName('external', node).length > 0; } private hasProvides(node: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, fieldName: string): boolean { const fields = this.providesMap[node.name.value]; if (fields?.length) { return fields.includes(fieldName); } return false; } private createMapOfProvides() { const providesMap: Record = {}; for (const typename of Object.keys(this.schema.getTypeMap())) { const objectType = this.schema.getType(typename); if (isObjectType(objectType)) { for (const field of Object.values(objectType.getFields())) { const provides = getDirectivesByName('provides', field.astNode) .map(extractReferenceSelectionSet) .reduce((prev, curr) => [...prev, ...Object.keys(curr)], []); // FIXME: this is not taking into account nested selection sets e.g. `company { taxCode }` const ofType = getBaseType(field.type); providesMap[ofType.name] ||= []; providesMap[ofType.name].push(...provides); } } } return providesMap; } } /** * Checks if Object Type is involved in Federation. Based on `@key` directive * @param node Type */ function checkTypeFederationDetails( node: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, schema: GraphQLSchema ): { resolvableKeyDirectives: readonly DirectiveNode[] } | false { const name = node.name.value; const directives = node.directives; const rootTypeNames = getRootTypeNames(schema); const isNotRoot = !rootTypeNames.has(name); const isNotIntrospection = !name.startsWith('__'); const keyDirectives = directives.filter(d => d.name.value === 'key'); const check = isNotRoot && isNotIntrospection && keyDirectives.length > 0; if (!check) { return false; } const resolvableKeyDirectives = keyDirectives.filter(d => { for (const arg of d.arguments) { if (arg.name.value === 'resolvable' && arg.value.kind === 'BooleanValue' && arg.value.value === false) { return false; } } return true; }); return { resolvableKeyDirectives }; } /** * Extracts directives from a node based on directive's name * @param name directive name * @param node ObjectType or Field */ function getDirectivesByName( name: string, node: ObjectTypeDefinitionNode | FieldDefinitionNode | InterfaceTypeDefinitionNode ): readonly DirectiveNode[] { return node?.directives?.filter(d => d.name.value === name) || []; } function extractReferenceSelectionSet(directive: DirectiveNode): ReferenceSelectionSet { const arg = directive.arguments.find(arg => arg.name.value === 'fields'); const { value } = arg.value as StringValueNode; return oldVisit(parse(`{${value}}`), { leave: { SelectionSet(node) { return (node.selections as any as DirectiveSelectionSet[]).reduce((accum, field) => { accum[field.name] = field.selection; return accum; }, {}); }, Field(node) { return { name: node.name.value, selection: node.selectionSet || true, } as DirectiveSelectionSet; }, Document(node) { return node.definitions.find( (def: DefinitionNode): def is OperationDefinitionNode => def.kind === 'OperationDefinition' && def.operation === 'query' ).selectionSet; }, }, }); } ================================================ FILE: packages/utils/plugins-helpers/src/getCachedDocumentNodeFromSchema.ts ================================================ import { getDocumentNodeFromSchema, memoize1 } from '@graphql-tools/utils'; export const getCachedDocumentNodeFromSchema = memoize1(getDocumentNodeFromSchema); ================================================ FILE: packages/utils/plugins-helpers/src/helpers.ts ================================================ import { ASTNode, DocumentNode, FieldNode, FragmentDefinitionNode, GraphQLObjectType, GraphQLOutputType, GraphQLSchema, InlineFragmentNode, InputValueDefinitionNode, isListType, isNonNullType, isObjectType, Kind, OperationDefinitionNode, SelectionSetNode, VariableDefinitionNode, visit, } from 'graphql'; import { Types } from './types.js'; import { getBaseType } from './utils.js'; export function isOutputConfigArray(type: any): type is Types.OutputConfig[] { return Array.isArray(type); } export function isConfiguredOutput(type: any): type is Types.ConfiguredOutput { return typeof type === 'object'; } export function normalizeOutputParam( config: Types.OutputConfig | Types.ConfiguredPlugin[] | Types.ConfiguredOutput ): Types.ConfiguredOutput { // In case of direct array with a list of plugins if (isOutputConfigArray(config)) { return { documents: [], schema: [], plugins: isConfiguredOutput(config) ? config.plugins : config, }; } if (isConfiguredOutput(config)) { return config; } throw new Error(`Invalid "generates" config!`); } export function normalizeInstanceOrArray(type: T | T[]): T[] { if (Array.isArray(type)) { return type; } if (!type) { return []; } return [type]; } export function normalizeConfig(config: Types.OutputConfig | Types.OutputConfig[]): Types.ConfiguredPlugin[] { if (typeof config === 'string') { return [{ [config]: {} }]; } if (Array.isArray(config)) { return config.map(plugin => (typeof plugin === 'string' ? { [plugin]: {} } : plugin)); } if (typeof config === 'object') { return Object.keys(config).reduce((prev, pluginName) => [...prev, { [pluginName]: config[pluginName] }], []); } return []; } export function hasNullableTypeRecursively(type: GraphQLOutputType): boolean { if (!isNonNullType(type)) { return true; } if (isListType(type) || isNonNullType(type)) { return hasNullableTypeRecursively(type.ofType); } return false; } export function isUsingTypes(document: DocumentNode, externalFragments: string[], schema?: GraphQLSchema): boolean { let foundFields = 0; const typesStack: GraphQLObjectType[] = []; visit(document, { SelectionSet: { enter( node: SelectionSetNode, key, parent: InlineFragmentNode | FragmentDefinitionNode | FieldNode | OperationDefinitionNode, anscestors ) { const insideIgnoredFragment = (anscestors as any).find( (f: ASTNode) => f.kind && f.kind === 'FragmentDefinition' && externalFragments.includes(f.name.value) ); if (insideIgnoredFragment) { return; } const selections = node.selections || []; if (schema && selections.length > 0) { const nextTypeName = (() => { if (parent.kind === Kind.FRAGMENT_DEFINITION) { return parent.typeCondition.name.value; } if (parent.kind === Kind.FIELD) { const lastType = typesStack[typesStack.length - 1]; if (!lastType) { throw new Error(`Unable to find parent type! Please make sure you operation passes validation`); } const field = lastType.getFields()[parent.name.value]; if (!field) { throw new Error(`Unable to find field "${parent.name.value}" on type "${lastType}"!`); } return getBaseType(field.type).name; } if (parent.kind === Kind.OPERATION_DEFINITION) { if (parent.operation === 'query') { return schema.getQueryType().name; } if (parent.operation === 'mutation') { return schema.getMutationType().name; } if (parent.operation === 'subscription') { return schema.getSubscriptionType().name; } } else if (parent.kind === Kind.INLINE_FRAGMENT) { if (parent.typeCondition) { return parent.typeCondition.name.value; } return typesStack[typesStack.length - 1].name; } return null; })(); typesStack.push(schema.getType(nextTypeName) as any); } }, leave(node: SelectionSetNode) { const selections = node.selections || []; if (schema && selections.length > 0) { typesStack.pop(); } }, }, Field: { enter: (node: FieldNode, key, parent, path, anscestors) => { if (node.name.value.startsWith('__')) { return; } const insideIgnoredFragment = (anscestors as any).find( (f: ASTNode) => f.kind && f.kind === 'FragmentDefinition' && externalFragments.includes(f.name.value) ); if (insideIgnoredFragment) { return; } const selections = node.selectionSet ? node.selectionSet.selections || [] : []; const relevantFragmentSpreads = selections.filter( s => s.kind === Kind.FRAGMENT_SPREAD && !externalFragments.includes(s.name.value) ); if (selections.length === 0 || relevantFragmentSpreads.length > 0) { foundFields++; } if (schema) { const lastType = typesStack[typesStack.length - 1]; if (lastType && isObjectType(lastType)) { const field = lastType.getFields()[node.name.value]; if (!field) { throw new Error(`Unable to find field "${node.name.value}" on type "${lastType}"!`); } const currentType = field.type; // To handle `Maybe` usage if (hasNullableTypeRecursively(currentType)) { foundFields++; } } } }, }, VariableDefinition: { enter: (node: VariableDefinitionNode, key, parent, path, anscestors) => { const insideIgnoredFragment = (anscestors as any).find( (f: ASTNode) => f.kind && f.kind === 'FragmentDefinition' && externalFragments.includes(f.name.value) ); if (insideIgnoredFragment) { return; } foundFields++; }, }, InputValueDefinition: { enter: (node: InputValueDefinitionNode, key, parent, path, anscestors) => { const insideIgnoredFragment = (anscestors as any).find( (f: ASTNode) => f.kind && f.kind === 'FragmentDefinition' && externalFragments.includes(f.name.value) ); if (insideIgnoredFragment) { return; } foundFields++; }, }, }); return foundFields > 0; } export function normalizeImportExtension({ emitLegacyCommonJSImports, importExtension, }: { emitLegacyCommonJSImports: boolean | undefined; importExtension: '' | `.${string}` | undefined; }): '' | `.${string}` { if (importExtension !== undefined) { return importExtension; } if (emitLegacyCommonJSImports === undefined || emitLegacyCommonJSImports === true) { return ''; } return '.js'; } ================================================ FILE: packages/utils/plugins-helpers/src/index.ts ================================================ export * from './federation.js'; export * from './getCachedDocumentNodeFromSchema.js'; export * from './helpers.js'; export * from './oldVisit.js'; export * from './profiler.js'; export { resolveExternalModuleAndFn } from './resolve-external-module-and-fn.js'; export * from './types.js'; export { Types } from './types.js'; export * from './utils.js'; ================================================ FILE: packages/utils/plugins-helpers/src/oldVisit.ts ================================================ import { ASTNode, visit } from 'graphql'; type VisitFn = typeof visit; type NewVisitor = Partial[1]>; type OldVisitor = { enter?: Partial['enter']>>; leave?: Partial['leave']>>; } & NewVisitor; export function oldVisit( root: ASTNode, { enter: enterVisitors, leave: leaveVisitors, ...newVisitor }: OldVisitor ): any { if (typeof enterVisitors === 'object') { for (const key in enterVisitors) { newVisitor[key] ||= {}; newVisitor[key].enter = enterVisitors[key]; } } if (typeof leaveVisitors === 'object') { for (const key in leaveVisitors) { newVisitor[key] ||= {}; newVisitor[key].leave = leaveVisitors[key]; } } return visit(root, newVisitor); } ================================================ FILE: packages/utils/plugins-helpers/src/profiler.ts ================================================ export interface ProfilerEvent { /** The name of the event, as displayed in Trace Viewer */ name: string; /** The event categories. This is a comma separated list of categories for the event. The categories can be used to hide events in the Trace Viewer UI. */ cat: string; /** The event type. This is a single character which changes depending on the type of event being output. The valid values are listed in the table below. We will discuss each phase type below. */ ph: string; /** The tracing clock timestamp of the event. The timestamps are provided at microsecond granularity. */ ts: number; /** Optional. The thread clock timestamp of the event. The timestamps are provided at microsecond granularity. */ tts?: string; /** The process ID for the process that output this event. */ pid: number; /** The thread ID for the thread that output this event. */ tid: number; /** Any arguments provided for the event. Some of the event types have required argument fields, otherwise, you can put any information you wish in here. The arguments are displayed in Trace Viewer when you view an event in the analysis section. */ args?: any; /** duration */ dur: number; /** A fixed color name to associate with the event. If provided, cname must be one of the names listed in trace-viewer's base color scheme's reserved color names list */ cname?: string; } export interface Profiler { run(fn: () => Promise, name: string, cat?: string): Promise; collect(): ProfilerEvent[]; } export function createNoopProfiler(): Profiler { return { run(fn) { return Promise.resolve().then(() => fn()); }, collect() { return []; }, }; } export function createProfiler(): Profiler { const events: ProfilerEvent[] = []; return { collect() { return events; }, run(fn, name, cat) { let startTime: [number, number]; return Promise.resolve() .then(() => { startTime = process.hrtime(); }) .then(() => fn()) .then(value => { const duration = process.hrtime(startTime); // Trace Event Format documentation: // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview const event: ProfilerEvent = { name, cat, ph: 'X', ts: hrtimeToMicroseconds(startTime), pid: 1, tid: 0, dur: hrtimeToMicroseconds(duration), }; events.push(event); return value; }); }, }; } function hrtimeToMicroseconds(hrtime: any) { return (hrtime[0] * 1e9 + hrtime[1]) / 1000; } ================================================ FILE: packages/utils/plugins-helpers/src/resolve-external-module-and-fn.ts ================================================ import { createRequire } from 'module'; import { cwd } from 'process'; import * as changeCaseAll from 'change-case-all'; export function resolveExternalModuleAndFn(pointer: any): any { if (typeof pointer === 'function') { return pointer; } let [moduleName, functionName] = pointer.split('#'); // Temp workaround until v2 if (moduleName === 'change-case') { moduleName = 'change-case-all'; } let loadedModule: any; if (moduleName === 'change-case-all') { loadedModule = changeCaseAll; } else { // we have to use a path to a filename here (it does not need to exist.) // https://github.com/dotansimha/graphql-code-generator/issues/6553 const cwdRequire = createRequire(cwd() + '/index.js'); loadedModule = cwdRequire(moduleName); if (!(functionName in loadedModule) && typeof loadedModule !== 'function') { throw new Error(`${functionName} couldn't be found in module ${moduleName}!`); } } return loadedModule[functionName] || loadedModule; } ================================================ FILE: packages/utils/plugins-helpers/src/types.ts ================================================ import type { ApolloEngineOptions } from '@graphql-tools/apollo-engine-loader'; import { Source } from '@graphql-tools/utils'; import { DocumentNode, GraphQLSchema } from 'graphql'; import type { Profiler } from './profiler.js'; export namespace Types { export interface GenerateOptions { filename: string; plugins: Types.ConfiguredPlugin[]; // TODO: Remove schemaAst and change schema to GraphQLSchema in the next major version schema: DocumentNode; schemaAst?: GraphQLSchema; documents: Types.DocumentFile[]; config: { [key: string]: any }; pluginMap: { [name: string]: CodegenPlugin; }; skipDocumentsValidation?: Types.SkipDocumentsValidationOptions; pluginContext?: { [key: string]: any }; profiler?: Profiler; cache?(namespace: string, key: string, factory: () => Promise): Promise; documentTransforms?: ConfiguredDocumentTransform[]; emitLegacyCommonJSImports?: boolean; importExtension?: '' | `.${string}`; } export type FileOutput = { filename: string; content: string; hooks?: { beforeOneFileWrite?: LifecycleHooksDefinition['beforeOneFileWrite']; afterOneFileWrite?: LifecycleHooksDefinition['afterOneFileWrite']; }; }; export interface DocumentFile extends Source { hash?: string; } /* Utils */ export type Promisable = T | Promise; export type InstanceOrArray = T | T[]; /** * @additionalProperties false * @description Loads schema using a pointer, with a custom loader (code file). */ export interface SchemaWithLoaderOptions { /** * @description Specify a path to a custom code file (local or module) that will handle the schema loading. */ loader: string; } export interface SchemaWithLoader { [pointer: string]: SchemaWithLoaderOptions; } /** * @additionalProperties false * @description Loads schema using a pointer, without using `require` while looking for schemas in code files. */ export interface SchemaFromCodeFileOptions { /** * @description Set this to `true` in order to tell codegen not to try to `require` files in order to find schema/docs */ noRequire?: boolean; /** * @description Set this to `true` in order to tell codegen not to try to extract GraphQL AST strings schema/docs */ noPluck?: boolean; /** * @description Set this to `true` in order to tell codegen to skip documents validation. */ assumeValid?: boolean; } export interface SchemaFromCodeFile { [path: string]: SchemaFromCodeFileOptions; } /** * @description A function to use for fetching the schema. * @see fetch */ export type CustomSchemaFetcher = (url: string, options?: RequestInit) => Promise; /** * @additionalProperties false * @description Loads a schema from remote endpoint, with custom http options. */ export interface UrlSchemaOptions { /** * @description HTTP headers you wish to add to the HTTP request sent by codegen to fetch your GraphQL remote schema. */ headers?: { [headerName: string]: string }; /** * @description Specify a Node module name, a custom file, or a function, to be used instead of a standard `fetch`. */ customFetch?: string | CustomSchemaFetcher; /** * @description HTTP Method to use, either POST (default) or GET. */ method?: string; /** * @description Handling the response as SDL will allow you to load schema from remote server that doesn't return a JSON introspection. */ handleAsSDL?: boolean; } export interface UrlSchemaWithOptions { [url: string]: UrlSchemaOptions; } /** * @additionalProperties false * @description Loads a schema a local file or files, with customized options for parsing/loading. */ export interface LocalSchemaPathOptions { /** * @description Skips checks for graphql-import syntax and loads the file as-is, without imports support. * @default true */ skipGraphQLImport?: boolean; /** * @description Converts all GraphQL comments (`#` sign) to descriptions during the parse phase, to make it available * for plugins later. * @default false */ commentDescriptions?: boolean; /** * Set to true to assume the SDL is valid. * * @default false */ assumeValidSDL?: boolean; /** * By default, the parser creates AST nodes that know the location * in the source that they correspond to. This configuration flag * disables that behavior for performance or testing. * * @default false */ noLocation?: boolean; /** * If enabled, the parser will parse empty fields sets in the Schema * Definition Language. Otherwise, the parser will follow the current * specification. * * This option is provided to ease adoption of the final SDL specification * and will be removed in v16. * * @default false */ allowLegacySDLEmptyFields?: boolean; /** * If enabled, the parser will parse implemented interfaces with no `&` * character between each interface. Otherwise, the parser will follow the * current specification. * * This option is provided to ease adoption of the final SDL specification * and will be removed in v16. * * @default false */ allowLegacySDLImplementsInterfaces?: boolean; /** * EXPERIMENTAL: * * If enabled, the parser will understand and parse variable definitions * contained in a fragment definition. They'll be represented in the * `variableDefinitions` field of the FragmentDefinitionNode. * * The syntax is identical to normal, query-defined variables. For example: * * fragment A($var: Boolean = false) on T { * ... * } * * Note: this feature is experimental and may change or be removed in the * future. * * @default false */ experimentalFragmentVariables?: boolean; } export interface LocalSchemaPathWithOptions { [globPath: string]: LocalSchemaPathOptions; } export interface ApolloEngineSchemaOptions { 'apollo-engine': ApolloEngineOptions; } export interface GitHubSchemaOptions { [githubProtocol: string]: { token: string }; } export type SchemaGlobPath = string; /** * @description A URL to your GraphQL endpoint, a local path to `.graphql` file, a glob pattern to your GraphQL schema files, or a JavaScript file that exports the schema to generate code from. This can also be an array which specifies multiple schemas to generate code from. You can read more about the supported formats [here](schema-field#available-formats). */ export type Schema = | string | UrlSchemaWithOptions | ApolloEngineSchemaOptions | GitHubSchemaOptions | LocalSchemaPathWithOptions | SchemaGlobPath | SchemaWithLoader | SchemaFromCodeFile | GraphQLSchema; /* Document Definitions */ export type OperationDocumentGlobPath = string; /** * @additionalProperties false * @description Specify a path to a custom loader for your GraphQL documents. */ export interface CustomDocumentLoaderOptions { /** * @description Specify a path to a custom code file (local or module) that will handle the documents loading. */ loader: string; } export interface CustomDocumentLoader { [path: string]: CustomDocumentLoaderOptions; } export type OperationDocument = OperationDocumentGlobPath | CustomDocumentLoader; /* Plugin Definition */ export type PluginConfig = { [key: string]: T }; export interface ConfiguredPlugin { [name: string]: PluginConfig; } export type NamedPlugin = string; /* Output Definition */ export type NamedPreset = string; export type OutputConfig = NamedPlugin | ConfiguredPlugin; export type PresetNamesBase = | 'client' | 'near-operation-file' | 'gql-tag-operations' | 'graphql-modules' | 'import-types'; export type PresetNames = `${PresetNamesBase}-preset` | PresetNamesBase; /** * @additionalProperties false */ export interface ConfiguredOutput { /** * @type array * @items { "$ref": "#/definitions/GeneratedPluginsMap" } * @description List of plugins to apply to this current output file. * * You can either specify plugins from the community using the NPM package name (after you installed it in your project), or you can use a path to a local file for custom plugins. * * You can find a list of available plugins here: https://the-guild.dev/graphql/codegen/docs/plugins/index * Need a custom plugin? read this: https://the-guild.dev/graphql/codegen/docs/custom-codegen/index */ plugins?: OutputConfig[]; /** * @description If your setup uses Preset to have a more dynamic setup and output, set the name of your preset here. * * Presets are a way to have more than one file output, for example: https://the-guild.dev/graphql/codegen/docs/presets/near-operation-file * * You can either specify a preset from the community using the NPM package name (after you installed it in your project), or you can use a path to a local file for a custom preset. * * List of available presets: https://graphql-code-generator.com/docs/presets/presets-index */ preset?: PresetNames | OutputPreset; /** * @description If your setup uses Preset to have a more dynamic setup and output, set the configuration object of your preset here. * * List of available presets: https://graphql-code-generator.com/docs/presets/presets-index */ presetConfig?: { [key: string]: any }; /** * @description A flag to overwrite files if they already exist when generating code (`true` by default). * * For more details: https://graphql-code-generator.com/docs/config-reference/codegen-config */ overwrite?: boolean; /** * @description A pointer(s) to your GraphQL documents: query, mutation, subscription and fragment. These documents will be loaded into for all your output files. * You can use one of the following: * * - Path to a local `.graphql` file * - Path to a code file (for example: `.js` or `.tsx`) containing GraphQL operation strings. * - Glob expression pointing to multiple `.graphql` files * - Glob expression pointing to multiple code files * - Inline string containing GraphQL SDL operation definition * * You can specify either a single file, or multiple. * * For more details: https://graphql-code-generator.com/docs/config-reference/documents-field */ documents?: InstanceOrArray; /** * @description A pointer(s) to your GraphQL schema. This schema will be available only for this specific `generates` record. * You can use one of the following: * * - URL pointing to a GraphQL endpoint * - Path to a local `.json` file * - Path to a local `.graphql` file * - Glob expression pointing to multiple `.graphql` files * - Path to a local code file (for example: `.js`) that exports `GraphQLSchema` object * - Inline string containing GraphQL SDL schema definition * * You can specify either a single schema, or multiple, and GraphQL Code Generator will merge the schemas into a single schema. * * For more details: https://graphql-code-generator.com/docs/config-reference/schema-field */ schema?: InstanceOrArray; /** * @description Configuration object containing key => value that will be passed to the plugins. * Specifying configuration in this level of your configuration file will pass it to all plugins, in all outputs. * * The options may vary depends on what plugins you are using. * * For more details: https://graphql-code-generator.com/docs/config-reference/config-field */ config?: PluginConfig; /** * @description Specifies scripts to run when events are happening in the codegen core. * Hooks defined on that level will effect only the current output files. * * For more details: https://graphql-code-generator.com/docs/config-reference/lifecycle-hooks */ hooks?: Partial; /** * @description DocumentTransform changes documents before executing plugins. */ documentTransforms?: OutputDocumentTransform[]; /** * @description: Additional file pattern to watch when using watch mode */ watchPattern?: string | string[]; } /* Output Builder Preset */ export type PresetFnArgs< Config = any, PluginConfig = { [key: string]: any; } > = { presetConfig: Config; baseOutputDir: string; plugins: Types.ConfiguredPlugin[]; schema: DocumentNode; schemaAst?: GraphQLSchema; documents: Types.DocumentFile[]; config: PluginConfig; pluginMap: { [name: string]: CodegenPlugin; }; pluginContext?: { [name: string]: any; }; profiler?: Profiler; cache?(namespace: string, key: string, factory: () => Promise): Promise; documentTransforms?: ConfiguredDocumentTransform[]; }; export type OutputPreset = { buildGeneratesSection: (options: PresetFnArgs) => Promisable; prepareDocuments?: ( outputFilePath: string, outputSpecificDocuments: Types.OperationDocument[] ) => Promisable; }; /* Require Extensions */ export type RequireExtension = InstanceOrArray; /* PackageLoaderFn Loader */ export type PackageLoaderFn = (name: string) => Promisable; /** * @description Represents the root YAML schema for the config file. * @additionalProperties false */ export interface Config { /** * @description A pointer(s) to your GraphQL schema. This schema will be the base schema for all your outputs. * You can use one of the following: * * - URL pointing to a GraphQL endpoint * - Path to a local `.json` file * - Path to a local `.graphql` file * - Glob expression pointing to multiple `.graphql` files * - Path to a local code file (for example: `.js`) that exports `GraphQLSchema` object * - Inline string containing GraphQL SDL schema definition * * You can specify either a single schema, or multiple, and GraphQL Code Generator will merge the schemas into a single schema. * * For more details: https://graphql-code-generator.com/docs/config-reference/schema-field */ schema?: InstanceOrArray; /** * @description A path to a file which defines custom Node.JS require() handlers for custom file extensions. * This is essential if the code generator has to go through files which require other files in an unsupported format (by default). * * For more details: https://graphql-code-generator.com/docs/config-reference/require-field * See more information about require.extensions: https://gist.github.com/jamestalmage/df922691475cff66c7e6. * * Note: values that specified in your .yml file will get loaded after loading the config .yml file. */ require?: RequireExtension; /** * @description Specify a Node module name, a custom file, or a function, to be used instead of a standard `fetch`. */ customFetch?: string | CustomSchemaFetcher; /** * @description A pointer(s) to your GraphQL documents: query, mutation, subscription and fragment. These documents will be loaded into for all your output files. * You can use one of the following: * * - Path to a local `.graphql` file * - Path to a code file (for example: `.js` or `.tsx`) containing GraphQL operation strings. * - Glob expression pointing to multiple `.graphql` files * - Glob expression pointing to multiple code files * - Inline string containing GraphQL SDL operation definition * * You can specify either a single file, or multiple. * * For more details: https://graphql-code-generator.com/docs/config-reference/documents-field */ documents?: InstanceOrArray; /** * @type object * @additionalProperties true * @description Configuration object containing key => value that will be passed to the plugins. * Specifying configuration in this level of your configuration file will pass it to all plugins, in all outputs. * * The options may vary depends on what plugins you are using. * * For more details: https://graphql-code-generator.com/docs/config-reference/config-field */ config?: PluginConfig; /** * @description A map where the key represents an output path for the generated code and the value represents a set of options which are relevant for that specific file. * * For more details: https://graphql-code-generator.com/docs/config-reference/codegen-config */ generates: { [outputPath: string]: ConfiguredOutput | ConfiguredPlugin[]; }; /** * @description A flag to overwrite files if they already exist when generating code (`true` by default). * * For more details: https://graphql-code-generator.com/docs/config-reference/codegen-config */ overwrite?: boolean; /** * @description A flag to trigger codegen when there are changes in the specified GraphQL schemas. * * You can either specify a boolean to turn it on/off or specify an array of glob patterns to add custom files to the watch. * * For more details: https://graphql-code-generator.com/docs/getting-started/development-workflow#watch-mode */ watch?: boolean | string | string[]; /** * @description A flag to suppress non-zero exit code when there are no documents to generate. */ ignoreNoDocuments?: boolean; /** * @deprecated Please use `importExtension` instead. * @description A flag to disable adding `.js` extension to the output file. Default: `true`. */ emitLegacyCommonJSImports?: boolean; /** * @description Append this extension to all imports. * Useful for ESM environments that require file extensions in import statements. */ importExtension?: '' | `.${string}`; /** * @description A flag to suppress printing errors when they occur. */ silent?: boolean; /** * @description A flag to output more detailed information about tasks */ verbose?: boolean; /** * @description A flag to output debug logs */ debug?: boolean; /** * @description A flag to print only errors. */ errorsOnly?: boolean; /** * @description If you are using the programmatic API in a browser environment, you can override this configuration to load your plugins in a way different than require. */ pluginLoader?: PackageLoaderFn; /** * @description Additional context passed to plugins */ pluginContext?: { [key: string]: any }; /** * @description Allows you to override the configuration for `@graphql-tools/graphql-tag-pluck`, the tool that extracts your GraphQL operations from your code files. * * For more details: https://graphql-code-generator.com/docs/config-reference/documents-field#graphql-tag-pluck */ pluckConfig?: { /** * @description An array of package name and identifier that will be used to track down your gql usages and imports. Use this if your code files imports gql from another library or you have a custom gql tag. identifier is the named export, so don't provide it if the tag function is imported as default. */ modules?: Array<{ /** * @description the name of the NPM package name you wish to look for */ name: string; /** * @description the tag identifier name you wish to look for */ identifier?: string; }>; /** * @description Configures the magic GraphQL comments to look for. The default is `GraphQL`. */ gqlMagicComment?: string; /** * @description Overrides the name of the default GraphQL name identifier. */ globalIdentifier?: string; /** * @description Allows to use a global identifier instead of a module import. */ globalGqlIdentifierName?: string | string[]; }; /** * @description Specifies scripts to run when events are happening in the codegen core. * Hooks defined on that level will effect all output files. * * For more details: https://graphql-code-generator.com/docs/config-reference/lifecycle-hooks */ hooks?: Partial; /** * @description Alows to raise errors if any matched files are not valid GraphQL. Default: false. */ noSilentErrors?: boolean; /** * @description If `true`, write to files whichever `generates` block succeeds. If `false`, one failed `generates` means no output is written to files. Default: false */ allowPartialOutputs?: boolean; } export type ComplexPluginOutput> = { content: string; prepend?: string[]; append?: string[]; meta?: M; }; export type PluginOutput = string | ComplexPluginOutput; export type HookFunction = (...args: any[]) => void | Promise; export type HookAlterFunction = (...args: any[]) => void | string | Promise; export type LifeCycleHookValue = string | HookFunction | (string | HookFunction)[]; export type LifeCycleAlterHookValue = | string | HookFunction | HookAlterFunction | (string | HookFunction | HookAlterFunction)[]; /** * @description All available lifecycle hooks * @additionalProperties false */ export type LifecycleHooksDefinition = { /** * @description Triggered with no arguments when the codegen starts (after the `codegen.yml` has beed parsed). * * Specify a shell command to run. */ afterStart: LifeCycleHookValue; /** * @description Triggered with no arguments, right before the codegen closes, or when watch mode is stopped. * * Specify a shell command to run. */ beforeDone: LifeCycleHookValue; /** * @description Triggered every time a file changes when using watch mode. * Triggered with two arguments: the type of the event (for example, `changed`) and the path of the file. */ onWatchTriggered: LifeCycleHookValue; /** * @description Triggered in case of a general error in the codegen. The argument is a string containing the error. */ onError: LifeCycleHookValue; /** * @description Triggered after a file is written to the file-system. Executed with the path for the file. * If the content of the file hasn't changed since last execution - this hooks won't be triggered. * * > This is a very useful hook, you can use it for integration with Prettier or other linters. */ afterOneFileWrite: LifeCycleHookValue; /** * @description Executed after writing all the files to the file-system. * Triggered with multiple arguments - paths for all files. */ afterAllFileWrite: LifeCycleHookValue; /** * @description Triggered before a file is written to the file-system. * Executed with the path and content for the file. * * Returning a string will override the content of the file. * * If the content of the file hasn't changed since last execution - this hooks won't be triggered. */ beforeOneFileWrite: LifeCycleAlterHookValue; /** * @description Executed after the codegen has done creating the output and before writing the files to the file-system. * * Triggered with multiple arguments - paths for all relevant files. * * > Not all the files will be actually written to the file-system, because this is triggered before checking if the file has changed since last execution. */ beforeAllFileWrite: LifeCycleHookValue; }; export type SkipDocumentsValidationOptions = | { /** * @description Allows you to skip specific rules while validating the documents. * See all the rules; https://github.com/graphql/graphql-js/tree/main/src/validation/rules */ ignoreRules?: string[]; /** * @description Ignore duplicate documents validation */ skipDuplicateValidation?: boolean; /** * @description Skip document validation entirely against the schema */ skipValidationAgainstSchema?: boolean; } | boolean; export type DocumentTransformFunction = (options: { documents: Types.DocumentFile[]; schema: DocumentNode; config: Config; pluginContext?: { [key: string]: any }; }) => Types.Promisable; export type DocumentTransformObject = { transform: DocumentTransformFunction; }; export type DocumentTransformFileName = string; export type DocumentTransformFileConfig = { [name: DocumentTransformFileName]: T }; export type DocumentTransformFile = DocumentTransformFileName | DocumentTransformFileConfig; export type OutputDocumentTransform = DocumentTransformObject | DocumentTransformFile; export type ConfiguredDocumentTransform = { name: string; transformObject: DocumentTransformObject; config?: T; }; } export function isComplexPluginOutput(obj: Types.PluginOutput): obj is Types.ComplexPluginOutput { return typeof obj === 'object' && Object.prototype.hasOwnProperty.call(obj, 'content'); } export type PluginFunction = ( schema: GraphQLSchema, documents: Types.DocumentFile[], config: T, info?: { outputFile?: string; allPlugins?: Types.ConfiguredPlugin[]; pluginContext?: { [key: string]: any }; [key: string]: any; } ) => Types.Promisable; export type PluginValidateFn = ( schema: GraphQLSchema, documents: Types.DocumentFile[], config: T, outputFile: string, allPlugins: Types.ConfiguredPlugin[], pluginContext?: { [key: string]: any } ) => Types.Promisable; export type AddToSchemaResult = string | DocumentNode | undefined; export interface CodegenPlugin { plugin: PluginFunction; addToSchema?: AddToSchemaResult | ((config: T) => AddToSchemaResult); validate?: PluginValidateFn; } ================================================ FILE: packages/utils/plugins-helpers/src/typings.d.ts ================================================ declare module 'import-from'; ================================================ FILE: packages/utils/plugins-helpers/src/utils.ts ================================================ import { GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLOutputType, isListType, isNonNullType } from 'graphql'; import { Types } from './types.js'; export function mergeOutputs(content: Types.PluginOutput | Array): string { const result: Types.ComplexPluginOutput = { content: '', prepend: [], append: [] }; if (Array.isArray(content)) { for (const item of content) { if (typeof item === 'string') { result.content += item; } else { result.content += item.content; result.prepend.push(...(item.prepend || [])); result.append.push(...(item.append || [])); } } } return [...result.prepend, result.content, ...result.append].join('\n'); } export function isWrapperType(t: GraphQLOutputType): t is GraphQLNonNull | GraphQLList { return isListType(t) || isNonNullType(t); } export function getBaseType(type: GraphQLOutputType): GraphQLNamedType { if (isWrapperType(type)) { return getBaseType(type.ofType); } return type; } export function removeNonNullWrapper(type: GraphQLOutputType): GraphQLOutputType { return isNonNullType(type) ? type.ofType : type; } ================================================ FILE: packages/utils/plugins-helpers/tests/fixtures/externalModuleFn.js ================================================ export const test = 'foobar'; ================================================ FILE: packages/utils/plugins-helpers/tests/is-using-types.spec.ts ================================================ import { buildSchema, parse } from 'graphql'; import { isUsingTypes } from '../src/helpers.js'; describe('isUsingTypes', () => { describe('Issues', () => { it('#3248 - error on missing field on type', () => { const schema = buildSchema(/* GraphQL */ ` scalar ObjectId type UserTypeA { _id: ObjectId! } type UserTypeB { _id: ObjectId! } union User = UserTypeA | UserTypeB interface Request { _id: ObjectId! foo: User barRequired: User! } type ARequest implements Request { _id: ObjectId! foo: User barRequired: User! } type BRequest implements Request { _id: ObjectId! foo: User barRequired: User! } type Query { allRequests: [Request!]! nodes: [Node!]! } interface Node { id: ID! s: NodeSelection } type NodeSelection { foo: String } type A implements Node { id: ID! s: NodeSelection a: String b: AInner } type AInner { id: ID! inner: AInner2 } type AInner2 { f: String } `); const ast = parse(/* GraphQL */ ` query AllRequests { nodes { id s { foo } ... on A { a b { id inner { f } } } } allRequests { _id foo { ... on UserTypeA { _id } ... on UserTypeB { _id } } barRequired { ... on UserTypeA { _id } ... on UserTypeB { _id } } } } `); expect(isUsingTypes(ast, [], schema)).toBeTruthy(); }); it('#3217 - complex selection set causes issues with incorrect parent type', () => { const schema = buildSchema(/* GraphQL */ ` type BrazilianCompany { _id: ID! ratings: [BrazilianCompanyRating!]! chiefExecutiveOfficer: String! financials: BrazilianCompanyFinancials! } type BrazilianCompanyFinancials { template: BrazilianCompanyFinancialsTemplate! } enum BrazilianCompanyFinancialsTemplate { BANK COMPANY INSURER } type GlassdoorRating { linkHref: String! overallRating: Float! reviewsCount: Int! recommendToFriend: Int! dateOfReference: String! } type ReclameAquiRating { linkHref: String! humanReadablePeriod: String classification: String score: Float formattedScore: String } union BrazilianCompanyRating = GlassdoorRating | ReclameAquiRating type Query { assetById(id: String!): Asset } union Asset = BrazilianCompany `); const ast = parse(/* GraphQL */ ` query AssetById($id: String!) { assetById(id: $id) { __typename ... on BrazilianCompany { ...BrazilianCompanyTopLevel } } } fragment BrazilianCompanyTopLevel on BrazilianCompany { _id ratings { ... on ReclameAquiRating { linkHref humanReadablePeriod classification score formattedScore } ... on GlassdoorRating { linkHref overallRating } } chiefExecutiveOfficer financials { template } } `); expect(isUsingTypes(ast, [], schema)).toBeTruthy(); }); }); it('Should work with __typename on fragments', () => { const schema = buildSchema(/* GraphQL */ ` type Query { user(id: ID!): User! } type User { id: ID! username: String! email: String! } `); const ast = parse(/* GraphQL */ ` fragment User on User { __typename } `); expect(isUsingTypes(ast, [], schema)).toBeFalsy(); }); it('Should include fragments when they are not extenral', () => { const ast = parse(/* GraphQL */ ` fragment UserFields on User { id } query user { ...UserFields } `); expect(isUsingTypes(ast, [], null)).toBeTruthy(); }); it('Should ignore fragments when they are extenral', () => { const ast = parse(/* GraphQL */ ` fragment UserFields on User { id } query user { ...UserFields } `); expect(isUsingTypes(ast, ['UserFields'], null)).toBeFalsy(); }); it('Should includes types import when fragment spread is used over an optional field', () => { const schema = buildSchema(/* GraphQL */ ` interface Node { id: ID! } type User implements Node { id: ID! login: String! name: String } type Query { user: User } `); const ast = parse(/* GraphQL */ ` query getUser { user { ...user } } fragment user on User { id } `); expect(isUsingTypes(ast, ['user'], schema)).toBeTruthy(); }); it('Should includes types correctly', () => { const schema = buildSchema(/* GraphQL */ ` type User { id: ID! profile: Profile } type Profile { name: String } type Query { user: User } `); const ast = parse(/* GraphQL */ ` query getUser { user { id profile { name } } } `); expect(isUsingTypes(ast, ['user'], schema)).toBeTruthy(); }); it('Should includes types correctly when used in fragment', () => { const schema = buildSchema(/* GraphQL */ ` interface Node { id: ID! } type User implements Node { id: ID! login: String! name: String pictures(limit: Int!): PictureConnection! } type PictureConnection { nodes: [Picture]! } type Picture { size: Int! url: String! } type Query { user: User } `); const ast = parse(/* GraphQL */ ` fragment pictures on User { pictures(limit: 10) { nodes { ...picture } } } fragment picture on Picture { size url } `); expect(isUsingTypes(ast, ['picture'], schema)).toBeTruthy(); }); }); ================================================ FILE: packages/utils/plugins-helpers/tests/resolve-external-module-and-fn.spec.ts ================================================ import path from 'path'; import { resolveExternalModuleAndFn } from '../src/resolve-external-module-and-fn.js'; describe('resolveExternalModuleAndFn', () => { describe('Issues', () => { it('#6553 - Cannot find module', () => { const relativePathToSelf = path.relative(process.cwd(), path.join(__dirname, './fixtures/externalModuleFn.js')); expect(resolveExternalModuleAndFn('./' + relativePathToSelf + '#test')).toBe('foobar'); }); }); }); ================================================ FILE: packages/utils/plugins-helpers/vitest.config.ts ================================================ import { defineProject, mergeConfig } from 'vitest/config'; import { sharedConfig } from '../../../vitest.config.js'; export default mergeConfig( sharedConfig, defineProject({ test: { name: 'plugin-helpers', include: ['**/*.spec.ts'], }, }) ); ================================================ FILE: patches/typescript-json-schema+0.56.0.patch ================================================ diff --git a/node_modules/typescript-json-schema/dist/typescript-json-schema.js b/node_modules/typescript-json-schema/dist/typescript-json-schema.js index d5aa7f7..b5f0978 100644 --- a/node_modules/typescript-json-schema/dist/typescript-json-schema.js +++ b/node_modules/typescript-json-schema/dist/typescript-json-schema.js @@ -302,6 +302,8 @@ var annotationKeywords = { description: true, default: true, examples: true, + // https://github.com/YousefED/typescript-json-schema/issues/431 + exampleMarkdown: true, $ref: true, }; var subDefinitions = { ================================================ FILE: prettier.config.cjs ================================================ /* eslint-disable import/no-extraneous-dependencies */ const { plugins, ...prettierConfig } = require('@theguild/prettier-config'); module.exports = { ...prettierConfig, plugins: [ ...plugins, // `prettier-plugin-svelte` and `svelte` packages used for formatting ```svelte code blocks in md/mdx files require('prettier-plugin-svelte'), // Sort classes in website require('prettier-plugin-tailwindcss'), ], tailwindConfig: './website/tailwind.config.ts', }; ================================================ FILE: renovate.json ================================================ { "extends": ["github>the-guild-org/shared-config:renovate"], "automerge": true, "major": { "automerge": false }, "lockFileMaintenance": { "enabled": true, "automerge": true }, "lockFileMaintenance": { "enabled": true, "automerge": true }, "packageRules": [ { "excludePackagePatterns": [ "@changesets/*", "typescript", "^@theguild/", "next", "tailwindcss", "@whatwg-node/*", "graphql-jit", "husky", "@types/lz-string", "swc*" ], "matchPackagePatterns": ["*"], "matchUpdateTypes": ["minor", "patch"], "groupName": "all non-major dependencies", "groupSlug": "all-minor-patch" } ] } ================================================ FILE: scripts/fix-bin.js ================================================ /* eslint-disable import/no-extraneous-dependencies */ // @ts-check const fs = require('fs-extra'); const path = require('path'); const fg = require('fast-glob'); const absoluteBinPath = path.resolve(__dirname, '../packages/graphql-codegen-cli/dist/cjs/bin.js'); const packageDirectories = fg .sync(['examples/**/package.json'], { ignore: ['**/node_modules/**'] }) .map(p => path.dirname(p)); packageDirectories.push('website'); for (const dirname of packageDirectories) { const absolutePath = path.join(__dirname, '..', dirname); if (fs.lstatSync(absolutePath).isDirectory()) { const execNames = ['graphql-codegen', 'graphql-codegen-esm']; for (const execName of execNames) { const targetPath = path.join(absolutePath, 'node_modules', '.bin', execName); try { fs.ensureSymlinkSync(absoluteBinPath, targetPath); fs.chmodSync(targetPath, '755'); const targetCmdPath = targetPath + '.cmd'; fs.writeFileSync( targetCmdPath, ` @IF EXIST "%~dp0\\node.exe" ( "%~dp0\\node.exe" "${absoluteBinPath}" %* ) ELSE ( @SETLOCAL @SET PATHEXT=%PATHEXT:;.JS;=;% node "${absoluteBinPath}" %* ) ` ); fs.chmodSync(targetCmdPath, '755'); } catch { /* ignore symlink that already exist */ } } } } ================================================ FILE: scripts/match-graphql.js ================================================ const { writeFileSync } = require('fs'); const { resolve } = require('path'); const { argv, cwd } = require('process'); const pkgPath = resolve(cwd(), './package.json'); const pkg = require(pkgPath); const version = argv[2]; pkg.resolutions ||= {}; if (pkg.devDependencies.graphql?.startsWith(version)) { // eslint-disable-next-line no-console console.info(`GraphQL v${version} is match! Skipping.`); return; } const npmVersion = version.includes('-') ? version : `^${version}`; pkg.devDependencies.graphql = npmVersion; pkg.resolutions.graphql = npmVersion; writeFileSync(pkgPath, JSON.stringify(pkg, null, 2), 'utf8'); ================================================ FILE: scripts/print-example-ci-command.js ================================================ /* eslint-disable import/no-extraneous-dependencies, no-console */ const fs = require('fs-extra'); const fg = require('fast-glob'); const packageJSON = fg.sync(['examples/**/package.json'], { ignore: ['**/node_modules/**'] }); const ignoredPackages = []; const exampleTypeMap = { all: 'all', swc: 'swc', normal: 'normal', }; const exampleType = exampleTypeMap[process.env.EXAMPLE_TYPE] || 'all'; const result = packageJSON.reduce( (res, packageJSONPath) => { const { name, devDependencies } = fs.readJSONSync(packageJSONPath); if (ignoredPackages.includes(name)) { res.ignored.push(name); return res; } if ( (exampleType === 'swc' && !devDependencies['@graphql-codegen/client-preset-swc-plugin']) || (exampleType === 'normal' && devDependencies['@graphql-codegen/client-preset-swc-plugin']) ) { res.ignored.push(name); return res; } res.commands.push(`yarn workspace ${name} run ${process.argv[2]}`); return res; }, { ignored: [], commands: [] } ); if (result.ignored.length > 0) { result.commands.push(`echo "Ignored packages: ${result.ignored.join(',')}"`); } console.log(result.commands.join(' && ')); ================================================ FILE: tsconfig.json ================================================ { "compilerOptions": { "incremental": true, "baseUrl": ".", "outDir": "dist", "rootDir": "packages", "esModuleInterop": true, "allowSyntheticDefaultImports": true, "importHelpers": true, "experimentalDecorators": true, "module": "esnext", "target": "es2022", "lib": ["es6", "esnext", "es2023", "dom"], "moduleResolution": "node", "emitDecoratorMetadata": true, "sourceMap": true, "declaration": true, "noImplicitThis": true, "alwaysStrict": true, "noImplicitReturns": true, "noUnusedLocals": true, "resolveJsonModule": true, "skipLibCheck": true, "paths": { "@graphql-codegen/cli": ["packages/graphql-codegen-cli/src/index.ts"], "@graphql-codegen/core": ["packages/graphql-codegen-core/src/index.ts"], "@graphql-codegen/add": ["packages/plugins/other/add/src/index.ts"], "@graphql-codegen/fragment-matcher": ["packages/plugins/other/fragment-matcher/src/index.ts"], "@graphql-codegen/introspection": ["packages/plugins/other/introspection/src/index.ts"], "@graphql-codegen/schema-ast": ["packages/plugins/other/schema-ast/src/index.ts"], "@graphql-codegen/time": ["packages/plugins/other/time/src/index.ts"], "@graphql-codegen/visitor-plugin-common": ["packages/plugins/other/visitor-plugin-common/src/index.ts"], "@graphql-codegen/typescript-document-nodes": ["packages/plugins/typescript/document-nodes/src/index.ts"], "@graphql-codegen/typescript-operations": ["packages/plugins/typescript/operations/src/index.ts"], "@graphql-codegen/typescript-resolvers": ["packages/plugins/typescript/resolvers/src/index.ts"], "@graphql-codegen/typed-document-node": ["packages/plugins/typescript/typed-document-node/src/index.ts"], "@graphql-codegen/gql-tag-operations": ["packages/plugins/typescript/gql-tag-operations/src/index.ts"], "@graphql-codegen/typescript": ["packages/plugins/typescript/typescript/src/index.ts"], "@graphql-codegen/testing": ["packages/utils/graphql-codegen-testing/src/index.ts"], "@graphql-codegen/plugin-helpers": ["packages/utils/plugins-helpers/src/index.ts"] } }, "include": ["packages"], "exclude": [ "**/dist", "**/temp", "**/vitest.config.ts", "**/vitest.setup.ts", "**/*.spec.ts", "**/tests/**/*.ts", "**/tests/test-files", "**/tests/test-documents" ], "references": [ { "path": "./tsconfig.spec.json" } ] } ================================================ FILE: tsconfig.spec.json ================================================ { "extends": "./tsconfig.json", "compilerOptions": { "rootDir": ".", "composite": true, "types": ["vitest/globals"] }, "exclude": [], "include": [ "**/vitest.config.ts", "**/vitest.setup.ts", "**/*.spec.ts", "**/tests/**/*.ts", "**/tests/test-files", "**/tests/test-documents" ] } ================================================ FILE: vitest.config.ts ================================================ import { defineConfig } from 'vitest/config'; import tsconfigPaths from 'vite-tsconfig-paths'; export const sharedConfig = defineConfig({ plugins: [tsconfigPaths() as any], resolve: { alias: { graphql: 'graphql/index.js', }, }, test: { globals: true, }, }); export default defineConfig({ test: { projects: ['packages/**/vitest.config.ts', 'examples/**/vitest.config.ts'], watch: false, }, }); ================================================ FILE: website/.gitignore ================================================ # NPM packages info fetched before building. # Without this, every page build process will hit NPM and may get rate limited. # Run `yarn generate-packages-info` to regenerate. src/lib/packages-info.generated.ts ================================================ FILE: website/README.md ================================================ # Website This website is built using NextJS ## Installation Run `yarn` from the root directory ## Building the app Run `yarn build` from the root directory ## Local Development ```sh yarn dev ``` This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. ================================================ FILE: website/next-env.d.ts ================================================ /// /// // NOTE: This file should not be edited // see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. ================================================ FILE: website/next-sitemap.config.js ================================================ /** @type {import('next-sitemap').IConfig} */ export default { siteUrl: process.env.SITE_URL || 'https://the-guild.dev/graphql/codegen', generateIndexSitemap: false, exclude: ['*/_meta'], output: 'export', }; ================================================ FILE: website/next.config.js ================================================ import { withGuildDocs } from '@theguild/components/next.config'; import { CategoryToPackages } from './src/category-to-packages.mjs'; const PLUGINS_REDIRECTS = Object.entries(CategoryToPackages).flatMap(([category, packageNames]) => packageNames.map(packageName => [`/plugins/${packageName}`, `/plugins/${category}/${packageName}`]) ); export default withGuildDocs({ nextraConfig: { autoImportThemeStyle: false, }, output: 'export', experimental: { urlImports: [ 'https://graphql-modules.com/assets/subheader-logo.svg', 'https://pbs.twimg.com/profile_images/1004185780313395200/ImZxrDWf_400x400.jpg', 'https://raw.githubusercontent.com/mswjs/msw/HEAD/media/msw-logo.svg', ], }, typescript: { // Todo: remove it before merge to master ignoreBuildErrors: true, }, webpack(config, meta) { config.resolve.fallback = { ...config.resolve.fallback, module: false, }; return config; }, redirects: () => Object.entries({ '/live-demo': '/', '/docs/presets/presets-index': '/plugins', '/docs/guides': '/docs/guides/react', '/docs/plugins/typescript-server': '/plugins/typescript/typescript-resolvers', '/docs/react': '/docs/guides/react', '/docs/guides/react-vue-angular': '/docs/guides/react-vue', '/docs/guides/front-end-typescript-only': '/docs/guides/react-vue', '/plugins/other': '/plugins', '/plugins/c-sharp': '/plugins/c-sharp/c-sharp-operations', '/docs/integrations': '/plugins', '/docs/advanced': '/docs/advanced/generated-files-colocation', '/plugins/java-installation': '/plugins/java/java', '/docs/plugins/c-sharp': '/plugins/c-sharp/c-sharp-operations', '/plugins/dart/flutter': '/plugins/dart/flutter-freezed', '/docs/getting-started/programmatic-usage': '/docs/advanced/programmatic-usage', '/docs/tags': '/docs/getting-started', '/docs': '/docs/getting-started', '/docs/plugins': '/plugins', '/docs/generated-config/base-documents-visitor': '/plugins', '/docs/config-reference': '/docs/config-reference/codegen-config', '/docs/config-reference/': '/docs/config-reference/codegen-config', '/plugins/flow': '/plugins/flow/flow-operations', '/plugins/typescript-common': '/plugins/typescript/typescript', '/plugins/other/typescript-operations': '/plugins/typescript/typescript-operations', '/plugins/typescript-urql-graphcache': '/plugins/typescript/typescript-urql', '/plugins/typescript/typescript-urql-graphcache': '/plugins/typescript/typescript-urql', '/docs/generated-config/:presetName-preset': '/plugins/:presetName-preset', '/docs/generated-config/:pluginName': '/plugins/:pluginName', '/docs/custom-codegen/write-your-plugin': '/docs/custom-codegen', '/plugins/typescript': '/plugins/typescript/typescript', '/docs/plugins/typescript-common': '/plugins/typescript/typescript', '/docs/presets/:presetName': '/plugins/:presetName-preset', '/docs/plugins/:pluginName': '/plugins/:pluginName', '/docs/plugins/client-note': '/plugins', '/docs/getting-started/config-reference/codegen-config': '/docs/config-reference/codegen-config', '/docs/getting-started/codegen-config': '/docs/config-reference/codegen-config', '/docs/getting-started/documents-field': '/docs/config-reference/documents-field', '/docs/getting-started/schema-field': '/docs/config-reference/schema-field', '/docs/getting-started/config-field': '/docs/config-reference/config-field', '/docs/getting-started/lifecycle-hooks': '/docs/config-reference/lifecycle-hooks', '/docs/getting-started/require-field': '/docs/config-reference/require-field', '/docs/getting-started/naming-convention': '/docs/config-reference/naming-convention', '/docs/getting-started/how-does-it-work': '/docs/advanced/how-does-it-work', '/docs/guides/react': '/docs/guides/react-vue', '/docs/guides/vue': '/docs/guides/react-vue', '/plugins/typescript-svelte-urql': '/plugins', '/plugins/presets': '/plugins', '/docs/getting-startedinstallation': '/docs/getting-started', '/docs/plugins/typescript-graphql-requesttypescript-graphql-request': '/plugins/typescript/typescript-graphql-request', '/plugins/typescript/fragment-matcher': '/plugins/other/fragment-matcher', '/plugins/core': '/plugins', '/plugins/dart': '/plugins', '/docs/presets': '/plugins', '/home': '/', '/plugins/presets/client': '/docs/guides/react-vue', '/plugins/presets/client-preset': '/docs/guides/react-vue', '/plugins/typescript/add': '/plugins/other/add', '/plugins/typescript/typescript-add': '/plugins/other/add', '/docs/generated-config/base-visitor': '/docs/custom-codegen/using-visitor', '/plugins/base-visitor': '/docs/custom-codegen/using-visitor', '/plugins/typescript/instrospection': '/plugins/other/introspection', '/docs/custom-codegen/using-handlebars': '/docs/custom-codegen', '/plugins/presets/near-operation-file': '/plugins/presets/near-operation-file-preset', '/plugins/typescript/near-operation-file': '/plugins/presets/near-operation-file-preset', '/typescript/typescript-resolvers': '/plugins/typescript/typescript-resolvers', '/docs/guides/graphql-cli': '/docs/migration/graphql-cli', '/plugins/presets/gql-tag-operations-preset': '/plugins/presets/preset-client', '/plugins/gql-tag-operations-preset': '/plugins/presets/preset-client', }) .concat(PLUGINS_REDIRECTS) .map(([from, to]) => ({ source: from, destination: to, permanent: true, })), }); ================================================ FILE: website/package.json ================================================ { "name": "website", "version": "1.17.7", "private": true, "type": "module", "scripts": { "start": "next start", "build": "yarn generate-packages-info && yarn generate-json-config && next build && next-sitemap", "dev": "next", "generate-json-config": "tsx scripts/generate-config-json-schema.ts", "generate-packages-info": "tsx scripts/generate-packages-info.ts" }, "devDependencies": { "@theguild/tailwind-config": "0.6.4", "@types/dedent": "0.7.2", "@types/jsonpath": "0.2.4", "@types/node": "22.10.7", "@types/react": "18.3.3", "fast-xml-parser": "5.4.2", "jsonpath": "1.1.1", "postcss-import": "^16.1.0", "postcss-lightningcss": "^1.0.1", "prettier-plugin-tailwindcss": "0.2.8", "tailwindcss": "^3.4.14", "semver": "7.7.3", "@types/semver": "7.7.1" }, "dependencies": { "@graphql-codegen/add": "6.0.0", "@graphql-codegen/c-sharp": "4.3.1", "@graphql-codegen/c-sharp-operations": "2.3.1", "@graphql-codegen/cli": "6.2.1", "@graphql-codegen/client-preset": "5.2.4", "@graphql-codegen/core": "5.0.1", "@graphql-codegen/flow": "2.3.6", "@graphql-codegen/flow-operations": "2.3.6", "@graphql-codegen/flow-resolvers": "2.4.4", "@graphql-codegen/flutter-freezed": "^3.0.1", "@graphql-codegen/fragment-matcher": "6.0.0", "@graphql-codegen/hasura-allow-list": "2.0.0", "@graphql-codegen/import-types-preset": "2.2.6", "@graphql-codegen/introspection": "5.0.1", "@graphql-codegen/java": "3.3.6", "@graphql-codegen/java-apollo-android": "2.3.6", "@graphql-codegen/java-resolvers": "2.3.6", "@graphql-codegen/jsdoc": "2.3.6", "@graphql-codegen/kotlin": "2.3.6", "@graphql-codegen/named-operations-object": "2.3.1", "@graphql-codegen/near-operation-file-preset": "2.5.0", "@graphql-codegen/schema-ast": "5.0.1", "@graphql-codegen/time": "6.0.0", "@graphql-codegen/typed-document-node": "6.1.7", "@graphql-codegen/typescript": "5.0.9", "@graphql-codegen/typescript-apollo-angular": "3.5.6", "@graphql-codegen/typescript-apollo-client-helpers": "2.2.6", "@graphql-codegen/typescript-generic-sdk": "3.1.0", "@graphql-codegen/typescript-graphql-files-modules": "2.2.1", "@graphql-codegen/typescript-graphql-request": "5.0.0", "@graphql-codegen/typescript-mongodb": "2.4.6", "@graphql-codegen/typescript-msw": "3.0.1", "@graphql-codegen/typescript-nhost": "0.0.3", "@graphql-codegen/typescript-operations": "5.0.9", "@graphql-codegen/typescript-react-apollo": "3.3.7", "@graphql-codegen/typescript-react-query": "4.1.0", "@graphql-codegen/typescript-resolvers": "5.1.7", "@graphql-codegen/typescript-rtk-query": "2.4.1", "@graphql-codegen/typescript-stencil-apollo": "2.3.6", "@graphql-codegen/typescript-type-graphql": "2.3.6", "@graphql-codegen/typescript-urql": "3.7.3", "@graphql-codegen/typescript-vue-apollo": "3.3.7", "@graphql-codegen/typescript-vue-apollo-smart-ops": "2.3.6", "@graphql-codegen/typescript-vue-urql": "2.3.6", "@graphql-codegen/urql-introspection": "2.2.1", "@mizdra/graphql-codegen-typescript-fabbrica": "^0.6.0", "@monaco-editor/react": "4.6.0", "@radix-ui/react-accordion": "^1.2.1", "@radix-ui/react-icons": "^1.3.0", "@theguild/components": "7.6.5", "classnames": "2.5.1", "date-fns": "4.1.0", "dedent": "1.5.3", "graphql": "16.9.0", "js-yaml": "4.1.0", "next": "14.2.35", "next-mdx-remote": "5.0.0", "next-sitemap": "4.2.3", "postcss-nesting": "^13.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-markdown": "9.0.3", "react-select": "5.8.0", "typescript-json-schema": "0.56.0" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ================================================ FILE: website/postcss.config.mjs ================================================ import config from '@theguild/tailwind-config/postcss.config'; export default { ...config, plugins: { ...config.plugins, 'postcss-nesting': {}, }, }; ================================================ FILE: website/public/config.schema.json ================================================ { "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "Types.Config": { "description": "Represents the root YAML schema for the config file.", "additionalProperties": false, "type": "object", "properties": { "schema": { "$ref": "#/definitions/Types.InstanceOrArray", "description": "A pointer(s) to your GraphQL schema. This schema will be the base schema for all your outputs.\nYou can use one of the following:\n\n- URL pointing to a GraphQL endpoint\n- Path to a local `.json` file\n- Path to a local `.graphql` file\n- Glob expression pointing to multiple `.graphql` files\n- Path to a local code file (for example: `.js`) that exports `GraphQLSchema` object\n- Inline string containing GraphQL SDL schema definition\n\nYou can specify either a single schema, or multiple, and GraphQL Code Generator will merge the schemas into a single schema.\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/schema-field" }, "require": { "$ref": "#/definitions/Types.RequireExtension", "description": "A path to a file which defines custom Node.JS require() handlers for custom file extensions.\nThis is essential if the code generator has to go through files which require other files in an unsupported format (by default).\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/require-field\nSee more information about require.extensions: https://gist.github.com/jamestalmage/df922691475cff66c7e6.\n\nNote: values that specified in your .yml file will get loaded after loading the config .yml file." }, "customFetch": { "description": "Specify a Node module name, a custom file, or a function, to be used instead of a standard `fetch`.", "anyOf": [ { "$ref": "#/definitions/Types.CustomSchemaFetcher", "description": "A function to use for fetching the schema." }, { "type": "string" } ] }, "documents": { "$ref": "#/definitions/Types.InstanceOrArray_1", "description": "A pointer(s) to your GraphQL documents: query, mutation, subscription and fragment. These documents will be loaded into for all your output files.\nYou can use one of the following:\n\n- Path to a local `.graphql` file\n- Path to a code file (for example: `.js` or `.tsx`) containing GraphQL operation strings.\n- Glob expression pointing to multiple `.graphql` files\n- Glob expression pointing to multiple code files\n- Inline string containing GraphQL SDL operation definition\n\nYou can specify either a single file, or multiple.\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/documents-field" }, "config": { "type": "object", "additionalProperties": true, "description": "Configuration object containing key => value that will be passed to the plugins.\nSpecifying configuration in this level of your configuration file will pass it to all plugins, in all outputs.\n\nThe options may vary depends on what plugins you are using.\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/config-field" }, "generates": { "description": "A map where the key represents an output path for the generated code and the value represents a set of options which are relevant for that specific file.\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/codegen-config", "type": "object", "additionalProperties": { "anyOf": [ { "type": "array", "items": { "$ref": "#/definitions/Types.ConfiguredPlugin" } }, { "$ref": "#/definitions/Types.ConfiguredOutput" } ] } }, "overwrite": { "description": "A flag to overwrite files if they already exist when generating code (`true` by default).\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/codegen-config", "type": "boolean" }, "watch": { "description": "A flag to trigger codegen when there are changes in the specified GraphQL schemas.\n\nYou can either specify a boolean to turn it on/off or specify an array of glob patterns to add custom files to the watch.\n\nFor more details: https://graphql-code-generator.com/docs/getting-started/development-workflow#watch-mode", "anyOf": [{ "type": "array", "items": { "type": "string" } }, { "type": ["string", "boolean"] }] }, "ignoreNoDocuments": { "description": "A flag to suppress non-zero exit code when there are no documents to generate.", "type": "boolean" }, "emitLegacyCommonJSImports": { "description": "A flag to disable adding `.js` extension to the output file. Default: `true`.", "type": "boolean" }, "importExtension": { "description": "Append this extension to all imports.\nUseful for ESM environments that require file extensions in import statements.", "anyOf": [ { "type": "array", "items": { "type": "string" } }, { "enum": [""], "type": "string" } ] }, "silent": { "description": "A flag to suppress printing errors when they occur.", "type": "boolean" }, "verbose": { "description": "A flag to output more detailed information about tasks", "type": "boolean" }, "debug": { "description": "A flag to output debug logs", "type": "boolean" }, "errorsOnly": { "description": "A flag to print only errors.", "type": "boolean" }, "pluginLoader": { "$ref": "#/definitions/Types.PackageLoaderFn", "description": "If you are using the programmatic API in a browser environment, you can override this configuration to load your plugins in a way different than require." }, "pluginContext": { "description": "Additional context passed to plugins", "type": "object", "additionalProperties": {} }, "pluckConfig": { "description": "Allows you to override the configuration for `@graphql-tools/graphql-tag-pluck`, the tool that extracts your GraphQL operations from your code files.\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/documents-field#graphql-tag-pluck", "type": "object", "properties": { "modules": { "$ref": "#/definitions/Array", "description": "An array of package name and identifier that will be used to track down your gql usages and imports. Use this if your code files imports gql from another library or you have a custom gql tag. identifier is the named export, so don't provide it if the tag function is imported as default." }, "gqlMagicComment": { "description": "Configures the magic GraphQL comments to look for. The default is `GraphQL`.", "type": "string" }, "globalIdentifier": { "description": "Overrides the name of the default GraphQL name identifier.", "type": "string" }, "globalGqlIdentifierName": { "description": "Allows to use a global identifier instead of a module import.", "anyOf": [{ "type": "array", "items": { "type": "string" } }, { "type": "string" }] } } }, "hooks": { "$ref": "#/definitions/Partial", "description": "Specifies scripts to run when events are happening in the codegen core.\nHooks defined on that level will effect all output files.\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/lifecycle-hooks" }, "noSilentErrors": { "description": "Alows to raise errors if any matched files are not valid GraphQL. Default: false.", "type": "boolean" }, "allowPartialOutputs": { "description": "If `true`, write to files whichever `generates` block succeeds. If `false`, one failed `generates` means no output is written to files. Default: false", "type": "boolean" } } }, "FlutterFreezedPluginConfig": { "description": "configure the `flutter-freezed` plugin", "type": "object", "properties": { "camelCasedEnums": { "type": "{(boolean | DartIdentifierCasing)}", "description": "Setting this option to `true` will camelCase enum values as required by Dart's recommended linter.\n\nIf set to false, the original casing as specified in the Graphql Schema is used\n\nYou can also transform the casing by specifying your preferred casing for Enum values.\n\nAvailable options are: `'snake_case'`, `'camelCase'` and `'PascalCase'`\n\nFor consistency, this option applies the same configuration to all Enum Types in the GraphQL Schema\nDefault value: \"true\"" }, "copyWith": { "type": "{(boolean | TypeNamePattern)}", "description": "The [`freezed`](https://pub.dev/packages/freezed) library has this option enabled by default.\nUse this option to enable/disable this option completely.\n\nThe plugin by default generates immutable Freezed models using the `@freezed` decorator.\n\nIf this option is configured, the plugin will generate immutable Freezed models using the `@Freezed(copyWith: value)` instead.\n\nSetting a boolean value will enable/disable this option globally for every GraphQL Type\nbut you can also set this option to `true` for one or more GraphQL Types using a `TypeNamePattern`.\nDefault value: \"undefined\"" }, "customScalars": { "type": "{(Record)}", "description": "The `key` is the GraphQL Scalar Type and the `value` is the equivalent Dart Type\n\nThe plugin automatically handles built-in GraphQL Scalar Types so only specify the custom Scalars in your Graphql Schema.\nDefault value: \"[object Object]\"" }, "defaultValues": { "type": "{([pattern: FieldNamePattern, value: string, appliesOn: AppliesOnParameters[]][])}", "description": "This will annotate the generated parameter with a `@Default(value: defaultValue)` decorator.\n\nThe default value will be interpolated into the `@Default(value: ${value})` decorator so\nUse backticks for the value element so that you can use quotation marks for string values.\nE.g: `\"I'm a string default value\"` but `Episode.jedi` is not a string value.\n\nUse the `appliesOn` to specify where this option should be applied on\nDefault value: \"undefined\"" }, "deprecated": { "type": "{([pattern: Pattern, appliesOn: (AppliesOnFactory | AppliesOnParameters)[]][])}", "description": "Using a TypeNamePattern, you can mark an entire factory constructor for one or more GraphQL types as deprecated.\n\nLikewise, using a FieldNamePattern, you can mark one or more fields as deprecated\n\nSince the first element in the tuple has a type signature of `Pattern`,\nyou can use either TypeNamePattern or FieldNamePattern or use both\nby composing them with `Pattern.compose(...)`\n\nUse the `appliesOn` to specify which block this option should be applied on\nDefault value: \"undefined\"" }, "equal": { "type": "{(boolean | TypeNamePattern)}", "description": "The [`freezed`](https://pub.dev/packages/freezed) library has this option enabled by default.\nUse this option to enable/disable this option completely.\n\nThe plugin by default generates immutable Freezed models using the `@freezed` decorator.\n\nIf this option is configured, the plugin will generate immutable Freezed models using the `@Freezed(equal: value)` instead.\n\nSetting a boolean value will enable/disable this option globally for every GraphQL Type\nbut you can also set this option to `true` for one or more GraphQL Types using a `TypeNamePattern`.\nDefault value: \"undefined\"" }, "escapeDartKeywords": { "type": "{(boolean | [pattern: Pattern, prefix?: string, suffix?: string, appliesOn?: AppliesOn[]][])}", "description": "Wraps the fields names that are valid Dart keywords with the prefix and suffix given\nDefault value: \"true\"" }, "final": { "type": "{([pattern: FieldNamePattern, appliesOn: AppliesOnParameters[]][])}", "description": "This will mark the specified parameters as final\nDefault value: \"undefined\"" }, "ignoreTypes": { "type": "{(TypeNamePattern)}", "description": "names of GraphQL types to ignore when generating Freezed classes\nDefault value: \"undefined\"" }, "immutable": { "type": "{(boolean | TypeNamePattern)}", "description": "The [`freezed`](https://pub.dev/packages/freezed) library by default generates immutable models decorated with the `@freezed` decorator.\nThis option if set to `false` the plugin will generate mutable Freezed models using the `@unfreezed` decorator instead.\n\nSetting a boolean value will enable/disable this option globally for every GraphQL Type\nbut you can also set this option to `true` for one or more GraphQL Types using a `TypeNamePattern`.\nDefault value: \"undefined\"" }, "makeCollectionsUnmodifiable": { "type": "{(boolean | TypeNamePattern)}", "description": "allows collections(lists/maps) to be modified even if class is immutable\nDefault value: \"undefined\"" }, "mergeTypes": { "type": "{(Record)}", "description": "maps over the value(array of typeNames) and transform each as a named factory constructor inside a class generated for the key(target GraphQL Object Type).\nDefault value: \"undefined\"" }, "mutableInputs": { "description": "since inputs will be used to collect data, it makes sense to make them mutable with Freezed's `@unfreezed` decorator.\n\nThis overrides(in order words: has a higher precedence than) the `immutable` config value `ONLY` for GraphQL `input types`.\nDefault value: \"true\"", "anyOf": [{ "$ref": "#/definitions/TypeNamePattern" }, { "type": "boolean" }] }, "privateEmptyConstructor": { "description": "if true, defines a private empty constructor to allow getter and methods to work on the class\nDefault value: \"true\"", "anyOf": [{ "$ref": "#/definitions/TypeNamePattern" }, { "type": "boolean" }] }, "unionClass": { "description": "customize the key to be used for fromJson with multiple constructors\nDefault value: \"undefined\"", "type": "array", "items": { "type": "array", "items": [ { "$ref": "#/definitions/TypeNamePattern" }, { "type": "string" }, { "$ref": "#/definitions/UnionValueCase" }, { "type": "array", "items": { "type": "array", "items": [{ "$ref": "#/definitions/TypeName" }, { "type": "string" }], "minItems": 2, "maxItems": 2 } } ], "minItems": 1, "maxItems": 4 } } } }, "ReactQueryRawPluginConfig": { "description": "This plugin generates `React-Query` Hooks with TypeScript typings.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\n> **If you are using the `react-query` package instead of the `@tanstack/react-query` package in your project, please set the `legacyMode` option to `true`.**", "type": "object", "properties": { "fetcher": { "description": "Customize the fetcher you wish to use in the generated file. React-Query is agnostic to the data-fetching layer, so you should provide it, or use a custom one.\n\nThe following options are available to use:\n\n- 'fetch' - requires you to specify endpoint and headers on each call, and uses `fetch` to do the actual http call.\n- `{ endpoint: string, fetchParams: RequestInit }`: hardcode your endpoint and fetch options into the generated output, using the environment `fetch` method. You can also use `process.env.MY_VAR` as endpoint or header value.\n- `file#identifier` - You can use custom fetcher method that should implement the exported `ReactQueryFetcher` interface. Example: `./my-fetcher#myCustomFetcher`.\n- `graphql-request`: Will generate each hook with `client` argument, where you should pass your own `GraphQLClient` (created from `graphql-request`).", "anyOf": [ { "$ref": "#/definitions/HardcodedFetch" }, { "type": "object", "properties": { "func": { "type": "string" }, "isReactHook": { "type": "boolean" } } }, { "type": "string" } ] }, "exposeDocument": { "description": "For each generate query hook adds `document` field with a\ncorresponding GraphQL query. Useful for `queryClient.fetchQuery`.\nDefault value: \"false\"", "type": "boolean" }, "exposeQueryKeys": { "description": "For each generate query hook adds getKey(variables: QueryVariables) function. Useful for cache updates. If addInfiniteQuery is true, it will also add a getKey function to each infinite query.\nDefault value: \"false\"", "type": "boolean" }, "exposeMutationKeys": { "description": "For each generate mutation hook adds getKey() function. Useful for call outside of functional component.\nDefault value: \"false\"", "type": "boolean" }, "exposeFetcher": { "description": "For each generate query hook adds `fetcher` field with a corresponding GraphQL query using the fetcher.\nIt is useful for `queryClient.fetchQuery` and `queryClient.prefetchQuery`.\nDefault value: \"false\"", "type": "boolean" }, "errorType": { "description": "Changes the default \"TError\" generic type.\nDefault value: \"unknown\"", "type": "string" }, "addInfiniteQuery": { "description": "Adds an Infinite Query along side the standard one\nDefault value: \"false\"", "type": "boolean" }, "legacyMode": { "description": "If false, it will work with `@tanstack/react-query`, default value is true.\nDefault value: \"true\"", "type": "boolean" }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" } } }, "RTKConfig": { "type": "object", "properties": { "importBaseApiFrom": { "description": "Define where to import the base api to inject endpoints into", "type": "string" }, "importBaseApiAlternateName": { "description": "Change the import name of the baseApi from default 'api'\nDefault value: \"'api'\"", "type": "string" }, "exportHooks": { "description": "Whether to export React Hooks from the generated api. Enable only when using the `\"@reduxjs/toolkit/query/react\"` import of `createApi`\nDefault value: \"false\"", "type": "boolean" }, "overrideExisting": { "description": "Sets the `overrideExisting` option, for example to allow for hot module reloading when running graphql-codegen in watch mode.\nWill directly be injected as code.\nDefault value: \"undefined\"", "type": "string" } } }, "RawGenericSdkPluginConfig": { "description": "This plugin generate a generic SDK (without any Requester implemented), allow you to easily customize the way you fetch your data, without loosing the strongly-typed integration.", "type": "object", "properties": { "usingObservableFrom": { "description": "usingObservableFrom: `import Observable from 'zen-observable'`\nOR\nusingObservableFrom: `import { Observable } from 'rxjs'`", "type": "string" }, "rawRequest": { "description": "By default the `request` method return the `data` or `errors` key from the response. If you need to access the `extensions` key you can use the `rawRequest` method.\nDefault value: \"false\"", "type": "boolean" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "ApolloClientHelpersConfig": { "type": "object", "properties": { "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "requireKeyFields": { "type": "boolean", "description": "Remove optional sign from all `keyFields` fields.\nDefault value: \"false\"" }, "requirePoliciesForAllTypes": { "type": "boolean", "description": "Remove optional sign from all generated keys of the root TypePolicy.\nDefault value: \"false\"" } } }, "AddPluginConfig": { "type": "object", "properties": { "placement": { "description": "Allow you to choose where to add the content.\nDefault value: \"prepend\"", "enum": ["append", "content", "prepend"], "type": "string" }, "content": { "description": "The actual content you wish to add, either a string or array of strings.\nYou can also specify a path to a local file and the content if it will be loaded by codegen.", "anyOf": [{ "type": "array", "items": { "type": "string" } }, { "type": "string" }] } } }, "TimePluginConfig": { "type": "object", "properties": { "format": { "description": "Customize the Moment format of the output time.\nDefault value: \"YYYY-MM-DDTHH:mm:ssZ\"", "type": "string" }, "message": { "description": "Customize the comment message\nDefault value: \"'Generated on'\"", "type": "string" } } }, "TypeScriptPluginConfig": { "description": "This plugin generates the base TypeScript types, based on your GraphQL schema.\n\nThe types generated by this plugin are simple, and refers to the exact structure of your schema, and it's used as the base types for other plugins (such as `typescript-operations` / `typescript-resolvers`)", "type": "object", "properties": { "avoidOptionals": { "description": "This will cause the generator to avoid using TypeScript optionals (`?`) on types,\nso the following definition: `type A { myField: String }` will output `myField: Maybe`\ninstead of `myField?: Maybe`.\nDefault value: \"false\"", "anyOf": [{ "$ref": "#/definitions/AvoidOptionalsConfig" }, { "type": "boolean" }] }, "constEnums": { "description": "Will prefix every generated `enum` with `const`, you can read more about const enums here: https://www.typescriptlang.org/docs/handbook/enums.html.\nDefault value: \"false\"", "type": "boolean" }, "enumsAsTypes": { "description": "Generates enum as TypeScript string union `type` instead of an `enum`. Useful if you wish to generate `.d.ts` declaration file instead of `.ts`, or if you want to avoid using TypeScript enums due to bundle size concerns\nDefault value: \"false\"", "type": "boolean" }, "numericEnums": { "description": "Controls whether to preserve typescript enum values as numbers\nDefault value: \"false\"", "type": "boolean" }, "futureProofEnums": { "description": "This option controls whether or not a catch-all entry is added to enum type definitions for values that may be added in the future.\nThis is useful if you are using `relay`.\nDefault value: \"false\"", "type": "boolean" }, "futureProofUnions": { "description": "This option controls whether or not a catch-all entry is added to union type definitions for values that may be added in the future.\nThis is useful if you are using `relay`.\nDefault value: \"false\"", "type": "boolean" }, "enumsAsConst": { "description": "Generates enum as TypeScript `const assertions` instead of `enum`. This can even be used to enable enum-like patterns in plain JavaScript code if you choose not to use TypeScript’s enum construct.\nDefault value: \"false\"", "type": "boolean" }, "onlyEnums": { "description": "This will cause the generator to emit types for enums only.\nDefault value: \"false\"", "type": "boolean" }, "onlyOperationTypes": { "description": "This will cause the generator to emit types for operations only (basically only enums and scalars).\nInteracts well with `preResolveTypes: true`\nDefault value: \"false\"", "type": "boolean" }, "immutableTypes": { "description": "Generates immutable types by adding `readonly` to properties and uses `ReadonlyArray`.\nDefault value: \"false\"", "type": "boolean" }, "maybeValue": { "description": "Allow to override the type value of `Maybe`.\nDefault value: \"T | null\"", "type": "string" }, "inputMaybeValue": { "description": "Allow to override the type value of `Maybe` for input types and arguments.\nThis is useful in case you want to differentiate between the wrapper of input and output types.\nBy default, this type just refers to `Maybe` type, but you can override its definition.\nDefault value: \"Maybe\"", "type": "string" }, "noExport": { "description": "Set to `true` in order to generate output without `export` modifier.\nThis is useful if you are generating `.d.ts` file and want it to be globally available.\nDefault value: \"false\"", "type": "boolean" }, "disableDescriptions": { "description": "Set the value to `true` in order to disable all description generation.\nDefault value: \"false\"", "type": "boolean" }, "useImplementingTypes": { "description": "When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself.\nDefault value: \"false\"", "type": "boolean" }, "wrapEntireFieldDefinitions": { "type": "boolean", "description": "Set to `true` in order to wrap field definitions with `EntireFieldWrapper`.\nThis is useful to allow return types such as Promises and functions for fields.\nDiffers from `wrapFieldDefinitions` in that this wraps the entire field definition if i.e. the field is an Array, while\n`wrapFieldDefinitions` will wrap every single value inside the array.\nDefault value: \"false\"" }, "entireFieldWrapperValue": { "type": "string", "description": "Allow to override the type value of `EntireFieldWrapper`. This wrapper applies outside of Array and Maybe\nunlike `fieldWrapperValue`, that will wrap the inner type.\nDefault value: \"T | Promise | (() => T | Promise)\"" }, "allowEnumStringTypes": { "description": "Allow using enum string values directly.", "type": "boolean" }, "addUnderscoreToArgsType": { "description": "Adds `_` to generated `Args` types in order to avoid duplicate identifiers.", "type": "boolean" }, "enumValues": { "$ref": "#/definitions/EnumValuesMap", "description": "Overrides the default value of enum values declared in your GraphQL schema.\nYou can also map the entire enum to an external type by providing a string that of `module#type`." }, "declarationKind": { "description": "Overrides the default output for various GraphQL elements.", "anyOf": [ { "$ref": "#/definitions/DeclarationKindConfig" }, { "enum": ["abstract class", "class", "interface", "type"], "type": "string" } ] }, "enumPrefix": { "description": "Allow you to disable prefixing for generated enums, works in combination with `typesPrefix`.\nDefault value: \"true\"", "type": "boolean" }, "enumSuffix": { "description": "Allow you to disable suffixing for generated enums, works in combination with `typesSuffix`.\nDefault value: \"true\"", "type": "boolean" }, "fieldWrapperValue": { "description": "Allow you to add wrapper for field type, use T as the generic value. Make sure to set `wrapFieldDefinitions` to `true` in order to make this flag work.\nDefault value: \"T\"", "type": "string" }, "wrapFieldDefinitions": { "description": "Set to `true` in order to wrap field definitions with `FieldWrapper`.\nThis is useful to allow return types such as Promises and functions.\nDefault value: \"false\"", "type": "boolean" }, "ignoreEnumValuesFromSchema": { "description": "This will cause the generator to ignore enum values defined in GraphQLSchema\nDefault value: \"false\"", "type": "boolean" }, "directiveArgumentAndInputFieldMappings": { "$ref": "#/definitions/DirectiveArgumentAndInputFieldMappings", "description": "Replaces a GraphQL scalar with a custom type based on the applied directive on an argument or input field.\n\nYou can use both `module#type` and `module#namespace#type` syntax.\nWill NOT work with introspected schemas since directives are not exported.\nOnly works with directives on ARGUMENT_DEFINITION or INPUT_FIELD_DEFINITION.\n\n**WARNING:** Using this option does only change the type definitions.\n\nFor actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://graphql-tools.com/docs/schema-directives)) that apply those rules!\nOtherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors.\n\nPlease use this configuration option with care!" }, "directiveArgumentAndInputFieldMappingTypeSuffix": { "description": "Adds a suffix to the imported names to prevent name clashes.", "type": "string" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap_1", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention_1", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\n\"mask\" transforms the types for use with fragment masking. Useful when masked types are needed when not using the \"client\" preset e.g. such as combining it with Apollo Client's data masking feature.\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" }, "importExtension": { "description": "Append this extension to all imports.\nUseful for ESM environments that require file extensions in import statements.", "anyOf": [ { "type": "array", "items": { "type": "string" } }, { "enum": [""], "type": "string" } ] }, "extractAllFieldsToTypes": { "description": "Extract all field types to their own types, instead of inlining them.\nThis helps to reduce type duplication, and makes type errors more readable.\nIt can also significantly reduce the size of the generated code, the generation time,\nand the typechecking time.\nDefault value: \"false\"", "type": "boolean" }, "printFieldsOnNewLines": { "description": "If you prefer to have each field in generated types printed on a new line, set this to true.\nThis can be useful for improving readability of the resulting types,\nwithout resorting to running tools like Prettier on the output.\nDefault value: \"false\"", "type": "boolean" }, "includeExternalFragments": { "description": "Whether to include external fragments in the generated code. External fragments are not defined\nin the same location as the operation definition.\nDefault value: \"false\"", "type": "boolean" } } }, "TypeScriptDocumentsPluginConfig": { "description": "This plugin generates TypeScript types based on your GraphQLSchema _and_ your GraphQL operations and fragments.\nIt generates types for your GraphQL documents: Query, Mutation, Subscription and Fragment.\n\nNote: In most configurations, this plugin requires you to use `typescript as well, because it depends on its base types.", "type": "object", "properties": { "arrayInputCoercion": { "description": "The [GraphQL spec](https://spec.graphql.org/draft/#sel-FAHjBJFCAACE_Gh7d)\nallows arrays and a single primitive value for list input. This allows to\ndeactivate that behavior to only accept arrays instead of single values. If\nset to `false`, the definition: `query foo(bar: [Int!]!): Foo` will output\n`bar: Array` instead of `bar: Array | Int` for the variable part.\nDefault value: \"true\"", "type": "boolean" }, "avoidOptionals": { "description": "This will cause the generator to avoid using TypeScript optionals (`?`) on types,\nso the following definition: `type A { myField: String }` will output `myField: Maybe`\ninstead of `myField?: Maybe`.\nDefault value: \"false\"", "anyOf": [{ "$ref": "#/definitions/AvoidOptionalsConfig" }, { "type": "boolean" }] }, "immutableTypes": { "description": "Generates immutable types by adding `readonly` to properties and uses `ReadonlyArray`.\nDefault value: \"false\"", "type": "boolean" }, "flattenGeneratedTypes": { "description": "Flatten fragment spread and inline fragments into a simple selection set before generating.\nDefault value: \"false\"", "type": "boolean" }, "flattenGeneratedTypesIncludeFragments": { "description": "Include all fragments types when flattenGeneratedTypes is enabled.\nDefault value: \"false\"", "type": "boolean" }, "noExport": { "description": "Set to `true` in order to generate output without `export` modifier.\nThis is useful if you are generating `.d.ts` file and want it to be globally available.\nDefault value: \"false\"", "type": "boolean" }, "globalNamespace": { "type": "boolean" }, "addOperationExport": { "type": "boolean", "description": "Add const export of the operation name to output file. Pay attention that the file should be `d.ts`.\nYou can combine it with `near-operation-file preset` and therefore the types will be generated along with graphql file. Then you need to set extension in `presetConfig` to be `.gql.d.ts` and by that you can import `gql` file in `ts` files.\nIt will allow you to get everything with one import:\n\n```ts\nimport { GetClient, GetClientQuery, GetClientQueryVariables } from './GetClient.gql.js'\n```\nDefault value: \"false\"" }, "maybeValue": { "description": "Allow to override the type value of `Maybe`.\nDefault value: \"T | null\"", "type": "string" }, "allowUndefinedQueryVariables": { "description": "Adds undefined as a possible type for query variables\nDefault value: \"false\"", "type": "boolean" }, "nullability": { "description": "Options related to handling nullability", "type": "object", "properties": { "errorHandlingClient": { "type": "boolean" } } }, "preResolveTypes": { "description": "Uses primitive types where possible.\nSet to `false` in order to use `Pick` and take use the types generated by `typescript` plugin.\nDefault value: \"true\"", "type": "boolean" }, "skipTypeNameForRoot": { "description": "Avoid adding `__typename` for root types. This is ignored when a selection explicitly specifies `__typename`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "exportFragmentSpreadSubTypes": { "description": "If set to true, it will export the sub-types created in order to make it easier to access fields declared under fragment spread.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "mergeFragmentTypes": { "description": "If set to true, merge equal fragment interfaces.\nDefault value: \"false\"", "type": "boolean" }, "customDirectives": { "$ref": "#/definitions/CustomDirectivesConfig", "description": "Configures behavior for use with custom directives from\nvarious GraphQL libraries." }, "addUnderscoreToArgsType": { "description": "Adds `_` to generated `Args` types in order to avoid duplicate identifiers.", "type": "boolean" }, "enumValues": { "$ref": "#/definitions/EnumValuesMap", "description": "Overrides the default value of enum values declared in your GraphQL schema.\nYou can also map the entire enum to an external type by providing a string that of `module#type`." }, "declarationKind": { "description": "Overrides the default output for various GraphQL elements.", "anyOf": [ { "$ref": "#/definitions/DeclarationKindConfig" }, { "enum": ["abstract class", "class", "interface", "type"], "type": "string" } ] }, "enumPrefix": { "description": "Allow you to disable prefixing for generated enums, works in combination with `typesPrefix`.\nDefault value: \"true\"", "type": "boolean" }, "enumSuffix": { "description": "Allow you to disable suffixing for generated enums, works in combination with `typesSuffix`.\nDefault value: \"true\"", "type": "boolean" }, "fieldWrapperValue": { "description": "Allow you to add wrapper for field type, use T as the generic value. Make sure to set `wrapFieldDefinitions` to `true` in order to make this flag work.\nDefault value: \"T\"", "type": "string" }, "wrapFieldDefinitions": { "description": "Set to `true` in order to wrap field definitions with `FieldWrapper`.\nThis is useful to allow return types such as Promises and functions.\nDefault value: \"false\"", "type": "boolean" }, "onlyEnums": { "description": "This will cause the generator to emit types for enums only\nDefault value: \"false\"", "type": "boolean" }, "onlyOperationTypes": { "description": "This will cause the generator to emit types for operations only (basically only enums and scalars)\nDefault value: \"false\"", "type": "boolean" }, "ignoreEnumValuesFromSchema": { "description": "This will cause the generator to ignore enum values defined in GraphQLSchema\nDefault value: \"false\"", "type": "boolean" }, "wrapEntireFieldDefinitions": { "type": "boolean", "description": "Set to `true` in order to wrap field definitions with `EntireFieldWrapper`.\nThis is useful to allow return types such as Promises and functions for fields.\nDiffers from `wrapFieldDefinitions` in that this wraps the entire field definition if i.e. the field is an Array, while\n`wrapFieldDefinitions` will wrap every single value inside the array.\nDefault value: \"true\"" }, "entireFieldWrapperValue": { "type": "string", "description": "Allow to override the type value of `EntireFieldWrapper`. This wrapper applies outside of Array and Maybe\nunlike `fieldWrapperValue`, that will wrap the inner type.\nDefault value: \"T | Promise | (() => T | Promise)\"" }, "directiveArgumentAndInputFieldMappings": { "$ref": "#/definitions/DirectiveArgumentAndInputFieldMappings", "description": "Replaces a GraphQL scalar with a custom type based on the applied directive on an argument or input field.\n\nYou can use both `module#type` and `module#namespace#type` syntax.\nWill NOT work with introspected schemas since directives are not exported.\nOnly works with directives on ARGUMENT_DEFINITION or INPUT_FIELD_DEFINITION.\n\n**WARNING:** Using this option does only change the type definitions.\n\nFor actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://graphql-tools.com/docs/schema-directives)) that apply those rules!\nOtherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors.\n\nPlease use this configuration option with care!" }, "directiveArgumentAndInputFieldMappingTypeSuffix": { "description": "Adds a suffix to the imported names to prevent name clashes.", "type": "string" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap_1", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention_1", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\n\"mask\" transforms the types for use with fragment masking. Useful when masked types are needed when not using the \"client\" preset e.g. such as combining it with Apollo Client's data masking feature.\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" }, "importExtension": { "description": "Append this extension to all imports.\nUseful for ESM environments that require file extensions in import statements.", "anyOf": [ { "type": "array", "items": { "type": "string" } }, { "enum": [""], "type": "string" } ] }, "extractAllFieldsToTypes": { "description": "Extract all field types to their own types, instead of inlining them.\nThis helps to reduce type duplication, and makes type errors more readable.\nIt can also significantly reduce the size of the generated code, the generation time,\nand the typechecking time.\nDefault value: \"false\"", "type": "boolean" }, "printFieldsOnNewLines": { "description": "If you prefer to have each field in generated types printed on a new line, set this to true.\nThis can be useful for improving readability of the resulting types,\nwithout resorting to running tools like Prettier on the output.\nDefault value: \"false\"", "type": "boolean" }, "includeExternalFragments": { "description": "Whether to include external fragments in the generated code. External fragments are not defined\nin the same location as the operation definition.\nDefault value: \"false\"", "type": "boolean" } } }, "CSharpResolversPluginRawConfig": { "description": "This plugin generates C# `class` identifier for your schema types.", "type": "object", "properties": { "enumValues": { "$ref": "#/definitions/EnumValuesMap_1", "description": "Overrides the default value of enum values declared in your GraphQL schema." }, "namespaceName": { "description": "Allow you to customize the namespace name.\nDefault value: \"GraphQLCodeGen\"", "type": "string" }, "className": { "description": "Allow you to customize the parent class name.\nDefault value: \"Types\"", "type": "string" }, "listType": { "description": "Allow you to customize the list type\nDefault value: \"IEnumerable\"", "type": "string" }, "emitRecords": { "description": "Emit C# 9.0+ records instead of classes\nDefault value: \"false\"", "type": "boolean" }, "emitJsonAttributes": { "description": "Should JSON attributes be emitted for produced types and properties ot not\nDefault value: \"true\"", "type": "boolean" }, "jsonAttributesSource": { "$ref": "#/definitions/JsonAttributesSource", "description": "Library that should be used to emit JSON attributes. Ignored when `emitJsonAttributes` is `false` or not specified\nDefault value: \"Newtonsoft.Json\"" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap_2", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention_2", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "CSharpOperationsRawPluginConfig": { "description": "This plugin generates C# `class` based on your GraphQL operations.", "type": "object", "properties": { "namespaceName": { "description": "Allow you to customize the namespace name.\nDefault value: \"GraphQLCodeGen\"", "type": "string" }, "namedClient": { "description": "Defined the global value of `namedClient`.", "type": "string" }, "querySuffix": { "description": "Allows to define a custom suffix for query operations.\nDefault value: \"GQL\"", "type": "string" }, "mutationSuffix": { "description": "Allows to define a custom suffix for mutation operations.\nDefault value: \"GQL\"", "type": "string" }, "subscriptionSuffix": { "description": "Allows to define a custom suffix for Subscription operations.\nDefault value: \"GQL\"", "type": "string" }, "typesafeOperation": { "description": "Allows to generate operation methods with class definitions for request/response parameters\nDefault value: \"false\"", "type": "boolean" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode_1", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap_2", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention_2", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "SchemaASTConfig": { "description": "This plugin prints the merged schema as string. If multiple schemas are provided, they will be merged and printed as one schema.", "type": "object", "properties": { "includeDirectives": { "description": "Include directives to Schema output.\nDefault value: \"false\"", "type": "boolean" }, "includeIntrospectionTypes": { "description": "Include introspection types to Schema output.\nDefault value: \"false\"", "type": "boolean" }, "commentDescriptions": { "description": "Set to true in order to print description as comments (using `#` instead of `\"\"\"`)\nDefault value: \"false\"", "type": "boolean" }, "sort": { "description": "Set to false to disable sorting\nDefault value: \"true\"", "type": "boolean" }, "federation": { "type": "boolean" } } }, "TypeGraphQLPluginConfig": { "type": "object", "properties": { "decoratorName": { "$ref": "#/definitions/Partial_1", "description": "allow overriding of TypeGraphQL decorator types\nDefault value: \"{ type: 'ObjectType', interface: 'InterfaceType', arguments: 'ArgsType', field: 'Field', input: 'InputType' }\"" }, "decorateTypes": { "description": "Specifies the objects that will have TypeGraphQL decorators prepended to them, by name. Non-matching types will still be output, but without decorators. If not set, all types will be decorated.", "type": "array", "items": { "type": "string" } }, "avoidOptionals": { "description": "This will cause the generator to avoid using TypeScript optionals (`?`) on types,\nso the following definition: `type A { myField: String }` will output `myField: Maybe`\ninstead of `myField?: Maybe`.\nDefault value: \"false\"", "anyOf": [{ "$ref": "#/definitions/AvoidOptionalsConfig_1" }, { "type": "boolean" }] }, "constEnums": { "description": "Will prefix every generated `enum` with `const`, you can read more about const enums here: https://www.typescriptlang.org/docs/handbook/enums.html.\nDefault value: \"false\"", "type": "boolean" }, "enumsAsTypes": { "description": "Generates enum as TypeScript string union `type` instead of an `enum`. Useful if you wish to generate `.d.ts` declaration file instead of `.ts`, or if you want to avoid using TypeScript enums due to bundle size concerns\nDefault value: \"false\"", "type": "boolean" }, "numericEnums": { "description": "Controls whether to preserve typescript enum values as numbers\nDefault value: \"false\"", "type": "boolean" }, "futureProofEnums": { "description": "This option controls whether or not a catch-all entry is added to enum type definitions for values that may be added in the future.\nThis is useful if you are using `relay`.\nDefault value: \"false\"", "type": "boolean" }, "futureProofUnions": { "description": "This option controls whether or not a catch-all entry is added to union type definitions for values that may be added in the future.\nThis is useful if you are using `relay`.\nDefault value: \"false\"", "type": "boolean" }, "enumsAsConst": { "description": "Generates enum as TypeScript `const assertions` instead of `enum`. This can even be used to enable enum-like patterns in plain JavaScript code if you choose not to use TypeScript’s enum construct.\nDefault value: \"false\"", "type": "boolean" }, "onlyEnums": { "description": "This will cause the generator to emit types for enums only.\nDefault value: \"false\"", "type": "boolean" }, "onlyOperationTypes": { "description": "This will cause the generator to emit types for operations only (basically only enums and scalars).\nInteracts well with `preResolveTypes: true`\nDefault value: \"false\"", "type": "boolean" }, "immutableTypes": { "description": "Generates immutable types by adding `readonly` to properties and uses `ReadonlyArray`.\nDefault value: \"false\"", "type": "boolean" }, "maybeValue": { "description": "Allow to override the type value of `Maybe`.\nDefault value: \"T | null\"", "type": "string" }, "inputMaybeValue": { "description": "Allow to override the type value of `Maybe` for input types and arguments.\nThis is useful in case you want to differentiate between the wrapper of input and output types.\nBy default, this type just refers to `Maybe` type, but you can override its definition.\nDefault value: \"Maybe\"", "type": "string" }, "noExport": { "description": "Set to `true` in order to generate output without `export` modifier.\nThis is useful if you are generating `.d.ts` file and want it to be globally available.\nDefault value: \"false\"", "type": "boolean" }, "disableDescriptions": { "description": "Set the value to `true` in order to disable all description generation.\nDefault value: \"false\"", "type": "boolean" }, "useImplementingTypes": { "description": "When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself.\nDefault value: \"false\"", "type": "boolean" }, "wrapEntireFieldDefinitions": { "type": "boolean", "description": "Set to `true` in order to wrap field definitions with `EntireFieldWrapper`.\nThis is useful to allow return types such as Promises and functions for fields.\nDiffers from `wrapFieldDefinitions` in that this wraps the entire field definition if i.e. the field is an Array, while\n`wrapFieldDefinitions` will wrap every single value inside the array.\nDefault value: \"false\"" }, "entireFieldWrapperValue": { "type": "string", "description": "Allow to override the type value of `EntireFieldWrapper`. This wrapper applies outside of Array and Maybe\nunlike `fieldWrapperValue`, that will wrap the inner type.\nDefault value: \"T | Promise | (() => T | Promise)\"" }, "allowEnumStringTypes": { "description": "Allow using enum string values directly.", "type": "boolean" }, "addUnderscoreToArgsType": { "description": "Adds `_` to generated `Args` types in order to avoid duplicate identifiers.", "type": "boolean" }, "enumValues": { "$ref": "#/definitions/EnumValuesMap_1", "description": "Overrides the default value of enum values declared in your GraphQL schema.\nYou can also map the entire enum to an external type by providing a string that of `module#type`." }, "declarationKind": { "description": "Overrides the default output for various GraphQL elements.", "anyOf": [ { "$ref": "#/definitions/DeclarationKindConfig_1" }, { "enum": ["abstract class", "class", "interface", "type"], "type": "string" } ] }, "enumPrefix": { "description": "Allow you to disable prefixing for generated enums, works in combination with `typesPrefix`.\nDefault value: \"true\"", "type": "boolean" }, "fieldWrapperValue": { "description": "Allow you to add wrapper for field type, use T as the generic value. Make sure to set `wrapFieldDefinitions` to `true` in order to make this flag work.\nDefault value: \"T\"", "type": "string" }, "wrapFieldDefinitions": { "description": "Set to `true` in order to wrap field definitions with `FieldWrapper`.\nThis is useful to allow return types such as Promises and functions.\nDefault value: \"false\"", "type": "boolean" }, "ignoreEnumValuesFromSchema": { "description": "This will cause the generator to ignore enum values defined in GraphQLSchema\nDefault value: \"false\"", "type": "boolean" }, "directiveArgumentAndInputFieldMappings": { "$ref": "#/definitions/DirectiveArgumentAndInputFieldMappings_1", "description": "Replaces a GraphQL scalar with a custom type based on the applied directive on an argument or input field.\n\nYou can use both `module#type` and `module#namespace#type` syntax.\nWill NOT work with introspected schemas since directives are not exported.\nOnly works with directives on ARGUMENT_DEFINITION or INPUT_FIELD_DEFINITION.\n\n**WARNING:** Using this option does only change the type definitions.\n\nFor actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://graphql-tools.com/docs/schema-directives)) that apply those rules!\nOtherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors.\n\nPlease use this configuration option with care!" }, "directiveArgumentAndInputFieldMappingTypeSuffix": { "description": "Adds a suffix to the imported names to prevent name clashes.", "type": "string" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap_2", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention_2", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "TypeScriptFilesModulesPluginConfig": { "description": "This plugin generates TypeScript typings for `.graphql` files containing GraphQL documents, which later on can be consumed using [`graphql-tag/loader`](https://github.com/apollographql/graphql-tag#webpack-preprocessing-with-graphql-tagloader) or use `string` types if you will use the operations as raw strings, and get type-check and type-safety for your imports. This means that any time you import objects from `.graphql` files, your IDE will provide auto-complete.\n\nThis plugin also handles `.graphql` files containing multiple GraphQL documents, and name the imports according to the operation name.\n\n> ⚠ Fragments are not generated with named imports, only as default imports, due to `graphql-tag/loader` behavior.", "type": "object", "properties": { "modulePathPrefix": { "description": "Allows specifying a module definition path prefix to provide distinction\nbetween generated types.\nDefault value: \"\"", "type": "string" }, "relativeToCwd": { "description": "By default, only the filename is being used to generate TS module declarations. Setting this to `true` will generate it with a full path based on the CWD.\nDefault value: \"false\"", "type": "boolean" }, "prefix": { "description": "By default, a wildcard is being added as prefix, you can change that to a custom prefix\nDefault value: \"*\\/\"", "type": "string" }, "type": { "description": "By default, the named exports will have a type `DocumentNode`. Change this to \"string\" if you only use raw strings.\nDefault value: \"DocumentNode\"", "enum": ["DocumentNode", "string"], "type": "string" } } }, "NamedOperationsObjectPluginConfig": { "type": "object", "properties": { "identifierName": { "description": "Allow you to customize the name of the exported identifier\nDefault value: \"namedOperations\"", "type": "string" }, "useConsts": { "description": "Will generate a const string instead of regular string.\nDefault value: \"false\"", "type": "boolean" } } }, "RawGraphQLRequestPluginConfig": { "description": "This plugin generates [`graphql-request`](https://npmjs.com/package/graphql-request) ready-to-use SDK, which is fully-typed.", "type": "object", "properties": { "rawRequest": { "description": "By default, the `request` method return the `data` or `errors` key from the response. If you need to access the `extensions` key you can use the `rawRequest` method.\nDefault value: \"false\"", "type": "boolean" }, "extensionsType": { "description": "Allows you to override the type for extensions when `rawRequest` is enabled.\nDefault value: \"any\"", "type": "string" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "TypeScriptMongoPluginConfig": { "type": "object", "properties": { "dbTypeSuffix": { "description": "Customize the suffix for the generated GraphQL `type`s.\nDefault value: \"DbObject\"", "type": "string" }, "dbInterfaceSuffix": { "description": "Customize the suffix for the generated GraphQL `interface`s.\nDefault value: \"DbObject\"", "type": "string" }, "objectIdType": { "description": "Customize the type of `_id` fields. You can either specify a type name, or specify `module#type`.\nDefault value: \"mongodb#ObjectId\"", "type": "string" }, "idFieldName": { "description": "Customize the name of the id field generated after using `@id` directive over a GraphQL field.\nDefault value: \"_id\"", "type": "string" }, "enumsAsString": { "description": "Replaces generated `enum` values with `string`.\nDefault value: \"true\"", "type": "boolean" }, "avoidOptionals": { "description": "This will cause the generator to avoid using TypeScript optionals (`?`),\nso the following definition: `type A { myField: String }` will output `myField: Maybe`\ninstead of `myField?: Maybe`.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "TypeScriptResolversPluginConfig": { "description": "This plugin generates TypeScript signature for `resolve` functions of your GraphQL API.\nYou can use this plugin to generate simple resolvers signature based on your GraphQL types, or you can change its behavior be providing custom model types (mappers).\n\nYou can find a blog post explaining the usage of this plugin here: https://the-guild.dev/blog/better-type-safety-for-resolvers-with-graphql-codegen", "type": "object", "properties": { "useIndexSignature": { "description": "Adds an index signature to any generates resolver.\nDefault value: \"false\"", "type": "boolean" }, "noSchemaStitching": { "description": "Disables/Enables Schema Stitching support.\nBy default, the resolver signature does not include the support for schema-stitching.\nSet to `false` to enable that.\nDefault value: \"true\"", "type": "boolean" }, "wrapFieldDefinitions": { "description": "Set to `true` in order to wrap field definitions with `FieldWrapper`.\nThis is useful to allow return types such as Promises and functions. Needed for\ncompatibility with `federation: true` when\nDefault value: \"true\"", "type": "boolean" }, "customResolveInfo": { "description": "You can provide your custom GraphQLResolveInfo instead of the default one from graphql-js\nDefault value: \"graphql#GraphQLResolveInfo\"", "type": "string" }, "customResolverFn": { "description": "You can provide your custom ResolveFn instead the default. It has to be a type that uses the generics ``\nDefault value: \"(parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo) => Promise | TResult\"", "type": "string" }, "directiveResolverMappings": { "$ref": "#/definitions/Record", "description": "Map the usage of a directive into using a specific resolver." }, "allowParentTypeOverride": { "description": "Allow you to override the `ParentType` generic in each resolver, by avoid enforcing the base type of the generated generic type.\n\nThis will generate `ParentType = Type` instead of `ParentType extends Type = Type` in each resolver.", "type": "boolean" }, "optionalInfoArgument": { "description": "Sets `info` argument of resolver function to be optional field. Useful for testing.", "type": "boolean" }, "makeResolverTypeCallable": { "description": "Set to `true` in order to allow the Resolver type to be callable", "type": "boolean" }, "addUnderscoreToArgsType": { "description": "Adds `_` to generated `Args` types in order to avoid duplicate identifiers.", "type": "boolean" }, "contextType": { "description": "Use this configuration to set a custom type for your `context`, and it will\naffect all the resolvers, without the need to override it using generics each time.\nIf you wish to use an external type and import it from another file, you can use `add` plugin\nand add the required `import` statement, or you can use a `module#type` syntax.", "type": "string" }, "fieldContextTypes": { "$ref": "#/definitions/Array_1", "description": "Use this to set a custom type for a specific field `context`.\nIt will only affect the targeted resolvers.\nYou can either use `Field.Path#ContextTypeName` or `Field.Path#ExternalFileName#ContextTypeName`" }, "rootValueType": { "description": "Use this configuration to set a custom type for the `rootValue`, and it will\naffect resolvers of all root types (Query, Mutation and Subscription), without the need to override it using generics each time.\nIf you wish to use an external type and import it from another file, you can use `add` plugin\nand add the required `import` statement, or you can use both `module#type` or `module#namespace#type` syntax.", "type": "string" }, "directiveContextTypes": { "$ref": "#/definitions/Array_1", "description": "Use this to set a custom type for a specific field `context` decorated by a directive.\nIt will only affect the targeted resolvers.\nYou can either use `Field.Path#ContextTypeName` or `Field.Path#ExternalFileName#ContextTypeName`\n\nContextTypeName should by a generic Type that take the context or field context type as only type parameter." }, "mapperTypeSuffix": { "description": "Adds a suffix to the imported names to prevent name clashes.", "type": "string" }, "mappers": { "description": "Replaces a GraphQL type usage with a custom type, allowing you to return custom object from\nyour resolvers.\nYou can use both `module#type` and `module#namespace#type` syntax.", "type": "object", "additionalProperties": { "type": "string" } }, "defaultMapper": { "description": "Allow you to set the default mapper when it's not being override by `mappers` or generics.\nYou can specify a type name, or specify a string in `module#type` or `module#namespace#type` format.\nThe default value of mappers is the TypeScript type generated by `typescript` package.", "type": "string" }, "avoidOptionals": { "description": "This will cause the generator to avoid using optionals (`?`),\nso all field resolvers must be implemented in order to avoid compilation errors.\nDefault value: \"false\"", "anyOf": [{ "$ref": "#/definitions/AvoidOptionalsConfig" }, { "type": "boolean" }] }, "showUnusedMappers": { "description": "Warns about unused mappers.\nDefault value: \"true\"", "type": "boolean" }, "enumValues": { "$ref": "#/definitions/EnumValuesMap", "description": "Overrides the default value of enum values declared in your GraphQL schema, supported\nin this plugin because of the need for integration with `typescript` package.\nSee documentation under `typescript` plugin for more information and examples." }, "resolverTypeWrapperSignature": { "description": "Allow you to override `resolverTypeWrapper` definition.\nDefault value: \"Promise | T\"", "type": "string" }, "federation": { "description": "Supports Apollo Federation\nDefault value: \"false\"", "type": "boolean" }, "enumPrefix": { "description": "Allow you to disable prefixing for generated enums, works in combination with `typesPrefix`.\nDefault value: \"true\"", "type": "boolean" }, "enumSuffix": { "description": "Allow you to disable suffixing for generated enums, works in combination with `typesSuffix`.\nDefault value: \"true\"", "type": "boolean" }, "customDirectives": { "description": "Configures behavior for custom directives from various GraphQL libraries.", "type": "object", "properties": { "semanticNonNull": { "type": "boolean" } } }, "optionalResolveType": { "description": "Sets the `__resolveType` field as optional field.\nDefault value: \"false\"", "type": "boolean" }, "immutableTypes": { "description": "Generates immutable types by adding `readonly` to properties and uses `ReadonlyArray`.\nDefault value: \"false\"", "type": "boolean" }, "namespacedImportName": { "description": "Prefixes all GraphQL related generated types with that value, as namespaces import.\nYou can use this feature to allow separation of plugins to different files.\nDefault value: \"''\"", "type": "string" }, "resolverTypeSuffix": { "description": "Suffix we add to each generated type resolver.\nDefault value: \"Resolvers\"", "type": "string" }, "allResolversTypeName": { "description": "The type name to use when exporting all resolvers signature as unified type.\nDefault value: \"Resolvers\"", "type": "string" }, "internalResolversPrefix": { "type": "string", "description": "Defines the prefix value used for `__resolveType` and `__isTypeOf` resolvers.\nIf you are using `mercurius-js`, please set this field to empty string for better compatibility.\nDefault value: \"'__'\"" }, "resolversNonOptionalTypename": { "description": "Makes `__typename` of resolver mappings non-optional without affecting the base types.\nDefault value: \"false\"", "anyOf": [{ "$ref": "#/definitions/ResolversNonOptionalTypenameConfig" }, { "type": "boolean" }] }, "avoidCheckingAbstractTypesRecursively": { "type": "boolean", "description": "If true, recursively goes through all object type's fields, checks if they have abstract types and generates expected types correctly.\nThis may not work for cases where provided default mapper types are also nested e.g. `defaultMapper: DeepPartial<{T}>` or `defaultMapper: Partial<{T}>`.\nDefault value: \"false\"" }, "addInterfaceFieldResolverTypes": { "description": "If true, add field resolver types to Interfaces.\nBy default, GraphQL Interfaces do not trigger any field resolvers,\nmeaning every implementing type must implement the same resolver for the shared fields.\n\nSome tools provide a way to change the default behaviour by making GraphQL Objects inherit\nmissing resolvers from their Interface types. In these cases, it is fine to turn this option to true.\n\nFor example, if you are using `@graphql-tools/schema#makeExecutableSchema` with `inheritResolversFromInterfaces: true`,\nyou can make `addInterfaceFieldResolverTypes: true` as well\nhttps://the-guild.dev/graphql/tools/docs/generate-schema#makeexecutableschema\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap_1", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention_1", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\n\"mask\" transforms the types for use with fragment masking. Useful when masked types are needed when not using the \"client\" preset e.g. such as combining it with Apollo Client's data masking feature.\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" }, "importExtension": { "description": "Append this extension to all imports.\nUseful for ESM environments that require file extensions in import statements.", "anyOf": [ { "type": "array", "items": { "type": "string" } }, { "enum": [""], "type": "string" } ] }, "extractAllFieldsToTypes": { "description": "Extract all field types to their own types, instead of inlining them.\nThis helps to reduce type duplication, and makes type errors more readable.\nIt can also significantly reduce the size of the generated code, the generation time,\nand the typechecking time.\nDefault value: \"false\"", "type": "boolean" }, "printFieldsOnNewLines": { "description": "If you prefer to have each field in generated types printed on a new line, set this to true.\nThis can be useful for improving readability of the resulting types,\nwithout resorting to running tools like Prettier on the output.\nDefault value: \"false\"", "type": "boolean" }, "includeExternalFragments": { "description": "Whether to include external fragments in the generated code. External fragments are not defined\nin the same location as the operation definition.\nDefault value: \"false\"", "type": "boolean" } } }, "ApolloAngularRawPluginConfig": { "description": "This plugin generates Apollo services (`Query`, `Mutation` and `Subscription`) with TypeScript typings.\n\nIt will generate a strongly typed Angular service for every defined query, mutation or subscription. The generated Angular services are ready to inject and use within your Angular component.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\nTo shed some more light regards this template, it's recommended to go through this article: https://apollo-angular.com/docs/get-started, and to read the Code Generation with Apollo Angular: https://the-guild.dev/blog/apollo-angular-12", "type": "object", "properties": { "apolloAngularVersion": { "description": "Version of `apollo-angular` package\nDefault value: \"2\"", "type": "number" }, "ngModule": { "description": "Allows to define `ngModule` as part of the plugin's config so it's globally available.", "type": "string" }, "namedClient": { "description": "Defined the global value of `namedClient`.", "type": "string" }, "serviceName": { "description": "Defined the global value of `serviceName`.", "type": "string" }, "serviceProvidedInRoot": { "description": "Defined the global value of `serviceProvidedInRoot`.", "type": "boolean" }, "serviceProvidedIn": { "description": "Define the Injector of the SDK class.", "type": "string" }, "sdkClass": { "description": "Set to `true` in order to generate a SDK service class that uses all generated services.\nDefault value: \"false\"", "type": "boolean" }, "querySuffix": { "description": "Allows to define a custom suffix for query operations.\nDefault value: \"GQL\"", "type": "string" }, "mutationSuffix": { "description": "Allows to define a custom suffix for mutation operations.\nDefault value: \"GQL\"", "type": "string" }, "subscriptionSuffix": { "description": "Allows to define a custom suffix for Subscription operations.\nDefault value: \"GQL\"", "type": "string" }, "apolloAngularPackage": { "description": "Allows to define a custom Apollo-Angular package to import types from.\nDefault value: \"'apollo-angular'\"", "type": "string" }, "additionalDI": { "description": "Add additional dependency injections for generated services\nDefault value: \"\"", "type": "array", "items": { "type": "string" } }, "addExplicitOverride": { "description": "Add `override` modifier to make the generated code compatible with the `noImplicitOverride` option of Typescript v4.3+.\nDefault value: \"false\"", "type": "boolean" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "NhostPluginConfig": { "description": "This plugin generates the Typescript schema that enables queries and mutations to be typed in the Nhost SDK.", "type": "object", "properties": { "scalars": { "$ref": "#/definitions/ScalarsMap_3", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." } } }, "UrqlRawPluginConfig": { "description": "This plugin generates `urql` (https://github.com/FormidableLabs/urql) components and HOC with TypeScript typings.", "type": "object", "properties": { "withComponent": { "description": "Customized the output by enabling/disabling the generated Component.\nDefault value: \"false\"", "type": "boolean" }, "withHooks": { "description": "Customized the output by enabling/disabling the generated React Hooks.\nDefault value: \"true\"", "type": "boolean" }, "urqlImportFrom": { "description": "You can specify module that exports components `Query`, `Mutation`, `Subscription` and HOCs\nThis is useful for further abstraction of some common tasks (e.g. error handling).\nFilepath relative to generated file can be also specified.\nDefault value: \"urql\"", "type": "string" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "ReactApolloRawPluginConfig": { "description": "This plugin generates React Apollo components and HOC with TypeScript typings.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.", "type": "object", "properties": { "withComponent": { "description": "Customize the output by enabling/disabling the generated Component (deprecated since Apollo-Client v3). For more details: https://apollographql.com/docs/react/api/react/components\nDefault value: \"false\"", "type": "boolean" }, "withHOC": { "description": "Customize the output by enabling/disabling the HOC (deprecated since Apollo-Client v3). For more details: https://apollographql.com/docs/react/api/react/hoc\nDefault value: \"false\"", "type": "boolean" }, "withHooks": { "description": "Customized the output by enabling/disabling the generated React Hooks. For more details: https://apollographql.com/docs/react/api/react/hooks\nDefault value: \"true\"", "type": "boolean" }, "withMutationFn": { "description": "Customized the output by enabling/disabling the generated mutation function signature.\nDefault value: \"true\"", "type": "boolean" }, "withRefetchFn": { "description": "Enable generating a function to be used with refetchQueries\nDefault value: \"false\"", "type": "boolean" }, "apolloReactCommonImportFrom": { "description": "Customize the package where apollo-react common lib is loaded from.\nDefault value: \"@apollo/react-common\"", "type": "string" }, "apolloReactComponentsImportFrom": { "description": "Customize the package where apollo-react component lib is loaded from.\nDefault value: \"@apollo/react-components\"", "type": "string" }, "apolloReactHocImportFrom": { "description": "Customize the package where apollo-react HOC lib is loaded from.\nDefault value: \"@apollo/react-hoc\"", "type": "string" }, "apolloReactHooksImportFrom": { "description": "Customize the package where apollo-react hooks lib is loaded from.\nDefault value: \"@apollo/react-hooks\"", "type": "string" }, "componentSuffix": { "description": "You can specify a suffix that gets attached to the name of the generated component.\nDefault value: \"Component\"", "type": "string" }, "reactApolloVersion": { "description": "Sets the version of react-apollo.\nIf you are using the old (deprecated) package of `react-apollo`, please set this configuration to `2`.\nIf you are using Apollo-Client v3, please set this to `3`.\nDefault value: \"3\"", "enum": [2, 3], "type": "number" }, "withResultType": { "description": "Customized the output by enabling/disabling the generated result type.\nDefault value: \"true\"", "type": "boolean" }, "withMutationOptionsType": { "description": "Customized the output by enabling/disabling the generated mutation option type.\nDefault value: \"true\"", "type": "boolean" }, "addDocBlocks": { "description": "Allows you to enable/disable the generation of docblocks in generated code.\nSome IDE's (like VSCode) add extra inline information with docblocks, you can disable this feature if your preferred IDE does not.\nDefault value: \"true\"", "type": "boolean" }, "defaultBaseOptions": { "type": "object", "additionalProperties": { "type": "string" } }, "hooksSuffix": { "type": "string" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "VueApolloRawPluginConfig": { "description": "This plugin generates", "type": "object", "properties": { "withCompositionFunctions": { "description": "Customized the output by enabling/disabling the generated Vue composition functions.\nDefault value: \"true\"", "type": "boolean" }, "vueApolloComposableImportFrom": { "type": "string", "description": "\nDefault value: \"\"" }, "vueCompositionApiImportFrom": { "type": "string", "description": "\nDefault value: \"\"" }, "addDocBlocks": { "description": "Allows you to enable/disable the generation of docblocks in generated code.\nSome IDE's (like VSCode) add extra inline information with docblocks, you can disable this feature if your preferred IDE does not.\nDefault value: \"true\"", "type": "boolean" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "VueApolloSmartOpsRawPluginConfig": { "description": "This plugin generates Vue Apollo Smart Query, Smart Subscription and mutation operation functions with\nTypeScript typings.\n\nThis plugin relies on some helper functions and types from the `vue-apollo-smart-ops` package. That package also adds\nsome optional functionality for improved error handling in Vue Apollo operations which can be configured in the\ngenerated code from this plugin.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` -\nand thus shares a similar configuration.", "type": "object", "properties": { "withSmartOperationFunctions": { "description": "Customize the output by enabling/disabling the generated Vue Apollo Smart Operations functions.\nDefault value: \"true\"", "type": "boolean" }, "vueApolloOperationFunctionsImportFrom": { "description": "The `typescript-vue-apollo-smart-ops` plugin requires three functions that are used to define your\nquery, subscription and mutation operation functions:\n\n- `createMutationFunction`\n- `createSmartQueryOptionsFunction`\n- `createSmartSubscriptionOptionsFunction`\n\nBy default, these functions are provided by the `vue-apollo-smart-ops` package, but you can substitute\nyour own import path if you want to replace them with other implementations.\nDefault value: \"vue-apollo-smart-ops\"", "type": "string" }, "vueApolloErrorType": { "description": "The operation functions generated by `typescript-vue-apollo-smart-ops` include some functionality for\nerror handling. This configuration parameter allows you to customise the name of the error type that\nwill be used. The default is to use `ApolloError` from the `apollo-client` package.\nDefault value: \"ApolloError\"", "type": "string" }, "vueApolloErrorTypeImportFrom": { "description": "The operation functions generated by `typescript-vue-apollo-smart-ops` include some functionality for\nerror handling. This configuration parameter allows you to customise the package where the error type\nwill be imported from. The default is to use `ApolloError` from the `apollo-client` package.\nDefault value: \"vue-apollo-smart-ops\"", "type": "string" }, "vueApolloErrorHandlerFunction": { "description": "The operation functions generated by `typescript-vue-apollo-smart-ops` include some functionality for\nerror handling. You may supply an error handler function that will be called when an error occurs in\na query, subscription or mutation operation. This function should implement the\n`ApolloOperationErrorHandlerFunction` interface from `vue-apollo-smart-ops` package. You can\nhave a custom handler in your app that shows a notification to the user, for example. If unspecified,\nthis functionality will be disabled and errors handled (or not) by Vue Apollo in the normal way.\nDefault value: \"undefined\"", "type": "string" }, "vueApolloErrorHandlerFunctionImportFrom": { "description": "The import path where `vueApolloErrorHandlerFunction` should be imported from. Can be a package name\nor a local file path (anything that works in an import statement).\nDefault value: \"undefined\"", "type": "string" }, "vueAppType": { "description": "The operation functions generated by `typescript-vue-apollo-smart-ops` include some functionality for\nerror handling. When an error occurs, the Vue app instance is passed to the error handler. You can\ncustomise the expected type of the app object. For example, a Nuxt.js app might use `NuxtApp` from\n`@nuxt/types/app` instead. When unspecified, the default type is `Vue` from `vue/types/vue`.\nDefault value: \"undefined\"", "type": "string" }, "vueAppTypeImportFrom": { "description": "The import path where `vueAppType` should be imported from. Can be a package name or a local file path\n(anything that works in an import statement).\nDefault value: \"undefined\"", "type": "string" }, "addDocBlocks": { "description": "Allows you to enable/disable the generation of docblocks in generated code.\nSome IDE's (like VSCode) add extra inline information with docblocks, you can disable this feature if\nyour preferred IDE does not.\nDefault value: \"true\"", "type": "boolean" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "VueUrqlRawPluginConfig": { "description": "This plugin generates `urql` (https://github.com/FormidableLabs/urql) composition functions with TypeScript typings.", "type": "object", "properties": { "withComposition": { "description": "Customized the output by enabling/disabling the generated Vue Composition functions.\nDefault value: \"true\"", "type": "boolean" }, "urqlImportFrom": { "description": "You can specify module that exports components `Query`, `Mutation`, `Subscription`\nThis is useful for further abstraction of some common tasks (e.g. error handling).\nFilepath relative to generated file can be also specified.\nDefault value: \"urql\"", "type": "string" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "StencilApolloRawPluginConfig": { "description": "This plugin generates Stencil Apollo functional components typings\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.", "type": "object", "properties": { "componentType": { "$ref": "#/definitions/StencilComponentType", "description": "Customize the output of the plugin - you can choose to generate a Component class or a function component.\nDefault value: \"functional\"" }, "noGraphQLTag": { "description": "Deprecated. Changes the documentMode to `documentNode`.\nDefault value: \"false\"", "type": "boolean" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentNode: documentMode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "TypeScriptDocumentNodesRawPluginConfig": { "description": "This plugin generates TypeScript source `.ts` file from GraphQL files `.graphql`.", "type": "object", "properties": { "namingConvention": { "$ref": "#/definitions/NamingConvention_1", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "namePrefix": { "description": "Adds prefix to the name\nDefault value: \"\"", "type": "string" }, "nameSuffix": { "description": "Adds suffix to the name\nDefault value: \"\"", "type": "string" }, "fragmentPrefix": { "description": "Adds prefix to the fragment variable\nDefault value: \"\"", "type": "string" }, "fragmentSuffix": { "description": "Adds suffix to the fragment variable\nDefault value: \"\"", "type": "string" }, "gqlImport": { "description": "Customize from which module will `gql` be imported from.\nThis is useful if you want to use modules other than `graphql-tag`, e.g. `graphql.macro`.\nDefault value: \"graphql-tag#gql\"", "type": "string" }, "documentNodeImport": { "description": "Customize from which module will `DocumentNode` be imported from.\nThis is useful if you want to use modules other than `graphql`, e.g. `@graphql-typed-document-node`.\nDefault value: \"graphql#DocumentNode\"", "type": "string" }, "noExport": { "description": "Set this configuration to `true` if you wish to tell codegen to generate code with no `export` identifier.\nDefault value: \"false\"", "type": "boolean" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "documentVariablePrefix": { "description": "Changes the GraphQL operations variables prefix.\nDefault value: \"\"", "type": "string" }, "documentVariableSuffix": { "description": "Changes the GraphQL operations variables suffix.\nDefault value: \"Document\"", "type": "string" }, "fragmentVariablePrefix": { "description": "Changes the GraphQL fragments variables prefix.\nDefault value: \"\"", "type": "string" }, "fragmentVariableSuffix": { "description": "Changes the GraphQL fragments variables suffix.\nDefault value: \"FragmentDoc\"", "type": "string" }, "documentMode": { "$ref": "#/definitions/DocumentMode_2", "description": "Declares how DocumentNode are created:\n\n- `graphQLTag`: `graphql-tag` or other modules (check `gqlImport`) will be used to generate document nodes. If this is used, document nodes are generated on client side i.e. the module used to generate this will be shipped to the client\n- `documentNode`: document nodes will be generated as objects when we generate the templates.\n- `documentNodeImportFragments`: Similar to documentNode except it imports external fragments instead of embedding them.\n- `external`: document nodes are imported from an external file. To be used with `importDocumentNodeExternallyFrom`\n\nNote that some plugins (like `typescript-graphql-request`) also supports `string` for this parameter.\nDefault value: \"graphQLTag\"" }, "optimizeDocumentNode": { "description": "If you are using `documentMode: documentNode | documentNodeImportFragments`, you can set this to `true` to apply document optimizations for your GraphQL document.\nThis will remove all \"loc\" and \"description\" fields from the compiled document, and will remove all empty arrays (such as `directives`, `arguments` and `variableDefinitions`).\nDefault value: \"true\"", "type": "boolean" }, "importOperationTypesFrom": { "description": "This config is used internally by presets, but you can use it manually to tell codegen to prefix all base types that it's using.\nThis is useful if you wish to generate base types from `typescript-operations` plugin into a different file, and import it from there.\nDefault value: \"\"", "type": "string" }, "importDocumentNodeExternallyFrom": { "description": "This config should be used if `documentMode` is `external`. This has 2 usage:\n\n- any string: This would be the path to import document nodes from. This can be used if we want to manually create the document nodes e.g. Use `graphql-tag` in a separate file and export the generated document\n- 'near-operation-file': This is a special mode that is intended to be used with `near-operation-file` preset to import document nodes from those files. If these files are `.graphql` files, we make use of webpack loader.\nDefault value: \"\"", "type": "string" }, "pureMagicComment": { "description": "This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap_1", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\n\"mask\" transforms the types for use with fragment masking. Useful when masked types are needed when not using the \"client\" preset e.g. such as combining it with Apollo Client's data masking feature.\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" }, "importExtension": { "description": "Append this extension to all imports.\nUseful for ESM environments that require file extensions in import statements.", "anyOf": [ { "type": "array", "items": { "type": "string" } }, { "enum": [""], "type": "string" } ] }, "extractAllFieldsToTypes": { "description": "Extract all field types to their own types, instead of inlining them.\nThis helps to reduce type duplication, and makes type errors more readable.\nIt can also significantly reduce the size of the generated code, the generation time,\nand the typechecking time.\nDefault value: \"false\"", "type": "boolean" }, "printFieldsOnNewLines": { "description": "If you prefer to have each field in generated types printed on a new line, set this to true.\nThis can be useful for improving readability of the resulting types,\nwithout resorting to running tools like Prettier on the output.\nDefault value: \"false\"", "type": "boolean" }, "includeExternalFragments": { "description": "Whether to include external fragments in the generated code. External fragments are not defined\nin the same location as the operation definition.\nDefault value: \"false\"", "type": "boolean" } } }, "MSWConfig": { "description": "This plugin generates `msw` (https://github.com/mswjs/msw) mock handlers with TypeScript typings.", "type": "object", "properties": { "link": { "description": "GraphQL endpoint to use when working with multiple backends.", "type": "object", "properties": { "endpoint": { "type": "string" }, "name": { "type": "string" }, "withSuffix": { "type": "boolean" } } } } }, "JavaApolloAndroidPluginConfig": { "description": "This plugin and presets creates generated mappers and parsers for a complete type-safe GraphQL requests, for developers that uses Apollo Android runtime.", "type": "object", "properties": { "package": { "description": "Customize the Java package name for the generated operations. The default package name will be generated according to the output file path.", "type": "string" }, "typePackage": { "description": "Customize the Java package name for the types generated based on input types.", "type": "string" }, "fragmentPackage": { "description": "Customize the Java package name for the fragments generated classes.", "type": "string" }, "fileType": { "$ref": "#/definitions/FileType" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "JavaResolversPluginRawConfig": { "type": "object", "properties": { "package": { "description": "Customize the Java package name. The default package name will be generated according to the output file path.", "type": "string" }, "mappers": { "description": "Allow you to replace specific GraphQL types with your custom model classes. This is useful when you want to make sure your resolvers returns the correct class.\nThe default value is the values set by `defaultMapper` configuration.\nYou can use a direct path to the package, or use `package#class` syntax to have it imported.", "type": "object", "additionalProperties": { "type": "string" } }, "defaultMapper": { "description": "Sets the default mapper value in case it's not specified by `mappers`.\nYou can use a direct path to the package, or use `package#class` syntax to have it imported.\nThe default mapper is Java's `Object`.\nDefault value: \"Object\"", "type": "string" }, "className": { "description": "Allow you to customize the parent class name.\nDefault value: \"Resolvers\"", "type": "string" }, "listType": { "description": "Allow you to customize the list type.\nDefault value: \"Iterable\"", "type": "string" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "KotlinResolversPluginRawConfig": { "type": "object", "properties": { "package": { "description": "Customize the Java package name. The default package name will be generated according to the output file path.", "type": "string" }, "enumValues": { "$ref": "#/definitions/EnumValuesMap_2", "description": "Overrides the default value of enum values declared in your GraphQL schema." }, "listType": { "description": "Allow you to customize the list type\nDefault value: \"Iterable\"", "type": "string" }, "withTypes": { "description": "Allow you to enable generation for the types\nDefault value: \"false\"", "type": "boolean" }, "omitJvmStatic": { "description": "Allow you to omit JvmStatic annotation\nDefault value: \"false\"", "type": "boolean" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "FlowPluginConfig": { "description": "This plugin generates Flow types based on your `GraphQLSchema`.\n\nIt generates types for your entire schema: types, input types, enum, interface, scalar and union.", "type": "object", "properties": { "useFlowExactObjects": { "description": "Generates Flow types as Exact types.\nDefault value: \"true\"", "type": "boolean" }, "useFlowReadOnlyTypes": { "description": "Generates read-only Flow types\nDefault value: \"false\"", "type": "boolean" }, "addUnderscoreToArgsType": { "description": "Adds `_` to generated `Args` types in order to avoid duplicate identifiers.", "type": "boolean" }, "enumValues": { "$ref": "#/definitions/EnumValuesMap_2", "description": "Overrides the default value of enum values declared in your GraphQL schema.\nYou can also map the entire enum to an external type by providing a string that of `module#type`." }, "declarationKind": { "description": "Overrides the default output for various GraphQL elements.", "anyOf": [ { "$ref": "#/definitions/DeclarationKindConfig_2" }, { "enum": ["abstract class", "class", "interface", "type"], "type": "string" } ] }, "enumPrefix": { "description": "Allow you to disable prefixing for generated enums, works in combination with `typesPrefix`.\nDefault value: \"true\"", "type": "boolean" }, "fieldWrapperValue": { "description": "Allow you to add wrapper for field type, use T as the generic value. Make sure to set `wrapFieldDefinitions` to `true` in order to make this flag work.\nDefault value: \"T\"", "type": "string" }, "wrapFieldDefinitions": { "description": "Set to `true` in order to wrap field definitions with `FieldWrapper`.\nThis is useful to allow return types such as Promises and functions.\nDefault value: \"false\"", "type": "boolean" }, "onlyEnums": { "description": "This will cause the generator to emit types for enums only\nDefault value: \"false\"", "type": "boolean" }, "onlyOperationTypes": { "description": "This will cause the generator to emit types for operations only (basically only enums and scalars)\nDefault value: \"false\"", "type": "boolean" }, "ignoreEnumValuesFromSchema": { "description": "This will cause the generator to ignore enum values defined in GraphQLSchema\nDefault value: \"false\"", "type": "boolean" }, "wrapEntireFieldDefinitions": { "type": "boolean", "description": "Set to `true` in order to wrap field definitions with `EntireFieldWrapper`.\nThis is useful to allow return types such as Promises and functions for fields.\nDiffers from `wrapFieldDefinitions` in that this wraps the entire field definition if i.e. the field is an Array, while\n`wrapFieldDefinitions` will wrap every single value inside the array.\nDefault value: \"true\"" }, "entireFieldWrapperValue": { "type": "string", "description": "Allow to override the type value of `EntireFieldWrapper`. This wrapper applies outside of Array and Maybe\nunlike `fieldWrapperValue`, that will wrap the inner type.\nDefault value: \"T | Promise | (() => T | Promise)\"" }, "directiveArgumentAndInputFieldMappings": { "$ref": "#/definitions/DirectiveArgumentAndInputFieldMappings_2", "description": "Replaces a GraphQL scalar with a custom type based on the applied directive on an argument or input field.\n\nYou can use both `module#type` and `module#namespace#type` syntax.\nWill NOT work with introspected schemas since directives are not exported.\nOnly works with directives on ARGUMENT_DEFINITION or INPUT_FIELD_DEFINITION.\n\n**WARNING:** Using this option does only change the type definitions.\n\nFor actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://graphql-tools.com/docs/schema-directives)) that apply those rules!\nOtherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors.\n\nPlease use this configuration option with care!" }, "directiveArgumentAndInputFieldMappingTypeSuffix": { "description": "Adds a suffix to the imported names to prevent name clashes.", "type": "string" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "FlowResolversPluginConfig": { "description": "This plugin generates resolvers signature based on your `GraphQLSchema`.\n\nIt generates types for your entire schema: types, input types, enum, interface, scalar and union.\n\nThis plugin requires you to use `@graphql-codegen/flow` as well, because it depends on it's types.", "type": "object", "properties": { "addUnderscoreToArgsType": { "description": "Adds `_` to generated `Args` types in order to avoid duplicate identifiers.", "type": "boolean" }, "contextType": { "description": "Use this configuration to set a custom type for your `context`, and it will\naffect all the resolvers, without the need to override it using generics each time.\nIf you wish to use an external type and import it from another file, you can use `add` plugin\nand add the required `import` statement, or you can use a `module#type` syntax.", "type": "string" }, "fieldContextTypes": { "$ref": "#/definitions/Array_1", "description": "Use this to set a custom type for a specific field `context`.\nIt will only affect the targeted resolvers.\nYou can either use `Field.Path#ContextTypeName` or `Field.Path#ExternalFileName#ContextTypeName`" }, "rootValueType": { "description": "Use this configuration to set a custom type for the `rootValue`, and it will\naffect resolvers of all root types (Query, Mutation and Subscription), without the need to override it using generics each time.\nIf you wish to use an external type and import it from another file, you can use `add` plugin\nand add the required `import` statement, or you can use both `module#type` or `module#namespace#type` syntax.", "type": "string" }, "directiveContextTypes": { "$ref": "#/definitions/Array_1", "description": "Use this to set a custom type for a specific field `context` decorated by a directive.\nIt will only affect the targeted resolvers.\nYou can either use `Field.Path#ContextTypeName` or `Field.Path#ExternalFileName#ContextTypeName`\n\nContextTypeName should by a generic Type that take the context or field context type as only type parameter." }, "mapperTypeSuffix": { "description": "Adds a suffix to the imported names to prevent name clashes.", "type": "string" }, "mappers": { "description": "Replaces a GraphQL type usage with a custom type, allowing you to return custom object from\nyour resolvers.\nYou can use both `module#type` and `module#namespace#type` syntax.", "type": "object", "additionalProperties": { "type": "string" } }, "defaultMapper": { "description": "Allow you to set the default mapper when it's not being override by `mappers` or generics.\nYou can specify a type name, or specify a string in `module#type` or `module#namespace#type` format.\nThe default value of mappers is the TypeScript type generated by `typescript` package.", "type": "string" }, "avoidOptionals": { "description": "This will cause the generator to avoid using optionals (`?`),\nso all field resolvers must be implemented in order to avoid compilation errors.\nDefault value: \"false\"", "anyOf": [{ "$ref": "#/definitions/AvoidOptionalsConfig_2" }, { "type": "boolean" }] }, "showUnusedMappers": { "description": "Warns about unused mappers.\nDefault value: \"true\"", "type": "boolean" }, "enumValues": { "$ref": "#/definitions/EnumValuesMap_2", "description": "Overrides the default value of enum values declared in your GraphQL schema, supported\nin this plugin because of the need for integration with `typescript` package.\nSee documentation under `typescript` plugin for more information and examples." }, "resolverTypeWrapperSignature": { "description": "Allow you to override `resolverTypeWrapper` definition.\nDefault value: \"Promise | T\"", "type": "string" }, "federation": { "description": "Supports Apollo Federation\nDefault value: \"false\"", "type": "boolean" }, "enumPrefix": { "description": "Allow you to disable prefixing for generated enums, works in combination with `typesPrefix`.\nDefault value: \"true\"", "type": "boolean" }, "optionalResolveType": { "description": "Sets the `__resolveType` field as optional field.\nDefault value: \"false\"", "type": "boolean" }, "immutableTypes": { "description": "Generates immutable types by adding `readonly` to properties and uses `ReadonlyArray`.\nDefault value: \"false\"", "type": "boolean" }, "namespacedImportName": { "description": "Prefixes all GraphQL related generated types with that value, as namespaces import.\nYou can use this feature to allow separation of plugins to different files.\nDefault value: \"''\"", "type": "string" }, "resolverTypeSuffix": { "description": "Suffix we add to each generated type resolver.\nDefault value: \"Resolvers\"", "type": "string" }, "allResolversTypeName": { "description": "The type name to use when exporting all resolvers signature as unified type.\nDefault value: \"Resolvers\"", "type": "string" }, "internalResolversPrefix": { "type": "string", "description": "Defines the prefix value used for `__resolveType` and `__isTypeOf` resolvers.\nIf you are using `mercurius-js`, please set this field to empty string for better compatibility.\nDefault value: \"'__'\"" }, "onlyResolveTypeForInterfaces": { "type": "boolean", "description": "Turning this flag to `true` will generate resolver signature that has only `resolveType` for interfaces, forcing developers to write inherited type resolvers in the type itself.\nDefault value: \"false\"" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "FlowDocumentsPluginConfig": { "description": "This plugin generates Flow types based on your `GraphQLSchema` and your GraphQL operations and fragments.\n\nIt generates types for your GraphQL documents: Query, Mutation, Subscription and Fragment.\n\nThis plugin requires you to use `@graphql-codegen/flow` as well, because it depends on its types.", "type": "object", "properties": { "useFlowExactObjects": { "description": "Generates Flow types as Exact types.\nDefault value: \"true\"", "type": "boolean" }, "useFlowReadOnlyTypes": { "description": "Generates read-only Flow types\nDefault value: \"false\"", "type": "boolean" }, "flattenGeneratedTypes": { "description": "Flatten fragment spread and inline fragments into a simple selection set before generating.\nDefault value: \"false\"", "type": "boolean" }, "preResolveTypes": { "description": "Uses primitive types where possible.\nSet to `false` in order to use `Pick` and take use the types generated by `typescript` plugin.\nDefault value: \"true\"", "type": "boolean" }, "skipTypeNameForRoot": { "description": "Avoid adding `__typename` for root types. This is ignored when a selection explicitly specifies `__typename`.\nDefault value: \"false\"", "type": "boolean" }, "globalNamespace": { "description": "Puts all generated code under `global` namespace. Useful for Stencil integration.\nDefault value: \"false\"", "type": "boolean" }, "operationResultSuffix": { "description": "Adds a suffix to generated operation result type names\nDefault value: \"\"", "type": "string" }, "dedupeOperationSuffix": { "description": "Set this configuration to `true` if you wish to make sure to remove duplicate operation name suffix.\nDefault value: \"false\"", "type": "boolean" }, "omitOperationSuffix": { "description": "Set this configuration to `true` if you wish to disable auto add suffix of operation name, like `Query`, `Mutation`, `Subscription`, `Fragment`.\nDefault value: \"false\"", "type": "boolean" }, "exportFragmentSpreadSubTypes": { "description": "If set to true, it will export the sub-types created in order to make it easier to access fields declared under fragment spread.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "If set to true, it will enable support for parsing variables on fragments.\nDefault value: \"false\"", "type": "boolean" }, "mergeFragmentTypes": { "description": "If set to true, merge equal fragment interfaces.\nDefault value: \"false\"", "type": "boolean" }, "addUnderscoreToArgsType": { "description": "Adds `_` to generated `Args` types in order to avoid duplicate identifiers.", "type": "boolean" }, "enumValues": { "$ref": "#/definitions/EnumValuesMap_2", "description": "Overrides the default value of enum values declared in your GraphQL schema.\nYou can also map the entire enum to an external type by providing a string that of `module#type`." }, "declarationKind": { "description": "Overrides the default output for various GraphQL elements.", "anyOf": [ { "$ref": "#/definitions/DeclarationKindConfig_2" }, { "enum": ["abstract class", "class", "interface", "type"], "type": "string" } ] }, "enumPrefix": { "description": "Allow you to disable prefixing for generated enums, works in combination with `typesPrefix`.\nDefault value: \"true\"", "type": "boolean" }, "fieldWrapperValue": { "description": "Allow you to add wrapper for field type, use T as the generic value. Make sure to set `wrapFieldDefinitions` to `true` in order to make this flag work.\nDefault value: \"T\"", "type": "string" }, "wrapFieldDefinitions": { "description": "Set to `true` in order to wrap field definitions with `FieldWrapper`.\nThis is useful to allow return types such as Promises and functions.\nDefault value: \"false\"", "type": "boolean" }, "onlyEnums": { "description": "This will cause the generator to emit types for enums only\nDefault value: \"false\"", "type": "boolean" }, "onlyOperationTypes": { "description": "This will cause the generator to emit types for operations only (basically only enums and scalars)\nDefault value: \"false\"", "type": "boolean" }, "ignoreEnumValuesFromSchema": { "description": "This will cause the generator to ignore enum values defined in GraphQLSchema\nDefault value: \"false\"", "type": "boolean" }, "wrapEntireFieldDefinitions": { "type": "boolean", "description": "Set to `true` in order to wrap field definitions with `EntireFieldWrapper`.\nThis is useful to allow return types such as Promises and functions for fields.\nDiffers from `wrapFieldDefinitions` in that this wraps the entire field definition if i.e. the field is an Array, while\n`wrapFieldDefinitions` will wrap every single value inside the array.\nDefault value: \"true\"" }, "entireFieldWrapperValue": { "type": "string", "description": "Allow to override the type value of `EntireFieldWrapper`. This wrapper applies outside of Array and Maybe\nunlike `fieldWrapperValue`, that will wrap the inner type.\nDefault value: \"T | Promise | (() => T | Promise)\"" }, "directiveArgumentAndInputFieldMappings": { "$ref": "#/definitions/DirectiveArgumentAndInputFieldMappings_2", "description": "Replaces a GraphQL scalar with a custom type based on the applied directive on an argument or input field.\n\nYou can use both `module#type` and `module#namespace#type` syntax.\nWill NOT work with introspected schemas since directives are not exported.\nOnly works with directives on ARGUMENT_DEFINITION or INPUT_FIELD_DEFINITION.\n\n**WARNING:** Using this option does only change the type definitions.\n\nFor actually ensuring that a type is correct at runtime you will have to use schema transforms (e.g. with [@graphql-tools/utils mapSchema](https://graphql-tools.com/docs/schema-directives)) that apply those rules!\nOtherwise, you might end up with a runtime type mismatch which could cause unnoticed bugs or runtime errors.\n\nPlease use this configuration option with care!" }, "directiveArgumentAndInputFieldMappingTypeSuffix": { "description": "Adds a suffix to the imported names to prevent name clashes.", "type": "string" }, "strictScalars": { "description": "Makes scalars strict.\n\nIf scalars are found in the schema that are not defined in `scalars`\nan error will be thrown during codegen.\nDefault value: \"false\"", "type": "boolean" }, "defaultScalarType": { "description": "Allows you to override the type that unknown scalars will have.\nDefault value: \"any\"", "type": "string" }, "scalars": { "$ref": "#/definitions/ScalarsMap", "description": "Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type." }, "namingConvention": { "$ref": "#/definitions/NamingConvention", "description": "Allow you to override the naming convention of the output.\nYou can either override all namings, or specify an object with specific custom naming convention per output.\nThe format of the converter must be a valid `module#method`.\nAllowed values for specific output are: `typeNames`, `enumValues`.\nYou can also use \"keep\" to keep all GraphQL names as-is.\nAdditionally, you can set `transformUnderscore` to `true` if you want to override the default behavior,\nwhich is to preserve underscores.\n\nAvailable case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`\n[See more](https://github.com/btxtiger/change-case-all)\nDefault value: \"change-case-all#pascalCase\"" }, "typesPrefix": { "description": "Prefixes all the generated types.\nDefault value: \"\"", "type": "string" }, "typesSuffix": { "description": "Suffixes all the generated types.\nDefault value: \"\"", "type": "string" }, "skipTypename": { "description": "Does not add `__typename` to the generated types, unless it was specified in the selection set.\nDefault value: \"false\"", "type": "boolean" }, "nonOptionalTypename": { "description": "Automatically adds `__typename` field to the generated types, even when they are not specified\nin the selection set, and makes it non-optional\nDefault value: \"false\"", "type": "boolean" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "dedupeFragments": { "description": "Removes fragment duplicates for reducing data transfer.\nIt is done by removing sub-fragments imports from fragment definition\nInstead - all of them are imported to the Operation node.\nDefault value: \"false\"", "type": "boolean" }, "inlineFragmentTypes": { "description": "Whether fragment types should be inlined into other operations.\n\"inline\" is the default behavior and will perform deep inlining fragment types within operation type definitions.\n\"combine\" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).\nDefault value: \"inline\"", "type": "string" }, "emitLegacyCommonJSImports": { "description": "Emit legacy common js imports.\nDefault it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).\nDefault value: \"true\"", "type": "boolean" } } }, "IntrospectionPluginConfig": { "description": "This plugin generates a GraphQL introspection file based on your GraphQL schema.", "type": "object", "properties": { "minify": { "description": "Set to `true` in order to minify the JSON output.\nDefault value: \"false\"", "type": "boolean" }, "descriptions": { "description": "Whether to include descriptions in the introspection result.\nDefault value: \"true\"", "type": "boolean" }, "specifiedByUrl": { "description": "Whether to include `specifiedByUrl` in the introspection result.\nDefault value: \"false\"", "type": "boolean" }, "directiveIsRepeatable": { "description": "Whether to include `isRepeatable` flag on directives.\nDefault value: \"true\"", "type": "boolean" }, "schemaDescription": { "description": "Whether to include `description` field on schema.\nDefault value: \"false\"", "type": "boolean" }, "federation": { "type": "boolean" } } }, "FragmentMatcherConfig": { "description": "This plugin generates an introspection file but only with Interfaces and Unions, based on your GraphQLSchema.\n\nIf you are using `apollo-client` and your schema contains `interface` or `union` declaration, it's recommended to use Apollo's Fragment Matcher and the result generated by the plugin.\n\nYou can read more about it in [`apollo-client` documentation](https://apollographql.com/docs/react/data/fragments/#fragments-on-unions-and-interfaces).\n\nFragment Matcher plugin accepts a TypeScript / JavaScript or a JSON file as an output _(`.ts, .tsx, .js, .jsx, .json`)_.\n\nBoth in TypeScript and JavaScript a default export is being used.\n\n> The output is based on the output you choose for the output file name.", "type": "object", "properties": { "module": { "description": "Compatible only with JSON extension, allow you to choose the export type, either `module.exports` or `export default`. Allowed values are: `commonjs`, `es2015`.\nDefault value: \"es2015\"", "enum": ["commonjs", "es2015"], "type": "string" }, "apolloClientVersion": { "description": "Compatible only with TS/TSX/JS/JSX extensions, allow you to generate output based on your Apollo-Client version. Valid values are: `2`, `3`.\nDefault value: \"3\"", "enum": [2, 3], "type": "number" }, "useExplicitTyping": { "description": "Create an explicit type based on your schema. This can help IDEs autofill your fragment matcher. This is mostly useful if you do more with your fragment matcher than just pass it to an Apollo-Client.\nDefault value: \"false\"", "type": "boolean" }, "federation": { "type": "boolean" }, "deterministic": { "description": "When enabled sorts the fragment types lexicographically. This is useful for deterministic output.\nDefault value: \"false\"", "type": "boolean" } } }, "UrqlIntrospectionConfig": { "description": "This plugin generates an introspection file for Schema Awareness feature of Urql Cache Exchange\n\nYou can read more about it in `urql` documentation: https://formidable.com/open-source/urql/docs/graphcache/schema-awareness.\n\nUrql Introspection plugin accepts a TypeScript / JavaScript or a JSON file as an output _(`.ts, .tsx, .js, .jsx, .json`)_.\n\nBoth in TypeScript and JavaScript a default export is being used.\n\n> The output is based on the output you choose for the output file name.", "type": "object", "properties": { "module": { "description": "Compatible only with JSON extension, allow you to choose the export type, either `module.exports` or `export default`. Allowed values are: `commonjs`, `es2015`.\nDefault value: \"es2015\"", "enum": ["commonjs", "es2015"], "type": "string" }, "useTypeImports": { "type": "boolean", "description": "Will use `import type {}` rather than `import {}` when importing only types. This gives\ncompatibility with TypeScript's \"importsNotUsedAsValues\": \"error\" option\nDefault value: \"false\"" }, "includeScalars": { "type": "boolean", "description": "Includes scalar names (instead of an `Any` replacement) in the output when enabled.\nDefault value: \"false\"" }, "includeEnums": { "type": "boolean", "description": "Includes enums (instead of an `Any` replacement) in the output when enabled.\nDefault value: \"false\"" }, "includeInputs": { "type": "boolean", "description": "Includes all input objects (instead of an `Any` replacement) in the output when enabled.\nDefault value: \"false\"" }, "includeDirectives": { "type": "boolean", "description": "Includes all directives in the output when enabled.\nDefault value: \"false\"" } } }, "HasuraAllowListPluginConfig": { "type": "object", "properties": { "collectionName": { "description": "Choose the collection name to be generated. Defaults to allowed-queries\nDefault value: \"allowed-queries\"", "type": "string" }, "configVersion": { "description": "Target metadata config version. Supported versions are 2 and 3.\nThis is mostly for future proofing, currently has no impact as both versions use the same format.\nThe default value _will change_ in the future if/when newer config versions are released.\nDefault value: \"3\"", "enum": [2, 3], "type": "number" }, "globalFragments": { "description": "Whether to source fragments per-document, or globally. If set, will enforce fragment name uniqueness\nDefault value: \"false\"", "type": "boolean" } } }, "ModulesConfig": { "type": "object", "properties": { "baseTypesPath": { "type": "string", "description": "Required, should point to the base schema types file.\nThe key of the output is used a base path for this file." }, "importBaseTypesFrom": { "type": "string", "description": "Overrides the package import for the base types. Use this if you are within a monorepo, and you wish\nto import the base types directly from a different package, and not from a relative path." }, "cwd": { "type": "string", "description": "Optional, override the `cwd` of the execution. We are using `cwd` to figure out the imports between files. Use this if your execution path is not your project root directory.\nDefault value: \"process.cwd()\"" }, "importTypesNamespace": { "type": "string", "description": "Optional, override the name of the import namespace used to import from the `baseTypesPath` file.\nDefault value: \"Types\"" }, "filename": { "type": "string", "description": "Required, sets the file name for the generated files." }, "encapsulateModuleTypes": { "type": "string", "description": "Configure how to encapsulate the module types, to avoid confusion.\n\n`namespace` (default): will wrap all types in a TypeScript namespace, using the module name.\n`prefix`: will prefix all types from a specific module with the module name.\n`none`: will skip encapsulation, and generate type as-is.\nDefault value: \"namespace\"" }, "requireRootResolvers": { "type": "boolean", "description": "Generate resolvers of root types (Query, Mutation and Subscription) as non-optional.\nDefault value: \"false\"" }, "useGraphQLModules": { "type": "boolean", "description": "By default, the generated types will generate some code specific to `graphql-modules` library.\n\nIf you are not using GraphQL-Modules, you can disable this feature by setting this to `false`.\nDefault value: \"true\"" } } }, "NearOperationFileConfig": { "type": "object", "properties": { "baseTypesPath": { "description": "Required, should point to the base schema types file.\nThe key of the output is used a the base path for this file.\n\nIf you wish to use an NPM package or a local workspace package, make sure to prefix the package name with `~`.", "type": "string" }, "importAllFragmentsFrom": { "description": "Overrides all external fragments import types by using a specific file path or a package name.\n\nIf you wish to use an NPM package or a local workspace package, make sure to prefix the package name with `~`.", "anyOf": [{ "$ref": "#/definitions/FragmentImportFromFn" }, { "type": "string" }] }, "fileName": { "description": "Optional, sets a specific file name for the generated files. Use this to override the generated file name when generating files for example based on multiple .graphql files in separate directories.", "type": "string" }, "extension": { "description": "Optional, sets the extension for the generated files. Use this to override the extension if you are using plugins that requires a different type of extensions (such as `typescript-react-apollo`)\nDefault value: \".generated.ts\"", "type": "string" }, "cwd": { "description": "Optional, override the `cwd` of the execution. We are using `cwd` to figure out the imports between files. Use this if your execution path is not your project root directory.\nDefault value: \"process.cwd()\"", "type": "string" }, "folder": { "description": "Optional, defines a folder, (Relative to the source files) where the generated files will be created.\nDefault value: \"''\"", "type": "string" }, "importTypesNamespace": { "description": "Optional, override the name of the import namespace used to import from the `baseTypesPath` file.\nDefault value: \"Types\"", "type": "string" } } }, "ImportTypesConfig": { "type": "object", "properties": { "typesPath": { "description": "Required, should point to the base schema types file.\nThe key of the output is used a the base path for this file.", "type": "string" }, "importTypesNamespace": { "description": "Optional, override the name of the import namespace used to import from the `baseTypesPath` file.\nDefault value: \"Types\"", "type": "string" } } }, "Types.InstanceOrArray": { "anyOf": [ { "$ref": "#/definitions/Types.SchemaWithLoader" }, { "$ref": "#/definitions/Types.SchemaFromCodeFile" }, { "$ref": "#/definitions/Types.UrlSchemaWithOptions" }, { "$ref": "#/definitions/Types.LocalSchemaPathWithOptions" }, { "$ref": "#/definitions/Types.ApolloEngineSchemaOptions" }, { "$ref": "#/definitions/Types.GitHubSchemaOptions" }, { "type": "array", "items": { "$ref": "#/definitions/Types.Schema" } }, { "type": "string" } ] }, "Types.SchemaWithLoader": { "type": "object", "additionalProperties": { "$ref": "#/definitions/Types.SchemaWithLoaderOptions" } }, "Types.SchemaWithLoaderOptions": { "additionalProperties": false, "description": "Loads schema using a pointer, with a custom loader (code file).", "type": "object", "properties": { "loader": { "description": "Specify a path to a custom code file (local or module) that will handle the schema loading.", "type": "string" } } }, "Types.SchemaFromCodeFile": { "type": "object", "additionalProperties": { "$ref": "#/definitions/Types.SchemaFromCodeFileOptions" } }, "Types.SchemaFromCodeFileOptions": { "additionalProperties": false, "description": "Loads schema using a pointer, without using `require` while looking for schemas in code files.", "type": "object", "properties": { "noRequire": { "description": "Set this to `true` in order to tell codegen not to try to `require` files in order to find schema/docs", "type": "boolean" }, "noPluck": { "description": "Set this to `true` in order to tell codegen not to try to extract GraphQL AST strings schema/docs", "type": "boolean" }, "assumeValid": { "description": "Set this to `true` in order to tell codegen to skip documents validation.", "type": "boolean" } } }, "Types.UrlSchemaWithOptions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/Types.UrlSchemaOptions" } }, "Types.UrlSchemaOptions": { "additionalProperties": false, "description": "Loads a schema from remote endpoint, with custom http options.", "type": "object", "properties": { "headers": { "description": "HTTP headers you wish to add to the HTTP request sent by codegen to fetch your GraphQL remote schema.", "type": "object", "additionalProperties": { "type": "string" } }, "customFetch": { "description": "Specify a Node module name, a custom file, or a function, to be used instead of a standard `fetch`.", "anyOf": [ { "$ref": "#/definitions/Types.CustomSchemaFetcher", "description": "A function to use for fetching the schema." }, { "type": "string" } ] }, "method": { "description": "HTTP Method to use, either POST (default) or GET.", "type": "string" }, "handleAsSDL": { "description": "Handling the response as SDL will allow you to load schema from remote server that doesn't return a JSON introspection.", "type": "boolean" } } }, "__type": { "description": "A function to use for fetching the schema.", "type": "object" }, "Types.CustomSchemaFetcher": { "$ref": "#/definitions/__type" }, "Types.LocalSchemaPathWithOptions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/Types.LocalSchemaPathOptions" } }, "Types.LocalSchemaPathOptions": { "additionalProperties": false, "description": "Loads a schema a local file or files, with customized options for parsing/loading.", "type": "object", "properties": { "skipGraphQLImport": { "description": "Skips checks for graphql-import syntax and loads the file as-is, without imports support.\nDefault value: \"true\"", "type": "boolean" }, "commentDescriptions": { "description": "Converts all GraphQL comments (`#` sign) to descriptions during the parse phase, to make it available\nfor plugins later.\nDefault value: \"false\"", "type": "boolean" }, "assumeValidSDL": { "description": "Set to true to assume the SDL is valid.\nDefault value: \"false\"", "type": "boolean" }, "noLocation": { "description": "By default, the parser creates AST nodes that know the location\nin the source that they correspond to. This configuration flag\ndisables that behavior for performance or testing.\nDefault value: \"false\"", "type": "boolean" }, "allowLegacySDLEmptyFields": { "description": "If enabled, the parser will parse empty fields sets in the Schema\nDefinition Language. Otherwise, the parser will follow the current\nspecification.\n\nThis option is provided to ease adoption of the final SDL specification\nand will be removed in v16.\nDefault value: \"false\"", "type": "boolean" }, "allowLegacySDLImplementsInterfaces": { "description": "If enabled, the parser will parse implemented interfaces with no `&`\ncharacter between each interface. Otherwise, the parser will follow the\ncurrent specification.\n\nThis option is provided to ease adoption of the final SDL specification\nand will be removed in v16.\nDefault value: \"false\"", "type": "boolean" }, "experimentalFragmentVariables": { "description": "EXPERIMENTAL:\n\nIf enabled, the parser will understand and parse variable definitions\ncontained in a fragment definition. They'll be represented in the\n`variableDefinitions` field of the FragmentDefinitionNode.\n\nThe syntax is identical to normal, query-defined variables. For example:\n\n fragment A($var: Boolean = false) on T {\n ...\n }\n\nNote: this feature is experimental and may change or be removed in the\nfuture.\nDefault value: \"false\"", "type": "boolean" } } }, "Types.ApolloEngineSchemaOptions": { "type": "object", "properties": { "apollo-engine": { "$ref": "#/definitions/ApolloEngineOptions" } } }, "ApolloEngineOptions": { "description": "Additional options for loading from Apollo Engine", "type": "object", "properties": { "engine": { "type": "object", "properties": { "endpoint": { "type": "string" }, "apiKey": { "type": "string" } } }, "graph": { "type": "string" }, "variant": { "type": "string" }, "headers": { "$ref": "#/definitions/Record" }, "noLocation": { "type": "boolean" }, "allowLegacySDLEmptyFields": { "type": "boolean" }, "allowLegacySDLImplementsInterfaces": { "type": "boolean" }, "experimentalFragmentVariables": { "type": "boolean" }, "commentDescriptions": { "description": "Set to `true` in order to convert all GraphQL comments (marked with # sign) to descriptions (\"\"\")\nGraphQL has built-in support for transforming descriptions to comments (with `print`), but not while\nparsing. Turning the flag on will support the other way as well (`parse`)", "type": "boolean" }, "assumeValidSDL": { "description": "Set to true to assume the SDL is valid.\n\nDefault: false", "type": "boolean" }, "assumeValid": { "description": "When building a schema from a GraphQL service's introspection result, it\nmight be safe to assume the schema is valid. Set to true to assume the\nproduced schema is valid.\n\nDefault: false", "type": "boolean" }, "cwd": { "type": "string" }, "ignore": { "anyOf": [{ "type": "array", "items": { "type": "string" } }, { "type": "string" }] }, "includeSources": { "type": "boolean" } } }, "__type_1": { "type": "object" }, "Record": { "$ref": "#/definitions/__type_1" }, "Types.GitHubSchemaOptions": { "type": "object", "additionalProperties": { "type": "object", "properties": { "token": { "type": "string" } } } }, "Types.Schema": { "description": "A URL to your GraphQL endpoint, a local path to `.graphql` file, a glob pattern to your GraphQL schema files, or a JavaScript file that exports the schema to generate code from. This can also be an array which specifies multiple schemas to generate code from. You can read more about the supported formats [here](schema-field#available-formats).", "anyOf": [ { "$ref": "#/definitions/Types.SchemaWithLoader" }, { "$ref": "#/definitions/Types.SchemaFromCodeFile" }, { "$ref": "#/definitions/Types.UrlSchemaWithOptions" }, { "$ref": "#/definitions/Types.LocalSchemaPathWithOptions" }, { "$ref": "#/definitions/Types.ApolloEngineSchemaOptions" }, { "$ref": "#/definitions/Types.GitHubSchemaOptions" }, { "type": "string" } ] }, "Types.RequireExtension": { "anyOf": [{ "type": "array", "items": { "type": "string" } }, { "type": "string" }] }, "Types.InstanceOrArray_1": { "anyOf": [ { "$ref": "#/definitions/Types.CustomDocumentLoader" }, { "type": "array", "items": { "$ref": "#/definitions/Types.OperationDocument" } }, { "type": "string" } ] }, "Types.CustomDocumentLoader": { "type": "object", "additionalProperties": { "$ref": "#/definitions/Types.CustomDocumentLoaderOptions" } }, "Types.CustomDocumentLoaderOptions": { "additionalProperties": false, "description": "Specify a path to a custom loader for your GraphQL documents.", "type": "object", "properties": { "loader": { "description": "Specify a path to a custom code file (local or module) that will handle the documents loading.", "type": "string" } } }, "Types.OperationDocument": { "anyOf": [{ "$ref": "#/definitions/Types.CustomDocumentLoader" }, { "type": "string" }] }, "Types.ConfiguredPlugin": { "type": "object", "additionalProperties": { "type": "object", "additionalProperties": { "$ref": "#/definitions/T" } }, "properties": { "flutter-freezed": { "$ref": "#/definitions/FlutterFreezedPluginConfig" }, "typescript-react-query": { "$ref": "#/definitions/ReactQueryRawPluginConfig" }, "typescript-rtk-query": { "$ref": "#/definitions/RTKConfig" }, "typescript-generic-sdk": { "$ref": "#/definitions/RawGenericSdkPluginConfig" }, "typescript-apollo-client-helpers": { "$ref": "#/definitions/ApolloClientHelpersConfig" }, "add": { "$ref": "#/definitions/AddPluginConfig" }, "time": { "$ref": "#/definitions/TimePluginConfig" }, "typescript": { "$ref": "#/definitions/TypeScriptPluginConfig" }, "typescript-operations": { "$ref": "#/definitions/TypeScriptDocumentsPluginConfig" }, "c-sharp": { "$ref": "#/definitions/CSharpResolversPluginRawConfig" }, "c-sharp-operations": { "$ref": "#/definitions/CSharpOperationsRawPluginConfig" }, "schema-ast": { "$ref": "#/definitions/SchemaASTConfig" }, "typescript-type-graphql": { "$ref": "#/definitions/TypeGraphQLPluginConfig" }, "typescript-graphql-files-modules": { "$ref": "#/definitions/TypeScriptFilesModulesPluginConfig" }, "named-operations-object": { "$ref": "#/definitions/NamedOperationsObjectPluginConfig" }, "typescript-graphql-request": { "$ref": "#/definitions/RawGraphQLRequestPluginConfig" }, "typescript-mongodb": { "$ref": "#/definitions/TypeScriptMongoPluginConfig" }, "typescript-resolvers": { "$ref": "#/definitions/TypeScriptResolversPluginConfig" }, "typescript-apollo-angular": { "$ref": "#/definitions/ApolloAngularRawPluginConfig" }, "typescript-nhost": { "$ref": "#/definitions/NhostPluginConfig" }, "typescript-urql": { "$ref": "#/definitions/UrqlRawPluginConfig" }, "typescript-react-apollo": { "$ref": "#/definitions/ReactApolloRawPluginConfig" }, "typescript-vue-apollo": { "$ref": "#/definitions/VueApolloRawPluginConfig" }, "typescript-vue-apollo-smart-ops": { "$ref": "#/definitions/VueApolloSmartOpsRawPluginConfig" }, "typescript-vue-urql": { "$ref": "#/definitions/VueUrqlRawPluginConfig" }, "typescript-stencil-apollo": { "$ref": "#/definitions/StencilApolloRawPluginConfig" }, "typescript-document-nodes": { "$ref": "#/definitions/TypeScriptDocumentNodesRawPluginConfig" }, "typescript-msw": { "$ref": "#/definitions/MSWConfig" }, "java-apollo-android": { "$ref": "#/definitions/JavaApolloAndroidPluginConfig" }, "java-resolvers": { "$ref": "#/definitions/JavaResolversPluginRawConfig" }, "java": { "$ref": "#/definitions/JavaResolversPluginRawConfig" }, "kotlin": { "$ref": "#/definitions/KotlinResolversPluginRawConfig" }, "flow": { "$ref": "#/definitions/FlowPluginConfig" }, "flow-resolvers": { "$ref": "#/definitions/FlowResolversPluginConfig" }, "flow-operations": { "$ref": "#/definitions/FlowDocumentsPluginConfig" }, "introspection": { "$ref": "#/definitions/IntrospectionPluginConfig" }, "fragment-matcher": { "$ref": "#/definitions/FragmentMatcherConfig" }, "urql-introspection": { "$ref": "#/definitions/UrqlIntrospectionConfig" }, "hasura-allow-list": { "$ref": "#/definitions/HasuraAllowListPluginConfig" } } }, "T": { "type": "object" }, "Types.ConfiguredOutput": { "additionalProperties": false, "type": "object", "properties": { "plugins": { "type": "array", "items": { "$ref": "#/definitions/GeneratedPluginsMap" }, "description": "List of plugins to apply to this current output file.\n\nYou can either specify plugins from the community using the NPM package name (after you installed it in your project), or you can use a path to a local file for custom plugins.\n\nYou can find a list of available plugins here: https://the-guild.dev/graphql/codegen/docs/plugins/index\nNeed a custom plugin? read this: https://the-guild.dev/graphql/codegen/docs/custom-codegen/index" }, "preset": { "description": "If your setup uses Preset to have a more dynamic setup and output, set the name of your preset here.\n\nPresets are a way to have more than one file output, for example: https://the-guild.dev/graphql/codegen/docs/presets/near-operation-file\n\nYou can either specify a preset from the community using the NPM package name (after you installed it in your project), or you can use a path to a local file for a custom preset.\n\nList of available presets: https://graphql-code-generator.com/docs/presets/presets-index", "anyOf": [ { "$ref": "#/definitions/Types.OutputPreset" }, { "enum": [ "client", "client-preset", "gql-tag-operations", "gql-tag-operations-preset", "graphql-modules", "graphql-modules-preset", "import-types", "import-types-preset", "near-operation-file", "near-operation-file-preset" ], "type": "string" } ] }, "presetConfig": { "description": "If your setup uses Preset to have a more dynamic setup and output, set the configuration object of your preset here.\n\nList of available presets: https://graphql-code-generator.com/docs/presets/presets-index", "type": "object", "additionalProperties": {} }, "overwrite": { "description": "A flag to overwrite files if they already exist when generating code (`true` by default).\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/codegen-config", "type": "boolean" }, "documents": { "$ref": "#/definitions/Types.InstanceOrArray_1", "description": "A pointer(s) to your GraphQL documents: query, mutation, subscription and fragment. These documents will be loaded into for all your output files.\nYou can use one of the following:\n\n- Path to a local `.graphql` file\n- Path to a code file (for example: `.js` or `.tsx`) containing GraphQL operation strings.\n- Glob expression pointing to multiple `.graphql` files\n- Glob expression pointing to multiple code files\n- Inline string containing GraphQL SDL operation definition\n\nYou can specify either a single file, or multiple.\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/documents-field" }, "schema": { "$ref": "#/definitions/Types.InstanceOrArray", "description": "A pointer(s) to your GraphQL schema. This schema will be available only for this specific `generates` record.\nYou can use one of the following:\n\n- URL pointing to a GraphQL endpoint\n- Path to a local `.json` file\n- Path to a local `.graphql` file\n- Glob expression pointing to multiple `.graphql` files\n- Path to a local code file (for example: `.js`) that exports `GraphQLSchema` object\n- Inline string containing GraphQL SDL schema definition\n\nYou can specify either a single schema, or multiple, and GraphQL Code Generator will merge the schemas into a single schema.\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/schema-field" }, "config": { "additionalProperties": true }, "hooks": { "$ref": "#/definitions/Partial", "description": "Specifies scripts to run when events are happening in the codegen core.\nHooks defined on that level will effect only the current output files.\n\nFor more details: https://graphql-code-generator.com/docs/config-reference/lifecycle-hooks" }, "documentTransforms": { "description": "DocumentTransform changes documents before executing plugins.", "type": "array", "items": { "$ref": "#/definitions/Types.OutputDocumentTransform" } }, "watchPattern": { "description": ": Additional file pattern to watch when using watch mode", "anyOf": [{ "type": "array", "items": { "type": "string" } }, { "type": "string" }] } }, "allOf": [ { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "flutter-freezed" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/FlutterFreezedPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-react-query" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/ReactQueryRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-rtk-query" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/RTKConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-generic-sdk" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/RawGenericSdkPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-apollo-client-helpers" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/ApolloClientHelpersConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "add" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/AddPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "time" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/TimePluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/TypeScriptPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-operations" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/TypeScriptDocumentsPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "c-sharp" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/CSharpResolversPluginRawConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "c-sharp-operations" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/CSharpOperationsRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "schema-ast" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/SchemaASTConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-type-graphql" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/TypeGraphQLPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-graphql-files-modules" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/TypeScriptFilesModulesPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "named-operations-object" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/NamedOperationsObjectPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-graphql-request" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/RawGraphQLRequestPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-mongodb" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/TypeScriptMongoPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-resolvers" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/TypeScriptResolversPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-apollo-angular" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/ApolloAngularRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-nhost" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/NhostPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-urql" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/UrqlRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-react-apollo" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/ReactApolloRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-vue-apollo" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/VueApolloRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-vue-apollo-smart-ops" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/VueApolloSmartOpsRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-vue-urql" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/VueUrqlRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-stencil-apollo" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/StencilApolloRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-document-nodes" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/TypeScriptDocumentNodesRawPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "typescript-msw" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/MSWConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "java-apollo-android" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/JavaApolloAndroidPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "java-resolvers" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/JavaResolversPluginRawConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "java" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/JavaResolversPluginRawConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "kotlin" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/KotlinResolversPluginRawConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "flow" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/FlowPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "flow-resolvers" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/FlowResolversPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "flow-operations" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/FlowDocumentsPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "introspection" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/IntrospectionPluginConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "fragment-matcher" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/FragmentMatcherConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "urql-introspection" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/UrqlIntrospectionConfig" } } } }, { "if": { "properties": { "plugins": { "contains": { "type": "string", "const": "hasura-allow-list" } } } }, "then": { "properties": { "config": { "$ref": "#/definitions/HasuraAllowListPluginConfig" } } } } ] }, "__type_2": { "type": "object", "properties": { "buildGeneratesSection": { "type": "object" }, "prepareDocuments": { "type": "object" } } }, "Types.OutputPreset": { "$ref": "#/definitions/__type_2" }, "__type_3": { "type": "object", "additionalProperties": { "$ref": "#/definitions/T" } }, "Types.PluginConfig": { "$ref": "#/definitions/__type_3" }, "__type_4": { "type": "object", "properties": { "afterStart": { "$ref": "#/definitions/Types.LifeCycleHookValue", "description": "Triggered with no arguments when the codegen starts (after the `codegen.yml` has beed parsed).\n\nSpecify a shell command to run." }, "beforeDone": { "$ref": "#/definitions/Types.LifeCycleHookValue", "description": "Triggered with no arguments, right before the codegen closes, or when watch mode is stopped.\n\nSpecify a shell command to run." }, "onWatchTriggered": { "$ref": "#/definitions/Types.LifeCycleHookValue", "description": "Triggered every time a file changes when using watch mode.\nTriggered with two arguments: the type of the event (for example, `changed`) and the path of the file." }, "onError": { "$ref": "#/definitions/Types.LifeCycleHookValue", "description": "Triggered in case of a general error in the codegen. The argument is a string containing the error." }, "afterOneFileWrite": { "$ref": "#/definitions/Types.LifeCycleHookValue", "description": "Triggered after a file is written to the file-system. Executed with the path for the file.\nIf the content of the file hasn't changed since last execution - this hooks won't be triggered.\n\n> This is a very useful hook, you can use it for integration with Prettier or other linters." }, "afterAllFileWrite": { "$ref": "#/definitions/Types.LifeCycleHookValue", "description": "Executed after writing all the files to the file-system.\nTriggered with multiple arguments - paths for all files." }, "beforeOneFileWrite": { "$ref": "#/definitions/Types.LifeCycleAlterHookValue", "description": "Triggered before a file is written to the file-system.\nExecuted with the path and content for the file.\n\nReturning a string will override the content of the file.\n\nIf the content of the file hasn't changed since last execution - this hooks won't be triggered." }, "beforeAllFileWrite": { "$ref": "#/definitions/Types.LifeCycleHookValue", "description": "Executed after the codegen has done creating the output and before writing the files to the file-system.\n\nTriggered with multiple arguments - paths for all relevant files.\n\n> Not all the files will be actually written to the file-system, because this is triggered before checking if the file has changed since last execution." } } }, "Types.LifeCycleHookValue": { "anyOf": [ { "$ref": "#/definitions/Types.HookFunction" }, { "type": "array", "items": { "anyOf": [{ "$ref": "#/definitions/Types.HookFunction" }, { "type": "string" }] } }, { "type": "string" } ] }, "__type_5": { "type": "object" }, "Types.HookFunction": { "$ref": "#/definitions/__type_5" }, "Types.LifeCycleAlterHookValue": { "anyOf": [ { "$ref": "#/definitions/Types.HookFunction" }, { "$ref": "#/definitions/Types.HookAlterFunction" }, { "type": "array", "items": { "anyOf": [ { "$ref": "#/definitions/Types.HookFunction" }, { "$ref": "#/definitions/Types.HookAlterFunction" }, { "type": "string" } ] } }, { "type": "string" } ] }, "__type_6": { "type": "object" }, "Types.HookAlterFunction": { "$ref": "#/definitions/__type_6" }, "Partial": { "$ref": "#/definitions/__type_4" }, "Types.OutputDocumentTransform": { "anyOf": [ { "$ref": "#/definitions/Types.DocumentTransformObject" }, { "$ref": "#/definitions/Types.DocumentTransformFileConfig" }, { "type": "string" } ] }, "__type_7": { "type": "object", "properties": { "transform": { "$ref": "#/definitions/Types.DocumentTransformFunction" } } }, "__type_8": { "type": "object" }, "Types.DocumentTransformFunction": { "$ref": "#/definitions/__type_8" }, "Types.DocumentTransformObject": { "$ref": "#/definitions/__type_7" }, "__type_9": { "type": "object", "additionalProperties": { "$ref": "#/definitions/T_1" } }, "T_1": { "type": "object" }, "Types.DocumentTransformFileConfig": { "$ref": "#/definitions/__type_9" }, "__type_10": { "type": "object" }, "Types.PackageLoaderFn": { "$ref": "#/definitions/__type_10" }, "Array": { "type": "array", "items": { "type": "object", "properties": { "name": { "description": "the name of the NPM package name you wish to look for", "type": "string" }, "identifier": { "description": "the tag identifier name you wish to look for", "type": "string" } } } }, "TypeNamePattern": { "description": "A compact string of patterns used in the config for granular configuration of Graphql Types.\n\nThe string can contain one or more patterns, each pattern ends with a semi-colon (`;`).\n\nTo apply an option to all Graphql Types or all fields, use the allTypeNames (`@*TypeNames`) tokens.\n\nWherever you use the allTypeNames token, know very well that you can make some exceptions. After all, to every rule, there is an exception.\n\nA **square bracket** (`[]`) is used to specify what should be included and a **negated square bracket** (`-[]`) is used to specify what should be excluded.\n\nManually typing out a pattern may be prone to typos resulting in invalid patterns therefore the [`TypeNamePattern`]() class exposes some builder methods to be used in the plugin config file.\n\n## Available Builder Methods and the patterns they make\n```ts\nconst Droid = TypeName.fromString('Droid');\nconst Starship = TypeName.fromString('Starship');\nconst Human = TypeName.fromString('Human');\nconst Movie = TypeName.fromString('Movie');\n\n\n// Configuring specific Graphql Types\nconst pattern = TypeNamePattern.forTypeNames([Droid, Starship]);\nconsole.log(pattern); // \"Droid;Starship;\"\n\n// Configuring all Graphql Types\nconst pattern = TypeNamePattern.forAllTypeNames();\nconsole.log(pattern); // \"@*TypeNames;\"\n\n// Configuring all Graphql Types except those specified in the exclusion list of TypeNames\nconst pattern = TypeNamePattern.forAllTypeNamesExcludeTypeNames([Droid, Starship]);\nconsole.log(pattern); // \"@*TypeNames-[Droid,Starship];\"", "type": "object", "properties": { "_value": {}, "value": { "type": "string" } } }, "UnionValueCase": { "enum": ["FreezedUnionCase.camel", "FreezedUnionCase.pascal"], "type": "string" }, "TypeName": { "description": "represents a single valid GraphQL Type Name used in the GraphQL Schema provided", "type": "object", "properties": { "_value": {}, "value": { "type": "string" } } }, "__type_11": { "type": "object", "properties": { "endpoint": { "type": "string" }, "fetchParams": { "anyOf": [{ "$ref": "#/definitions/Record_1" }, { "type": "string" }] } } }, "__type_12": { "type": "object" }, "Record_1": { "$ref": "#/definitions/__type_12" }, "HardcodedFetch": { "$ref": "#/definitions/__type_11" }, "NamingConvention": { "anyOf": [ { "$ref": "#/definitions/NamingConventionFn" }, { "$ref": "#/definitions/NamingConventionMap" }, { "type": "string" } ] }, "__type_13": { "type": "object" }, "NamingConventionFn": { "$ref": "#/definitions/__type_13" }, "NamingConventionMap": { "additionalProperties": false, "type": "object", "properties": { "enumValues": { "anyOf": [{ "$ref": "#/definitions/NamingConventionFn" }, { "type": "string" }] }, "typeNames": { "anyOf": [{ "$ref": "#/definitions/NamingConventionFn" }, { "type": "string" }] }, "transformUnderscore": { "type": "boolean" } } }, "ScalarsMap": { "description": "Scalars map or a string, a map between the GraphQL scalar name and the identifier that should be used", "anyOf": [{ "type": "object", "additionalProperties": { "type": "string" } }, { "type": "string" }] }, "DocumentMode": { "enum": ["documentNode", "documentNodeImportFragments", "external", "graphQLTag", "string"], "type": "string" }, "AvoidOptionalsConfig": { "type": "object", "properties": { "field": { "type": "boolean" }, "object": { "type": "boolean" }, "inputValue": { "type": "boolean" }, "defaultValue": { "type": "boolean" }, "resolvers": { "type": "boolean" }, "query": { "type": "boolean" }, "mutation": { "type": "boolean" }, "subscription": { "type": "boolean" } } }, "EnumValuesMap": { "description": "A raw configuration for enumValues map - can be represented with a single string value for a file path,\na map between enum name and a file path, or a map between enum name and an object with explicit enum values.", "anyOf": [ { "type": "object", "additionalProperties": { "anyOf": [ { "allOf": [ { "type": "object", "additionalProperties": { "type": ["string", "number"] } }, { "$ref": "#/definitions/AdditionalProps" } ] }, { "type": "string" } ] } }, { "type": "string" } ] }, "AdditionalProps": { "type": "object" }, "DeclarationKindConfig": { "type": "object", "properties": { "directive": { "$ref": "#/definitions/DeclarationKind" }, "scalar": { "$ref": "#/definitions/DeclarationKind" }, "input": { "$ref": "#/definitions/DeclarationKind" }, "type": { "$ref": "#/definitions/DeclarationKind" }, "interface": { "$ref": "#/definitions/DeclarationKind" }, "arguments": { "$ref": "#/definitions/DeclarationKind" } } }, "DeclarationKind": { "enum": ["abstract class", "class", "interface", "type"], "type": "string" }, "__type_14": { "description": "A map between the GraphQL directive name and the identifier that should be used", "type": "object", "additionalProperties": { "type": "string" } }, "DirectiveArgumentAndInputFieldMappings": { "$ref": "#/definitions/__type_14" }, "ScalarsMap_1": { "description": "Scalars map or a string, a map between the GraphQL scalar name and the identifier that should be used", "anyOf": [ { "type": "object", "additionalProperties": { "anyOf": [ { "type": "object", "properties": { "input": { "type": "string" }, "output": { "type": "string" } } }, { "type": "string" } ] } }, { "type": "string" } ] }, "NamingConvention_1": { "anyOf": [ { "$ref": "#/definitions/NamingConventionFn_1" }, { "$ref": "#/definitions/NamingConventionMap_1" }, { "type": "string" } ] }, "__type_15": { "type": "object" }, "NamingConventionFn_1": { "$ref": "#/definitions/__type_15" }, "NamingConventionMap_1": { "additionalProperties": false, "type": "object", "properties": { "enumValues": { "anyOf": [{ "$ref": "#/definitions/NamingConventionFn_1" }, { "type": "string" }] }, "typeNames": { "anyOf": [{ "$ref": "#/definitions/NamingConventionFn_1" }, { "type": "string" }] }, "transformUnderscore": { "type": "boolean" } } }, "CustomDirectivesConfig": { "type": "object", "properties": { "apolloUnmask": { "description": "Adds integration with Apollo Client's `@unmask` directive\nwhen using Apollo Client's data masking feature. `@unmask` ensures fields\nmarked by `@unmask` are available in the type definition.\nDefault value: \"false\"", "type": "boolean" } } }, "EnumValuesMap_1": { "description": "A raw configuration for enumValues map - can be represented with a single string value for a file path,\na map between enum name and a file path, or a map between enum name and an object with explicit enum values.", "anyOf": [ { "type": "object", "additionalProperties": { "anyOf": [ { "allOf": [ { "type": "object", "additionalProperties": { "type": ["string", "number"] } }, { "$ref": "#/definitions/AdditionalProps_1" } ] }, { "type": "string" } ] } }, { "type": "string" } ] }, "AdditionalProps_1": { "type": "object" }, "JsonAttributesSource": { "enum": ["Newtonsoft.Json", "System.Text.Json"], "type": "string" }, "ScalarsMap_2": { "description": "Scalars map or a string, a map between the GraphQL scalar name and the identifier that should be used", "anyOf": [{ "type": "object", "additionalProperties": { "type": "string" } }, { "type": "string" }] }, "NamingConvention_2": { "anyOf": [ { "$ref": "#/definitions/NamingConventionFn_2" }, { "$ref": "#/definitions/NamingConventionMap_2" }, { "type": "string" } ] }, "__type_16": { "type": "object" }, "NamingConventionFn_2": { "$ref": "#/definitions/__type_16" }, "NamingConventionMap_2": { "additionalProperties": false, "type": "object", "properties": { "enumValues": { "anyOf": [{ "$ref": "#/definitions/NamingConventionFn_2" }, { "type": "string" }] }, "typeNames": { "anyOf": [{ "$ref": "#/definitions/NamingConventionFn_2" }, { "type": "string" }] }, "transformUnderscore": { "type": "boolean" } } }, "DocumentMode_1": { "enum": ["documentNode", "documentNodeImportFragments", "external", "graphQLTag", "string"], "type": "string" }, "__type_17": { "type": "object", "properties": { "type": { "type": "string" }, "interface": { "type": "string" }, "field": { "type": "string" }, "input": { "type": "string" }, "arguments": { "type": "string" } } }, "Partial_1": { "$ref": "#/definitions/__type_17" }, "AvoidOptionalsConfig_1": { "type": "object", "properties": { "field": { "type": "boolean" }, "object": { "type": "boolean" }, "inputValue": { "type": "boolean" }, "defaultValue": { "type": "boolean" }, "resolvers": { "type": "boolean" } } }, "DeclarationKindConfig_1": { "type": "object", "properties": { "directive": { "$ref": "#/definitions/DeclarationKind_1" }, "scalar": { "$ref": "#/definitions/DeclarationKind_1" }, "input": { "$ref": "#/definitions/DeclarationKind_1" }, "type": { "$ref": "#/definitions/DeclarationKind_1" }, "interface": { "$ref": "#/definitions/DeclarationKind_1" }, "arguments": { "$ref": "#/definitions/DeclarationKind_1" } } }, "DeclarationKind_1": { "enum": ["abstract class", "class", "interface", "type"], "type": "string" }, "__type_18": { "description": "A map between the GraphQL directive name and the identifier that should be used", "type": "object", "additionalProperties": { "type": "string" } }, "DirectiveArgumentAndInputFieldMappings_1": { "$ref": "#/definitions/__type_18" }, "Array_1": { "type": "array", "items": { "type": "string" } }, "ResolversNonOptionalTypenameConfig": { "type": "object", "properties": { "unionMember": { "type": "boolean" }, "interfaceImplementingType": { "type": "boolean" }, "excludeTypes": { "type": "array", "items": { "type": "string" } } } }, "ScalarsMap_3": { "description": "Scalars map or a string, a map between the GraphQL scalar name and the identifier that should be used", "anyOf": [{ "type": "object", "additionalProperties": { "type": "string" } }, { "type": "string" }] }, "StencilComponentType": { "enum": ["class", "functional"], "type": "string" }, "DocumentMode_2": { "enum": ["documentNode", "documentNodeImportFragments", "external", "graphQLTag", "string"], "type": "string" }, "FileType": { "enum": [0, 1, 2, 3], "type": "number" }, "EnumValuesMap_2": { "description": "A raw configuration for enumValues map - can be represented with a single string value for a file path,\na map between enum name and a file path, or a map between enum name and an object with explicit enum values.", "anyOf": [ { "type": "object", "additionalProperties": { "anyOf": [ { "allOf": [ { "type": "object", "additionalProperties": { "type": ["string", "number"] } }, { "$ref": "#/definitions/AdditionalProps_2" } ] }, { "type": "string" } ] } }, { "type": "string" } ] }, "AdditionalProps_2": { "type": "object" }, "DeclarationKindConfig_2": { "type": "object", "properties": { "directive": { "$ref": "#/definitions/DeclarationKind_2" }, "scalar": { "$ref": "#/definitions/DeclarationKind_2" }, "input": { "$ref": "#/definitions/DeclarationKind_2" }, "type": { "$ref": "#/definitions/DeclarationKind_2" }, "interface": { "$ref": "#/definitions/DeclarationKind_2" }, "arguments": { "$ref": "#/definitions/DeclarationKind_2" } } }, "DeclarationKind_2": { "enum": ["abstract class", "class", "interface", "type"], "type": "string" }, "__type_19": { "description": "A map between the GraphQL directive name and the identifier that should be used", "type": "object", "additionalProperties": { "type": "string" } }, "DirectiveArgumentAndInputFieldMappings_2": { "$ref": "#/definitions/__type_19" }, "AvoidOptionalsConfig_2": { "type": "object", "properties": { "field": { "type": "boolean" }, "object": { "type": "boolean" }, "inputValue": { "type": "boolean" }, "defaultValue": { "type": "boolean" }, "resolvers": { "type": "boolean" } } }, "__type_20": { "type": "object" }, "FragmentImportFromFn": { "$ref": "#/definitions/__type_20" }, "GeneratedPluginsMap": { "anyOf": [ { "type": "object", "additionalProperties": true, "properties": { "flutter-freezed": { "additionalProperties": false, "$ref": "#/definitions/FlutterFreezedPluginConfig" }, "@graphql-codegen/flutter-freezed": { "additionalProperties": false, "$ref": "#/definitions/FlutterFreezedPluginConfig" }, "typescript-react-query": { "additionalProperties": false, "$ref": "#/definitions/ReactQueryRawPluginConfig" }, "@graphql-codegen/typescript-react-query": { "additionalProperties": false, "$ref": "#/definitions/ReactQueryRawPluginConfig" }, "typescript-rtk-query": { "additionalProperties": false, "$ref": "#/definitions/RTKConfig" }, "@graphql-codegen/typescript-rtk-query": { "additionalProperties": false, "$ref": "#/definitions/RTKConfig" }, "typescript-generic-sdk": { "additionalProperties": false, "$ref": "#/definitions/RawGenericSdkPluginConfig" }, "@graphql-codegen/typescript-generic-sdk": { "additionalProperties": false, "$ref": "#/definitions/RawGenericSdkPluginConfig" }, "typescript-apollo-client-helpers": { "additionalProperties": false, "$ref": "#/definitions/ApolloClientHelpersConfig" }, "@graphql-codegen/typescript-apollo-client-helpers": { "additionalProperties": false, "$ref": "#/definitions/ApolloClientHelpersConfig" }, "add": { "additionalProperties": false, "$ref": "#/definitions/AddPluginConfig" }, "@graphql-codegen/add": { "additionalProperties": false, "$ref": "#/definitions/AddPluginConfig" }, "time": { "additionalProperties": false, "$ref": "#/definitions/TimePluginConfig" }, "@graphql-codegen/time": { "additionalProperties": false, "$ref": "#/definitions/TimePluginConfig" }, "typescript": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptPluginConfig" }, "@graphql-codegen/typescript": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptPluginConfig" }, "typescript-operations": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptDocumentsPluginConfig" }, "@graphql-codegen/typescript-operations": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptDocumentsPluginConfig" }, "c-sharp": { "additionalProperties": false, "$ref": "#/definitions/CSharpResolversPluginRawConfig" }, "@graphql-codegen/c-sharp": { "additionalProperties": false, "$ref": "#/definitions/CSharpResolversPluginRawConfig" }, "c-sharp-operations": { "additionalProperties": false, "$ref": "#/definitions/CSharpOperationsRawPluginConfig" }, "@graphql-codegen/c-sharp-operations": { "additionalProperties": false, "$ref": "#/definitions/CSharpOperationsRawPluginConfig" }, "schema-ast": { "additionalProperties": false, "$ref": "#/definitions/SchemaASTConfig" }, "@graphql-codegen/schema-ast": { "additionalProperties": false, "$ref": "#/definitions/SchemaASTConfig" }, "typescript-type-graphql": { "additionalProperties": false, "$ref": "#/definitions/TypeGraphQLPluginConfig" }, "@graphql-codegen/typescript-type-graphql": { "additionalProperties": false, "$ref": "#/definitions/TypeGraphQLPluginConfig" }, "typescript-graphql-files-modules": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptFilesModulesPluginConfig" }, "@graphql-codegen/typescript-graphql-files-modules": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptFilesModulesPluginConfig" }, "named-operations-object": { "additionalProperties": false, "$ref": "#/definitions/NamedOperationsObjectPluginConfig" }, "@graphql-codegen/named-operations-object": { "additionalProperties": false, "$ref": "#/definitions/NamedOperationsObjectPluginConfig" }, "typescript-graphql-request": { "additionalProperties": false, "$ref": "#/definitions/RawGraphQLRequestPluginConfig" }, "@graphql-codegen/typescript-graphql-request": { "additionalProperties": false, "$ref": "#/definitions/RawGraphQLRequestPluginConfig" }, "typescript-mongodb": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptMongoPluginConfig" }, "@graphql-codegen/typescript-mongodb": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptMongoPluginConfig" }, "typescript-resolvers": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptResolversPluginConfig" }, "@graphql-codegen/typescript-resolvers": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptResolversPluginConfig" }, "typescript-apollo-angular": { "additionalProperties": false, "$ref": "#/definitions/ApolloAngularRawPluginConfig" }, "@graphql-codegen/typescript-apollo-angular": { "additionalProperties": false, "$ref": "#/definitions/ApolloAngularRawPluginConfig" }, "typescript-nhost": { "additionalProperties": false, "$ref": "#/definitions/NhostPluginConfig" }, "@graphql-codegen/typescript-nhost": { "additionalProperties": false, "$ref": "#/definitions/NhostPluginConfig" }, "typescript-urql": { "additionalProperties": false, "$ref": "#/definitions/UrqlRawPluginConfig" }, "@graphql-codegen/typescript-urql": { "additionalProperties": false, "$ref": "#/definitions/UrqlRawPluginConfig" }, "typescript-react-apollo": { "additionalProperties": false, "$ref": "#/definitions/ReactApolloRawPluginConfig" }, "@graphql-codegen/typescript-react-apollo": { "additionalProperties": false, "$ref": "#/definitions/ReactApolloRawPluginConfig" }, "typescript-vue-apollo": { "additionalProperties": false, "$ref": "#/definitions/VueApolloRawPluginConfig" }, "@graphql-codegen/typescript-vue-apollo": { "additionalProperties": false, "$ref": "#/definitions/VueApolloRawPluginConfig" }, "typescript-vue-apollo-smart-ops": { "additionalProperties": false, "$ref": "#/definitions/VueApolloSmartOpsRawPluginConfig" }, "@graphql-codegen/typescript-vue-apollo-smart-ops": { "additionalProperties": false, "$ref": "#/definitions/VueApolloSmartOpsRawPluginConfig" }, "typescript-vue-urql": { "additionalProperties": false, "$ref": "#/definitions/VueUrqlRawPluginConfig" }, "@graphql-codegen/typescript-vue-urql": { "additionalProperties": false, "$ref": "#/definitions/VueUrqlRawPluginConfig" }, "typescript-stencil-apollo": { "additionalProperties": false, "$ref": "#/definitions/StencilApolloRawPluginConfig" }, "@graphql-codegen/typescript-stencil-apollo": { "additionalProperties": false, "$ref": "#/definitions/StencilApolloRawPluginConfig" }, "typescript-document-nodes": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptDocumentNodesRawPluginConfig" }, "@graphql-codegen/typescript-document-nodes": { "additionalProperties": false, "$ref": "#/definitions/TypeScriptDocumentNodesRawPluginConfig" }, "typescript-msw": { "additionalProperties": false, "$ref": "#/definitions/MSWConfig" }, "@graphql-codegen/typescript-msw": { "additionalProperties": false, "$ref": "#/definitions/MSWConfig" }, "java-apollo-android": { "additionalProperties": false, "$ref": "#/definitions/JavaApolloAndroidPluginConfig" }, "@graphql-codegen/java-apollo-android": { "additionalProperties": false, "$ref": "#/definitions/JavaApolloAndroidPluginConfig" }, "java-resolvers": { "additionalProperties": false, "$ref": "#/definitions/JavaResolversPluginRawConfig" }, "@graphql-codegen/java-resolvers": { "additionalProperties": false, "$ref": "#/definitions/JavaResolversPluginRawConfig" }, "java": { "additionalProperties": false, "$ref": "#/definitions/JavaResolversPluginRawConfig" }, "@graphql-codegen/java": { "additionalProperties": false, "$ref": "#/definitions/JavaResolversPluginRawConfig" }, "kotlin": { "additionalProperties": false, "$ref": "#/definitions/KotlinResolversPluginRawConfig" }, "@graphql-codegen/kotlin": { "additionalProperties": false, "$ref": "#/definitions/KotlinResolversPluginRawConfig" }, "flow": { "additionalProperties": false, "$ref": "#/definitions/FlowPluginConfig" }, "@graphql-codegen/flow": { "additionalProperties": false, "$ref": "#/definitions/FlowPluginConfig" }, "flow-resolvers": { "additionalProperties": false, "$ref": "#/definitions/FlowResolversPluginConfig" }, "@graphql-codegen/flow-resolvers": { "additionalProperties": false, "$ref": "#/definitions/FlowResolversPluginConfig" }, "flow-operations": { "additionalProperties": false, "$ref": "#/definitions/FlowDocumentsPluginConfig" }, "@graphql-codegen/flow-operations": { "additionalProperties": false, "$ref": "#/definitions/FlowDocumentsPluginConfig" }, "introspection": { "additionalProperties": false, "$ref": "#/definitions/IntrospectionPluginConfig" }, "@graphql-codegen/introspection": { "additionalProperties": false, "$ref": "#/definitions/IntrospectionPluginConfig" }, "fragment-matcher": { "additionalProperties": false, "$ref": "#/definitions/FragmentMatcherConfig" }, "@graphql-codegen/fragment-matcher": { "additionalProperties": false, "$ref": "#/definitions/FragmentMatcherConfig" }, "urql-introspection": { "additionalProperties": false, "$ref": "#/definitions/UrqlIntrospectionConfig" }, "@graphql-codegen/urql-introspection": { "additionalProperties": false, "$ref": "#/definitions/UrqlIntrospectionConfig" }, "hasura-allow-list": { "additionalProperties": false, "$ref": "#/definitions/HasuraAllowListPluginConfig" }, "@graphql-codegen/hasura-allow-list": { "additionalProperties": false, "$ref": "#/definitions/HasuraAllowListPluginConfig" } } }, { "type": "string", "oneOf": [ { "const": "flutter-freezed", "description": "configure the `flutter-freezed` plugin\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/flutter-freezed\n\n=> Make sure to include \"@graphql-codegen/flutter-freezed\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/flutter-freezed", "description": "configure the `flutter-freezed` plugin\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/flutter-freezed\n\n=> Make sure to include \"@graphql-codegen/flutter-freezed\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-react-query", "description": "This plugin generates `React-Query` Hooks with TypeScript typings.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\n> **If you are using the `react-query` package instead of the `@tanstack/react-query` package in your project, please set the `legacyMode` option to `true`.**\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-react-query\n\n=> Make sure to include \"@graphql-codegen/typescript-react-query\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-react-query", "description": "This plugin generates `React-Query` Hooks with TypeScript typings.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\n> **If you are using the `react-query` package instead of the `@tanstack/react-query` package in your project, please set the `legacyMode` option to `true`.**\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-react-query\n\n=> Make sure to include \"@graphql-codegen/typescript-react-query\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-rtk-query", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-rtk-query\n\n=> Make sure to include \"@graphql-codegen/typescript-rtk-query\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-rtk-query", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-rtk-query\n\n=> Make sure to include \"@graphql-codegen/typescript-rtk-query\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-generic-sdk", "description": "This plugin generate a generic SDK (without any Requester implemented), allow you to easily customize the way you fetch your data, without loosing the strongly-typed integration.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-generic-sdk\n\n=> Make sure to include \"@graphql-codegen/typescript-generic-sdk\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-generic-sdk", "description": "This plugin generate a generic SDK (without any Requester implemented), allow you to easily customize the way you fetch your data, without loosing the strongly-typed integration.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-generic-sdk\n\n=> Make sure to include \"@graphql-codegen/typescript-generic-sdk\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-apollo-client-helpers", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-apollo-client-helpers\n\n=> Make sure to include \"@graphql-codegen/typescript-apollo-client-helpers\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-apollo-client-helpers", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-apollo-client-helpers\n\n=> Make sure to include \"@graphql-codegen/typescript-apollo-client-helpers\" in your package.json file and install your dependencies.\n\n" }, { "const": "add", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/add\n\n=> Make sure to include \"@graphql-codegen/add\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/add", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/add\n\n=> Make sure to include \"@graphql-codegen/add\" in your package.json file and install your dependencies.\n\n" }, { "const": "time", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/time\n\n=> Make sure to include \"@graphql-codegen/time\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/time", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/time\n\n=> Make sure to include \"@graphql-codegen/time\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript", "description": "This plugin generates the base TypeScript types, based on your GraphQL schema.\n\nThe types generated by this plugin are simple, and refers to the exact structure of your schema, and it's used as the base types for other plugins (such as `typescript-operations` / `typescript-resolvers`)\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript\n\n=> Make sure to include \"@graphql-codegen/typescript\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript", "description": "This plugin generates the base TypeScript types, based on your GraphQL schema.\n\nThe types generated by this plugin are simple, and refers to the exact structure of your schema, and it's used as the base types for other plugins (such as `typescript-operations` / `typescript-resolvers`)\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript\n\n=> Make sure to include \"@graphql-codegen/typescript\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-operations", "description": "This plugin generates TypeScript types based on your GraphQLSchema _and_ your GraphQL operations and fragments.\nIt generates types for your GraphQL documents: Query, Mutation, Subscription and Fragment.\n\nNote: In most configurations, this plugin requires you to use `typescript as well, because it depends on its base types.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-operations\n\n=> Make sure to include \"@graphql-codegen/typescript-operations\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-operations", "description": "This plugin generates TypeScript types based on your GraphQLSchema _and_ your GraphQL operations and fragments.\nIt generates types for your GraphQL documents: Query, Mutation, Subscription and Fragment.\n\nNote: In most configurations, this plugin requires you to use `typescript as well, because it depends on its base types.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-operations\n\n=> Make sure to include \"@graphql-codegen/typescript-operations\" in your package.json file and install your dependencies.\n\n" }, { "const": "c-sharp", "description": "This plugin generates C# `class` identifier for your schema types.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/c-sharp\n\n=> Make sure to include \"@graphql-codegen/c-sharp\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/c-sharp", "description": "This plugin generates C# `class` identifier for your schema types.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/c-sharp\n\n=> Make sure to include \"@graphql-codegen/c-sharp\" in your package.json file and install your dependencies.\n\n" }, { "const": "c-sharp-operations", "description": "This plugin generates C# `class` based on your GraphQL operations.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/c-sharp-operations\n\n=> Make sure to include \"@graphql-codegen/c-sharp-operations\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/c-sharp-operations", "description": "This plugin generates C# `class` based on your GraphQL operations.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/c-sharp-operations\n\n=> Make sure to include \"@graphql-codegen/c-sharp-operations\" in your package.json file and install your dependencies.\n\n" }, { "const": "schema-ast", "description": "This plugin prints the merged schema as string. If multiple schemas are provided, they will be merged and printed as one schema.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/schema-ast\n\n=> Make sure to include \"@graphql-codegen/schema-ast\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/schema-ast", "description": "This plugin prints the merged schema as string. If multiple schemas are provided, they will be merged and printed as one schema.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/schema-ast\n\n=> Make sure to include \"@graphql-codegen/schema-ast\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-type-graphql", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-type-graphql\n\n=> Make sure to include \"@graphql-codegen/typescript-type-graphql\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-type-graphql", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-type-graphql\n\n=> Make sure to include \"@graphql-codegen/typescript-type-graphql\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-graphql-files-modules", "description": "This plugin generates TypeScript typings for `.graphql` files containing GraphQL documents, which later on can be consumed using [`graphql-tag/loader`](https://github.com/apollographql/graphql-tag#webpack-preprocessing-with-graphql-tagloader) or use `string` types if you will use the operations as raw strings, and get type-check and type-safety for your imports. This means that any time you import objects from `.graphql` files, your IDE will provide auto-complete.\n\nThis plugin also handles `.graphql` files containing multiple GraphQL documents, and name the imports according to the operation name.\n\n> ⚠ Fragments are not generated with named imports, only as default imports, due to `graphql-tag/loader` behavior.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-graphql-files-modules\n\n=> Make sure to include \"@graphql-codegen/typescript-graphql-files-modules\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-graphql-files-modules", "description": "This plugin generates TypeScript typings for `.graphql` files containing GraphQL documents, which later on can be consumed using [`graphql-tag/loader`](https://github.com/apollographql/graphql-tag#webpack-preprocessing-with-graphql-tagloader) or use `string` types if you will use the operations as raw strings, and get type-check and type-safety for your imports. This means that any time you import objects from `.graphql` files, your IDE will provide auto-complete.\n\nThis plugin also handles `.graphql` files containing multiple GraphQL documents, and name the imports according to the operation name.\n\n> ⚠ Fragments are not generated with named imports, only as default imports, due to `graphql-tag/loader` behavior.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-graphql-files-modules\n\n=> Make sure to include \"@graphql-codegen/typescript-graphql-files-modules\" in your package.json file and install your dependencies.\n\n" }, { "const": "named-operations-object", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/named-operations-object\n\n=> Make sure to include \"@graphql-codegen/named-operations-object\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/named-operations-object", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/named-operations-object\n\n=> Make sure to include \"@graphql-codegen/named-operations-object\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-graphql-request", "description": "This plugin generates [`graphql-request`](https://npmjs.com/package/graphql-request) ready-to-use SDK, which is fully-typed.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-graphql-request\n\n=> Make sure to include \"@graphql-codegen/typescript-graphql-request\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-graphql-request", "description": "This plugin generates [`graphql-request`](https://npmjs.com/package/graphql-request) ready-to-use SDK, which is fully-typed.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-graphql-request\n\n=> Make sure to include \"@graphql-codegen/typescript-graphql-request\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-mongodb", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-mongodb\n\n=> Make sure to include \"@graphql-codegen/typescript-mongodb\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-mongodb", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-mongodb\n\n=> Make sure to include \"@graphql-codegen/typescript-mongodb\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-resolvers", "description": "This plugin generates TypeScript signature for `resolve` functions of your GraphQL API.\nYou can use this plugin to generate simple resolvers signature based on your GraphQL types, or you can change its behavior be providing custom model types (mappers).\n\nYou can find a blog post explaining the usage of this plugin here: https://the-guild.dev/blog/better-type-safety-for-resolvers-with-graphql-codegen\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-resolvers\n\n=> Make sure to include \"@graphql-codegen/typescript-resolvers\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-resolvers", "description": "This plugin generates TypeScript signature for `resolve` functions of your GraphQL API.\nYou can use this plugin to generate simple resolvers signature based on your GraphQL types, or you can change its behavior be providing custom model types (mappers).\n\nYou can find a blog post explaining the usage of this plugin here: https://the-guild.dev/blog/better-type-safety-for-resolvers-with-graphql-codegen\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-resolvers\n\n=> Make sure to include \"@graphql-codegen/typescript-resolvers\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-apollo-angular", "description": "This plugin generates Apollo services (`Query`, `Mutation` and `Subscription`) with TypeScript typings.\n\nIt will generate a strongly typed Angular service for every defined query, mutation or subscription. The generated Angular services are ready to inject and use within your Angular component.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\nTo shed some more light regards this template, it's recommended to go through this article: https://apollo-angular.com/docs/get-started, and to read the Code Generation with Apollo Angular: https://the-guild.dev/blog/apollo-angular-12\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-apollo-angular\n\n=> Make sure to include \"@graphql-codegen/typescript-apollo-angular\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-apollo-angular", "description": "This plugin generates Apollo services (`Query`, `Mutation` and `Subscription`) with TypeScript typings.\n\nIt will generate a strongly typed Angular service for every defined query, mutation or subscription. The generated Angular services are ready to inject and use within your Angular component.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\nTo shed some more light regards this template, it's recommended to go through this article: https://apollo-angular.com/docs/get-started, and to read the Code Generation with Apollo Angular: https://the-guild.dev/blog/apollo-angular-12\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-apollo-angular\n\n=> Make sure to include \"@graphql-codegen/typescript-apollo-angular\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-nhost", "description": "This plugin generates the Typescript schema that enables queries and mutations to be typed in the Nhost SDK.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-nhost\n\n=> Make sure to include \"@graphql-codegen/typescript-nhost\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-nhost", "description": "This plugin generates the Typescript schema that enables queries and mutations to be typed in the Nhost SDK.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-nhost\n\n=> Make sure to include \"@graphql-codegen/typescript-nhost\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-urql", "description": "This plugin generates `urql` (https://github.com/FormidableLabs/urql) components and HOC with TypeScript typings.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-urql\n\n=> Make sure to include \"@graphql-codegen/typescript-urql\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-urql", "description": "This plugin generates `urql` (https://github.com/FormidableLabs/urql) components and HOC with TypeScript typings.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-urql\n\n=> Make sure to include \"@graphql-codegen/typescript-urql\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-react-apollo", "description": "This plugin generates React Apollo components and HOC with TypeScript typings.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-react-apollo\n\n=> Make sure to include \"@graphql-codegen/typescript-react-apollo\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-react-apollo", "description": "This plugin generates React Apollo components and HOC with TypeScript typings.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-react-apollo\n\n=> Make sure to include \"@graphql-codegen/typescript-react-apollo\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-vue-apollo", "description": "This plugin generates\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-vue-apollo\n\n=> Make sure to include \"@graphql-codegen/typescript-vue-apollo\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-vue-apollo", "description": "This plugin generates\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-vue-apollo\n\n=> Make sure to include \"@graphql-codegen/typescript-vue-apollo\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-vue-apollo-smart-ops", "description": "This plugin generates Vue Apollo Smart Query, Smart Subscription and mutation operation functions with\nTypeScript typings.\n\nThis plugin relies on some helper functions and types from the `vue-apollo-smart-ops` package. That package also adds\nsome optional functionality for improved error handling in Vue Apollo operations which can be configured in the\ngenerated code from this plugin.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` -\nand thus shares a similar configuration.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-vue-apollo-smart-ops\n\n=> Make sure to include \"@graphql-codegen/typescript-vue-apollo-smart-ops\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-vue-apollo-smart-ops", "description": "This plugin generates Vue Apollo Smart Query, Smart Subscription and mutation operation functions with\nTypeScript typings.\n\nThis plugin relies on some helper functions and types from the `vue-apollo-smart-ops` package. That package also adds\nsome optional functionality for improved error handling in Vue Apollo operations which can be configured in the\ngenerated code from this plugin.\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` -\nand thus shares a similar configuration.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-vue-apollo-smart-ops\n\n=> Make sure to include \"@graphql-codegen/typescript-vue-apollo-smart-ops\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-vue-urql", "description": "This plugin generates `urql` (https://github.com/FormidableLabs/urql) composition functions with TypeScript typings.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-vue-urql\n\n=> Make sure to include \"@graphql-codegen/typescript-vue-urql\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-vue-urql", "description": "This plugin generates `urql` (https://github.com/FormidableLabs/urql) composition functions with TypeScript typings.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-vue-urql\n\n=> Make sure to include \"@graphql-codegen/typescript-vue-urql\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-stencil-apollo", "description": "This plugin generates Stencil Apollo functional components typings\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-stencil-apollo\n\n=> Make sure to include \"@graphql-codegen/typescript-stencil-apollo\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-stencil-apollo", "description": "This plugin generates Stencil Apollo functional components typings\n\nIt extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-stencil-apollo\n\n=> Make sure to include \"@graphql-codegen/typescript-stencil-apollo\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-document-nodes", "description": "This plugin generates TypeScript source `.ts` file from GraphQL files `.graphql`.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-document-nodes\n\n=> Make sure to include \"@graphql-codegen/typescript-document-nodes\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-document-nodes", "description": "This plugin generates TypeScript source `.ts` file from GraphQL files `.graphql`.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-document-nodes\n\n=> Make sure to include \"@graphql-codegen/typescript-document-nodes\" in your package.json file and install your dependencies.\n\n" }, { "const": "typescript-msw", "description": "This plugin generates `msw` (https://github.com/mswjs/msw) mock handlers with TypeScript typings.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-msw\n\n=> Make sure to include \"@graphql-codegen/typescript-msw\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/typescript-msw", "description": "This plugin generates `msw` (https://github.com/mswjs/msw) mock handlers with TypeScript typings.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/typescript-msw\n\n=> Make sure to include \"@graphql-codegen/typescript-msw\" in your package.json file and install your dependencies.\n\n" }, { "const": "java-apollo-android", "description": "This plugin and presets creates generated mappers and parsers for a complete type-safe GraphQL requests, for developers that uses Apollo Android runtime.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/java-apollo-android\n\n=> Make sure to include \"@graphql-codegen/java-apollo-android\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/java-apollo-android", "description": "This plugin and presets creates generated mappers and parsers for a complete type-safe GraphQL requests, for developers that uses Apollo Android runtime.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/java-apollo-android\n\n=> Make sure to include \"@graphql-codegen/java-apollo-android\" in your package.json file and install your dependencies.\n\n" }, { "const": "java-resolvers", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/java-resolvers\n\n=> Make sure to include \"@graphql-codegen/java-resolvers\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/java-resolvers", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/java-resolvers\n\n=> Make sure to include \"@graphql-codegen/java-resolvers\" in your package.json file and install your dependencies.\n\n" }, { "const": "java", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/java\n\n=> Make sure to include \"@graphql-codegen/java\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/java", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/java\n\n=> Make sure to include \"@graphql-codegen/java\" in your package.json file and install your dependencies.\n\n" }, { "const": "kotlin", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/kotlin\n\n=> Make sure to include \"@graphql-codegen/kotlin\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/kotlin", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/kotlin\n\n=> Make sure to include \"@graphql-codegen/kotlin\" in your package.json file and install your dependencies.\n\n" }, { "const": "flow", "description": "This plugin generates Flow types based on your `GraphQLSchema`.\n\nIt generates types for your entire schema: types, input types, enum, interface, scalar and union.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/flow\n\n=> Make sure to include \"@graphql-codegen/flow\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/flow", "description": "This plugin generates Flow types based on your `GraphQLSchema`.\n\nIt generates types for your entire schema: types, input types, enum, interface, scalar and union.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/flow\n\n=> Make sure to include \"@graphql-codegen/flow\" in your package.json file and install your dependencies.\n\n" }, { "const": "flow-resolvers", "description": "This plugin generates resolvers signature based on your `GraphQLSchema`.\n\nIt generates types for your entire schema: types, input types, enum, interface, scalar and union.\n\nThis plugin requires you to use `@graphql-codegen/flow` as well, because it depends on it's types.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/flow-resolvers\n\n=> Make sure to include \"@graphql-codegen/flow-resolvers\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/flow-resolvers", "description": "This plugin generates resolvers signature based on your `GraphQLSchema`.\n\nIt generates types for your entire schema: types, input types, enum, interface, scalar and union.\n\nThis plugin requires you to use `@graphql-codegen/flow` as well, because it depends on it's types.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/flow-resolvers\n\n=> Make sure to include \"@graphql-codegen/flow-resolvers\" in your package.json file and install your dependencies.\n\n" }, { "const": "flow-operations", "description": "This plugin generates Flow types based on your `GraphQLSchema` and your GraphQL operations and fragments.\n\nIt generates types for your GraphQL documents: Query, Mutation, Subscription and Fragment.\n\nThis plugin requires you to use `@graphql-codegen/flow` as well, because it depends on its types.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/flow-operations\n\n=> Make sure to include \"@graphql-codegen/flow-operations\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/flow-operations", "description": "This plugin generates Flow types based on your `GraphQLSchema` and your GraphQL operations and fragments.\n\nIt generates types for your GraphQL documents: Query, Mutation, Subscription and Fragment.\n\nThis plugin requires you to use `@graphql-codegen/flow` as well, because it depends on its types.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/flow-operations\n\n=> Make sure to include \"@graphql-codegen/flow-operations\" in your package.json file and install your dependencies.\n\n" }, { "const": "introspection", "description": "This plugin generates a GraphQL introspection file based on your GraphQL schema.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/introspection\n\n=> Make sure to include \"@graphql-codegen/introspection\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/introspection", "description": "This plugin generates a GraphQL introspection file based on your GraphQL schema.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/introspection\n\n=> Make sure to include \"@graphql-codegen/introspection\" in your package.json file and install your dependencies.\n\n" }, { "const": "fragment-matcher", "description": "This plugin generates an introspection file but only with Interfaces and Unions, based on your GraphQLSchema.\n\nIf you are using `apollo-client` and your schema contains `interface` or `union` declaration, it's recommended to use Apollo's Fragment Matcher and the result generated by the plugin.\n\nYou can read more about it in [`apollo-client` documentation](https://apollographql.com/docs/react/data/fragments/#fragments-on-unions-and-interfaces).\n\nFragment Matcher plugin accepts a TypeScript / JavaScript or a JSON file as an output _(`.ts, .tsx, .js, .jsx, .json`)_.\n\nBoth in TypeScript and JavaScript a default export is being used.\n\n> The output is based on the output you choose for the output file name.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/fragment-matcher\n\n=> Make sure to include \"@graphql-codegen/fragment-matcher\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/fragment-matcher", "description": "This plugin generates an introspection file but only with Interfaces and Unions, based on your GraphQLSchema.\n\nIf you are using `apollo-client` and your schema contains `interface` or `union` declaration, it's recommended to use Apollo's Fragment Matcher and the result generated by the plugin.\n\nYou can read more about it in [`apollo-client` documentation](https://apollographql.com/docs/react/data/fragments/#fragments-on-unions-and-interfaces).\n\nFragment Matcher plugin accepts a TypeScript / JavaScript or a JSON file as an output _(`.ts, .tsx, .js, .jsx, .json`)_.\n\nBoth in TypeScript and JavaScript a default export is being used.\n\n> The output is based on the output you choose for the output file name.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/fragment-matcher\n\n=> Make sure to include \"@graphql-codegen/fragment-matcher\" in your package.json file and install your dependencies.\n\n" }, { "const": "urql-introspection", "description": "This plugin generates an introspection file for Schema Awareness feature of Urql Cache Exchange\n\nYou can read more about it in `urql` documentation: https://formidable.com/open-source/urql/docs/graphcache/schema-awareness.\n\nUrql Introspection plugin accepts a TypeScript / JavaScript or a JSON file as an output _(`.ts, .tsx, .js, .jsx, .json`)_.\n\nBoth in TypeScript and JavaScript a default export is being used.\n\n> The output is based on the output you choose for the output file name.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/urql-introspection\n\n=> Make sure to include \"@graphql-codegen/urql-introspection\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/urql-introspection", "description": "This plugin generates an introspection file for Schema Awareness feature of Urql Cache Exchange\n\nYou can read more about it in `urql` documentation: https://formidable.com/open-source/urql/docs/graphcache/schema-awareness.\n\nUrql Introspection plugin accepts a TypeScript / JavaScript or a JSON file as an output _(`.ts, .tsx, .js, .jsx, .json`)_.\n\nBoth in TypeScript and JavaScript a default export is being used.\n\n> The output is based on the output you choose for the output file name.\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/urql-introspection\n\n=> Make sure to include \"@graphql-codegen/urql-introspection\" in your package.json file and install your dependencies.\n\n" }, { "const": "hasura-allow-list", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/hasura-allow-list\n\n=> Make sure to include \"@graphql-codegen/hasura-allow-list\" in your package.json file and install your dependencies.\n\n" }, { "const": "@graphql-codegen/hasura-allow-list", "description": "\n\nFor more details and documentation: https://the-guild.dev/graphql/codegen/docs/plugins/hasura-allow-list\n\n=> Make sure to include \"@graphql-codegen/hasura-allow-list\" in your package.json file and install your dependencies.\n\n" } ] }, { "type": "string", "description": "Point to a custom plugin loaded from your file-system.", "pattern": "(\\\\?([^\\/]*[\\/])*)([^\\/]+)$" }, { "type": "string", "description": "You can point to any third-party module from node_modules that matches the requirements of a GraphQL Codegen plugin." } ] } }, "$ref": "#/definitions/Types.Config" } ================================================ FILE: website/route-lockfile.txt ================================================ /docs -> /docs/getting-started /docs/advanced -> /docs/advanced/generated-files-colocation /docs/advanced/generated-files-colocation /docs/advanced/how-does-it-work /docs/advanced/profiler /docs/advanced/programmatic-usage /docs/config-reference -> /docs/config-reference/codegen-config /docs/config-reference/ -> /docs/config-reference/codegen-config /docs/config-reference/codegen-config /docs/config-reference/config-field /docs/config-reference/documents-field /docs/config-reference/lifecycle-hooks /docs/config-reference/multiproject-config /docs/config-reference/naming-convention /docs/config-reference/require-field /docs/config-reference/schema-field /docs/custom-codegen /docs/custom-codegen/contributing /docs/custom-codegen/extend-schema /docs/custom-codegen/plugin-structure /docs/custom-codegen/using-visitor /docs/custom-codegen/validate-configuration /docs/custom-codegen/write-your-plugin -> /docs/custom-codegen /docs/generated-config/base-documents-visitor -> /plugins /docs/generated-config/base-visitor -> /plugins /docs/getting-started /docs/getting-started/codegen-config -> /docs/config-reference/codegen-config /docs/getting-started/config-field -> /docs/config-reference/config-field /docs/getting-started/config-reference/codegen-config -> /docs/config-reference/codegen-config /docs/getting-started/development-workflow /docs/getting-started/documents-field -> /docs/config-reference/documents-field /docs/getting-started/esm-typescript-usage /docs/getting-started/how-does-it-work -> /docs/advanced/how-does-it-work /docs/getting-started/installation /docs/getting-started/lifecycle-hooks -> /docs/config-reference/lifecycle-hooks /docs/getting-started/naming-convention -> /docs/config-reference/naming-convention /docs/getting-started/programmatic-usage -> /docs/advanced/programmatic-usage /docs/getting-started/require-field -> /docs/config-reference/require-field /docs/getting-started/schema-field -> /docs/config-reference/schema-field /docs/getting-startedinstallation -> /docs/getting-started /docs/guides/angular /docs/guides/flutter-freezed /docs/guides/further-reading /docs/guides/graphql-modules /docs/guides/graphql-server-apollo-yoga /docs/guides/react -> /docs/guides/react-vue /docs/guides/react-vue /docs/guides/svelte /docs/guides/vue -> /docs/guides/react-vue /docs/integrations -> /plugins /docs/integrations/apollo-local-state /docs/integrations/create-react-app /docs/integrations/federation /docs/integrations/gatsby /docs/integrations/prettier /docs/integrations/vscode /docs/migration/from-0-13 /docs/migration/from-0-18 /docs/migration/from-4-0 /docs/plugins -> /plugins /docs/plugins/c-sharp -> /plugins/c-sharp/c-sharp-operations /docs/plugins/client-note -> /plugins /docs/plugins/typescript-common -> /plugins/typescript/typescript /docs/plugins/typescript-graphql-requesttypescript-graphql-request -> /plugins/typescript/typescript-graphql-request /docs/plugins/typescript-server -> /plugins/typescript/typescript-resolvers /docs/presets/presets-index -> /plugins /docs/tags -> /docs/getting-started /plugins /plugins/add -> /plugins/other/add /plugins/c-sharp-operations -> /plugins/c-sharp/c-sharp-operations /plugins/c-sharp/c-sharp-operations /plugins/core -> /plugins /plugins/dart -> /plugins /plugins/dart/flutter -> /plugins/dart/flutter-freezed /plugins/dart/flutter-freezed /plugins/flow -> /plugins/flow/flow-operations /plugins/flow-operations -> /plugins/flow/flow-operations /plugins/flow-resolvers -> /plugins/flow/flow-resolvers /plugins/flow/flow-operations /plugins/flow/flow-resolvers /plugins/flutter-freezed -> /plugins/dart/flutter-freezed /plugins/fragment-matcher -> /plugins/other/fragment-matcher /plugins/gql-tag-operations-preset -> /plugins/presets/gql-tag-operations-preset /plugins/graphql-modules-preset -> /plugins/presets/graphql-modules-preset /plugins/hasura-allow-list -> /plugins/other/hasura-allow-list /plugins/import-types-preset -> /plugins/presets/import-types-preset /plugins/introspection -> /plugins/other/introspection /plugins/java -> /plugins/java/java /plugins/java-apollo-android -> /plugins/java/java-apollo-android /plugins/java-installation -> /plugins/java/java /plugins/java-resolvers -> /plugins/java/java-resolvers /plugins/java/java /plugins/java/java-apollo-android /plugins/java/java-resolvers /plugins/java/kotlin /plugins/jsdoc -> /plugins/other/jsdoc /plugins/kotlin -> /plugins/java/kotlin /plugins/named-operations-object -> /plugins/typescript/named-operations-object /plugins/near-operation-file-preset -> /plugins/presets/near-operation-file-preset /plugins/other -> /plugins /plugins/other/add /plugins/other/fragment-matcher /plugins/other/hasura-allow-list /plugins/other/introspection /plugins/other/jsdoc /plugins/other/reason-client /plugins/other/schema-ast /plugins/other/time /plugins/other/typescript-operations -> /plugins/typescript/typescript-operations /plugins/other/urql-introspection /plugins/presets -> /plugins /plugins/presets/gql-tag-operations-preset /plugins/presets/graphql-modules-preset /plugins/presets/import-types-preset /plugins/presets/near-operation-file-preset /plugins/reason-client -> /plugins/other/reason-client /plugins/relay-operation-optimizer -> /plugins/typescript/relay-operation-optimizer /plugins/schema-ast -> /plugins/other/schema-ast /plugins/time -> /plugins/other/time /plugins/typed-document-node -> /plugins/typescript/typed-document-node /plugins/typescript -> /plugins/typescript/typescript /plugins/typescript -> /plugins/typescript/typescript /plugins/typescript-apollo-angular -> /plugins/typescript/typescript-apollo-angular /plugins/typescript-apollo-client-helpers -> /plugins/typescript/typescript-apollo-client-helpers /plugins/typescript-apollo-next -> /plugins/typescript/typescript-apollo-next /plugins/typescript-common -> /plugins/typescript/typescript /plugins/typescript-document-nodes -> /plugins/typescript/typescript-document-nodes /plugins/typescript-generic-sdk -> /plugins/typescript/typescript-generic-sdk /plugins/typescript-graphql-files-modules -> /plugins/typescript/typescript-graphql-files-modules /plugins/typescript-graphql-request -> /plugins/typescript/typescript-graphql-request /plugins/typescript-mongodb -> /plugins/typescript/typescript-mongodb /plugins/typescript-msw -> /plugins/typescript/typescript-msw /plugins/typescript-oclif -> /plugins/typescript/typescript-oclif /plugins/typescript-operations -> /plugins/typescript/typescript-operations /plugins/typescript-react-apollo -> /plugins/typescript/typescript-react-apollo /plugins/typescript-react-query -> /plugins/typescript/typescript-react-query /plugins/typescript-resolvers -> /plugins/typescript/typescript-resolvers /plugins/typescript-rtk-query -> /plugins/typescript/typescript-rtk-query /plugins/typescript-stencil-apollo -> /plugins/typescript/typescript-stencil-apollo /plugins/typescript-svelte-apollo -> /plugins/typescript/typescript-svelte-apollo /plugins/typescript-svelte-urql -> /plugins /plugins/typescript-type-graphql -> /plugins/typescript/typescript-type-graphql /plugins/typescript-urql -> /plugins/typescript/typescript-urql /plugins/typescript-urql-graphcache -> /plugins/typescript/typescript-urql /plugins/typescript-validation-schema -> /plugins/typescript/typescript-validation-schema /plugins/typescript-vue-apollo -> /plugins/typescript/typescript-vue-apollo /plugins/typescript-vue-apollo-smart-ops -> /plugins/typescript/typescript-vue-apollo-smart-ops /plugins/typescript-vue-urql -> /plugins/typescript/typescript-vue-urql /plugins/typescript/fragment-matcher -> /plugins/other/fragment-matcher /plugins/typescript/named-operations-object /plugins/typescript/relay-operation-optimizer /plugins/typescript/typed-document-node /plugins/typescript/typescript /plugins/typescript/typescript-apollo-angular /plugins/typescript/typescript-apollo-client-helpers /plugins/typescript/typescript-apollo-next /plugins/typescript/typescript-document-nodes /plugins/typescript/typescript-generic-sdk /plugins/typescript/typescript-graphql-files-modules /plugins/typescript/typescript-graphql-request /plugins/typescript/typescript-mongodb /plugins/typescript/typescript-msw /plugins/typescript/typescript-oclif /plugins/typescript/typescript-operations /plugins/typescript/typescript-react-apollo /plugins/typescript/typescript-react-query /plugins/typescript/typescript-resolvers /plugins/typescript/typescript-rtk-query /plugins/typescript/typescript-stencil-apollo /plugins/typescript/typescript-svelte-apollo /plugins/typescript/typescript-type-graphql /plugins/typescript/typescript-urql /plugins/typescript/typescript-urql-graphcache -> /plugins/typescript/typescript-urql /plugins/typescript/typescript-validation-schema /plugins/typescript/typescript-vue-apollo /plugins/typescript/typescript-vue-apollo-smart-ops /plugins/typescript/typescript-vue-urql /plugins/urql-introspection -> /plugins/other/urql-introspection ================================================ FILE: website/scripts/generate-config-json-schema.ts ================================================ import { writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import jsonPath from 'jsonpath'; import prettier from 'prettier'; import { transformDocs } from '../src/lib/transform'; const MARKDOWN_JSDOC_KEY = 'exampleMarkdown'; const DEFAULT_JSDOC_KEY = 'default'; const CWD = process.cwd(); const OUT_PATH = join(CWD, 'public/config.schema.json'); const prettierOptions = prettier.resolveConfig.sync(CWD); async function generate(): Promise { const { schema } = transformDocs(); // Remove non-standard keys jsonPath.apply(schema, `$..${MARKDOWN_JSDOC_KEY}`, () => undefined); // Remove default to avoid annoying auto-complete jsonPath.apply(schema, `$..*`, v => { if (v && typeof v === 'object' && v[DEFAULT_JSDOC_KEY] !== undefined) { if (!v.description) { v.description = ''; } v.description += `\nDefault value: "${v.default}"`; delete v.default; } return v; }); const prettifiedSchema = prettier.format(JSON.stringify(schema), { ...prettierOptions, parser: 'json' }); await writeFile(OUT_PATH, prettifiedSchema); } generate() .then(() => { console.log('✅ Done!'); }) .catch(e => { console.error(e); }); ================================================ FILE: website/scripts/generate-packages-info.ts ================================================ import { writeFileSync } from 'node:fs'; import path from 'node:path'; import semver from 'semver'; import { PACKAGES } from '../src/lib/plugins/packages.js'; interface PackageInfo { readme: string; createdAt: string; updatedAt: string; description: string; weeklyNPMDownloads: number; } // FIXME: fetchPackageInfo is a simpler version of `@theguild/components`'s fetchPackageInfo // We cannot use the shared package version because it has imports that Next.js understands // but not a simple script like this. So, inlining this version helps unblock deployment const fetchPackageInfo = async (packageName: string): Promise => { const NO_NPM_README_PLACEHOLDER = 'ERROR: No README data found!'; const encodedName = encodeURIComponent(packageName); console.debug(`Loading NPM package info: ${packageName}`); const [packageInfo, { downloads }] = await Promise.all([ fetch(`https://registry.npmjs.org/${encodedName}`).then(response => response.json()), fetch(`https://api.npmjs.org/downloads/point/last-week/${encodedName}`).then(response => response.json()), ]); const { readme, time, description } = packageInfo; const latestVersion = packageInfo['dist-tags'].latest; return { readme: (readme !== NO_NPM_README_PLACEHOLDER && readme) || // for some reason top level "readme" can be empty string, so we get the latest version readme Object.values(packageInfo.versions as { readme?: string; version: string }[]) .reverse() .find(curr => { const isReadmeExist = curr.readme && curr.readme !== NO_NPM_README_PLACEHOLDER; if (isReadmeExist) { return semver.lte(curr.version, latestVersion); } })?.readme || '', createdAt: time.created, updatedAt: time.modified, description, weeklyNPMDownloads: downloads, }; }; const result: Record = {}; for (let [identifier, pkg] of Object.entries(PACKAGES)) { const packageInfo = await fetchPackageInfo(pkg.npmPackage); result[identifier] = packageInfo; await (async function randomSleep({ minMs, maxMs }: { minMs: number; maxMs: number }): Promise { function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } const delay = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs; await sleep(delay); })({ minMs: 100, maxMs: 5000 }); } writeFileSync( path.join(process.cwd(), 'src', 'lib', 'packages-info.generated.ts'), `export const packagesInfo= ${JSON.stringify(result)}`, { encoding: 'utf8', } ); ================================================ FILE: website/scripts/sitemap-ci.mjs ================================================ import fs from 'node:fs/promises'; import path from 'node:path'; import { XMLParser } from 'fast-xml-parser'; import config from '../next.config.mjs'; const parser = new XMLParser(); const sitemapPath = path.join(process.cwd(), 'public', 'sitemap.xml'); const { urlset } = parser.parse(await fs.readFile(sitemapPath, 'utf8')); const routes = urlset.url.map(url => new URL(url.loc).pathname); const redirectsPointingToNonExistingStuff = []; const redirects = await config.redirects(); for (const redirect of redirects) { if (routes.includes(redirect.destination)) { routes.push(`${redirect.source} -> ${redirect.destination}`); } else { redirectsPointingToNonExistingStuff.push(redirect); } } const lockfilePath = path.join(process.cwd(), 'route-lockfile.txt'); await fs.writeFile(lockfilePath, routes.sort().join('\n') + '\n'); ================================================ FILE: website/src/category-to-packages.mjs ================================================ /* Used to determine right category folder in plugins and for redirect legacy links in next.config#redirects */ export const CategoryToPackages = { 'c-sharp': ['c-sharp-operations'], flow: ['flow-operations', 'flow-resolvers'], java: ['java', 'java-apollo-android', 'java-resolvers', 'kotlin'], other: [ 'urql-introspection', 'time', 'schema-ast', 'reason-client', 'jsdoc', 'introspection', 'hasura-allow-list', 'fragment-matcher', 'add', ], presets: ['near-operation-file-preset', 'import-types-preset', 'graphql-modules-preset', 'preset-client'], typescript: [ 'named-operations-object', 'relay-operation-optimizer', 'typed-document-node', 'typescript', 'typescript-apollo-angular', 'typescript-apollo-client-helpers', 'typescript-apollo-next', 'typescript-document-nodes', 'typescript-fabbrica', 'typescript-generic-sdk', 'typescript-graphql-files-modules', 'typescript-graphql-request', 'typescript-mongodb', 'typescript-msw', 'typescript-oclif', 'typescript-operations', 'typescript-react-apollo', 'typescript-react-query', 'typescript-resolvers', 'typescript-rtk-query', 'typescript-stencil-apollo', 'typescript-svelte-apollo', 'typescript-type-graphql', 'typescript-urql', 'typescript-validation-schema', 'typescript-vue-apollo', 'typescript-vue-apollo-smart-ops', 'typescript-vue-urql', 'typescript-mock-data', ], dart: ['flutter-freezed'], }; ================================================ FILE: website/src/components/dev-ex-cards.tsx ================================================ import { cn, Heading, InfoCard } from '@theguild/components'; import boxSvg from './icons/box.svg'; import checkmarksSvg from './icons/checkmarks.svg'; import speedometerSvg from './icons/speedometer.svg'; export function DevExCards(props: { className?: string }) { return (
    Your chance to fully use GraphQL.

    Codegen enhances your GraphQL development with fully typed client and server code, generating robust, error-resistant solutions in seconds

      } className="flex-1 rounded-2xl md:rounded-3xl" > Automate the creation of typed queries, mutations, and subscriptions for frameworks like React, Vue, Angular, and more. } className="flex-1 basis-full rounded-2xl md:basis-0 md:rounded-3xl" > Generate typed GraphQL resolvers for any Node.js or Java GraphQL server, ensuring compatibility and efficiency. } className="flex-1 basis-full rounded-2xl md:rounded-3xl lg:basis-0" > Produce fully-typed Node.js SDKs, enhancing development with reliable, strongly typed software components.
    ); } ================================================ FILE: website/src/components/hero/index.tsx ================================================ import { ReactNode } from 'react'; import { DecorationIsolation, cn, CodegenIcon } from '@theguild/components'; import Image from 'next/image'; import codegenHeroBadge from './codegen-badge.svg'; export function Hero(props: { children: ReactNode; className?: string }) { return (
    {props.children}
    ); } export function HeroLinks(props: { children: ReactNode }) { return (
    {props.children}
    ); } export function HeroFeatures(props: { children: ReactNode }) { return (
      {props.children}
    ); } export function HeroTitle(props: { children: ReactNode }) { return (

    {props.children}

    ); } export function TrustedBy({ className, children, ...rest }: React.HTMLAttributes) { return (

    Trusted by global enterprises and fast-moving startups

    {children}
    ); } ================================================ FILE: website/src/components/index-page.tsx ================================================ import { ReactElement, useEffect, useLayoutEffect } from 'react'; import { ToolsAndLibrariesCards, Heading, CheckIcon, CallToAction, GitHubIcon, cn, InfoCard, Anchor, useData, ExploreMainProductCards, } from '@theguild/components'; import { DevExCards } from './dev-ex-cards'; import { Page } from './page'; import { Hero, HeroFeatures, HeroLinks } from './hero'; import { PluginsMarketplaceSearch, Plugin, getPluginsStaticProps } from './plugins-marketplace-search'; const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect; export { getPluginsStaticProps as getStaticProps }; export function IndexPage(): ReactElement { const plugins = useData() as Plugin[]; useIsomorphicLayoutEffect(() => { // We add .light class to body to style the Headless UI // portal containing search results. document.body.classList.add('light'); return () => { document.body.classList.remove('light'); }; }, []); return ( GraphQL Codegen

    Effortlessly generate comprehensive code from GraphQL schemas and operations, streamlining development across your tech stack.

  • End-to-end type safety
  • Customizable
  • Rich plugins ecosystem
  • Get started GitHub
    ); } function TypeSafeCards({ className }: { className?: string }) { return (
    Generate Type-Safe GraphQL Client and Server Code

    Codegen enhances your GraphQL development with fully typed client and server code, generating robust, error-resistant solutions in seconds

    } className="flex-1 px-0 sm:px-8 sm:py-0 md:px-8 md:py-0" > Codegen ensures your resolvers and client code are compliant with your GraphQL Schema. } className="flex-1 basis-full border-beige-400 px-0 sm:basis-0 sm:border-l sm:px-8 sm:py-0 md:px-8 md:py-0" > Tailor the output that you need with community plugins or write{' '} your own plugins {' '} to generate custom outputs matching your needs.
    ); } function ChevronsIcon(props: React.SVGProps) { return ( ); } function WritingIcon(props: React.SVGProps) { return ( ); } ================================================ FILE: website/src/components/java-installation.mdx ================================================ import { Callout } from '@theguild/components' ## Prepare your environment To use the GraphQL Code Generator with Java, start by adding the [com.moowork.node](https://plugins.gradle.org/plugin/com.moowork.node) Gradle plugin to your `build.gradle`: ``` plugins { id "com.moowork.node" version "1.3.1" } ``` Then, add the following in order to make sure you are running the code-generator on each build: ``` build.dependsOn yarn ``` Then, create a `package.json` file in your project root, with the following content: ```json filename="package.json" { "name": "java-app", "scripts": { "postinstall": "graphql-codegen" }, "dependencies": { "graphql": "14.5.8", "@graphql-codegen/cli": "1.7.0", "@graphql-codegen/RELEVANT_PLUGIN": "1.7.0" } } ``` Make sure to use the latest version of codegen and the plugins, and replace `RELEVANT_PLUGIN` with your plugin name. Then, create `codegen.yml` file in your root directory, pointing to your schema, and add the plugins you need. For example: ```yaml filename="codegen.yml" schema: src/main/resources/schema.graphqls generates: src/main/java/com/my-name/my-app/generated/File.java: - RELEVANT_PLUGIN # Replace with your plugin name ``` Also, make sure you add the following to your `.gitignore` file: ```gitignore filename=".gitignore" yarn.lock node_modules ``` Now, run `gradle yarn` to install the dependencies for the first time. Next time, the codegen will run automatically each time you run your Gradle build script. ================================================ FILE: website/src/components/live-demo/Editor.tsx ================================================ import { ReactElement } from 'react'; import MonacoEditor from '@monaco-editor/react'; import { useTheme } from '@theguild/components'; export function Editor({ value, lang, readOnly, onEdit, }: { lang: string; value: string | undefined; readOnly?: boolean; onEdit?: (value: string | undefined) => void; }): ReactElement { const { resolvedTheme } = useTheme(); return ( ); } ================================================ FILE: website/src/components/live-demo/LiveDemo.tsx ================================================ import { ReactElement, useEffect, useState } from 'react'; import { Image, useTheme } from '@theguild/components'; import Select from 'react-select'; import { icons } from '@/lib/plugins'; import { EXAMPLES } from './examples'; import { generate } from './generate'; import { LiveDemoEditors } from './LiveDemoEditors'; const groupedExamples = Object.entries(EXAMPLES).map(([catName, category]) => ({ label: catName, options: category.map((t, index) => ({ ...t, selectId: `${catName}__${index}` })), })); function useCodegen(config: string | undefined, schema: string | undefined, documents: string | undefined, templateName: string, operationsFileName?: string) { const [error, setError] = useState(null); const [output, setOutput] = useState<{filename: string, content: string}[] | null>(null); useEffect(() => { if (!config || !schema) return; generate(config, schema, documents, operationsFileName).then(result => { if (typeof result === 'string') { setOutput(null); setError(result); } else { setOutput(result); setError(null); } }); }, [config, schema, documents, templateName]); return { error, output }; } const DEFAULT_EXAMPLE = { catName: 'TypeScript', index: 0, } as const; export default function LiveDemo(): ReactElement { const { resolvedTheme } = useTheme(); const isDarkTheme = resolvedTheme === 'dark'; const [template, setTemplate] = useState(`${DEFAULT_EXAMPLE.catName}__${DEFAULT_EXAMPLE.index}`); const [schema, setSchema] = useState(EXAMPLES[DEFAULT_EXAMPLE.catName][DEFAULT_EXAMPLE.index].schema); const [documents, setDocuments] = useState(EXAMPLES[DEFAULT_EXAMPLE.catName][DEFAULT_EXAMPLE.index].documents); const [operationsFile, setOperationsFile] = useState<{filename: string, content: string, language: string} | undefined>(EXAMPLES[DEFAULT_EXAMPLE.catName][DEFAULT_EXAMPLE.index].operationsFile); const [config, setConfig] = useState(EXAMPLES[DEFAULT_EXAMPLE.catName][DEFAULT_EXAMPLE.index].config); const { output, error } = useCodegen(config, schema, documents, template, operationsFile?.filename); const changeTemplate = (value: string | undefined) => { if (!value) return; const [catName, index] = value.split('__'); setSchema(EXAMPLES[catName][Number(index)].schema); setDocuments(EXAMPLES[catName][Number(index)].documents); setOperationsFile(EXAMPLES[catName][Number(index)].operationsFile); setConfig(EXAMPLES[catName][Number(index)].config); setTemplate(value); }; return (

    Choose Live Example: