From 4a7b339637fe396f71fd5cbe33cc89fe84228bb9 Mon Sep 17 00:00:00 2001 From: beerose Date: Wed, 8 Mar 2023 13:51:08 +0100 Subject: [PATCH 01/28] Add unit tests --- .../client/tests/client-preset.spec.ts | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/packages/presets/client/tests/client-preset.spec.ts b/packages/presets/client/tests/client-preset.spec.ts index b2bb984e8b7..060a9bc89d4 100644 --- a/packages/presets/client/tests/client-preset.spec.ts +++ b/packages/presets/client/tests/client-preset.spec.ts @@ -1612,4 +1612,175 @@ export * from "./gql.js";`); 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('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 { TypedDocumentString } 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 }; + /** 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 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 const FooFragmentDoc = \` + fragment Foo on Foo { + value + } + \` as unknown as TypedDocumentString; + export const FooDocument = \` + query Foo { + foo { + ...Foo + } + } + \${FooFragmentDoc}\` as unknown as TypedDocumentString; + export const FoosDocument = \` + query Foos { + foos { + ...Foo + } + } + \${FooFragmentDoc}\` as unknown as TypedDocumentString;" + `); + }); + + it('does not include documents dictionary', 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).not.toContain('const documents = {'); + }); + + 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 */ + /** + * 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): string { return source; }" + `); + }); + }); }); From 504367a9d50dd368943a1f7bd02f39c15b75328f Mon Sep 17 00:00:00 2001 From: beerose Date: Wed, 8 Mar 2023 16:42:14 +0100 Subject: [PATCH 02/28] Add TypedDocumentNode string alternative --- .../urql-string-document-mode/.gitignore | 23 + .../react/urql-string-document-mode/README.md | 17 + .../urql-string-document-mode/codegen.ts | 18 + .../cypress.config.ts | 10 + .../cypress/e2e/end2end.cy.ts | 6 + .../cypress/support/commands.ts | 1 + .../cypress/support/e2e.ts | 1 + .../urql-string-document-mode/index.html | 13 + .../urql-string-document-mode/package.json | 30 + .../urql-string-document-mode/public/vite.svg | 1 + .../urql-string-document-mode/src/App.css | 38 + .../urql-string-document-mode/src/App.tsx | 62 + .../urql-string-document-mode/src/Film.tsx | 26 + .../src/gql/fragment-masking.ts | 48 + .../urql-string-document-mode/src/gql/gql.ts | 36 + .../src/gql/graphql.ts | 1320 +++++++++++++++++ .../src/gql/index.ts | 2 + .../urql-string-document-mode/src/logo.svg | 1 + .../urql-string-document-mode/src/main.css | 11 + .../urql-string-document-mode/src/main.tsx | 19 + .../src/vite-env.d.ts | 1 + .../urql-string-document-mode/tsconfig.json | 18 + .../tsconfig.node.json | 9 + .../urql-string-document-mode/vite.config.ts | 8 + .../gql-tag-operations/src/index.ts | 39 +- .../typed-document-node/src/index.ts | 11 +- .../typed-document-node/src/visitor.ts | 13 +- .../client/src/fragment-masking-plugin.ts | 10 +- packages/presets/client/src/index.ts | 1 + 29 files changed, 1778 insertions(+), 15 deletions(-) create mode 100644 examples/react/urql-string-document-mode/.gitignore create mode 100644 examples/react/urql-string-document-mode/README.md create mode 100644 examples/react/urql-string-document-mode/codegen.ts create mode 100644 examples/react/urql-string-document-mode/cypress.config.ts create mode 100644 examples/react/urql-string-document-mode/cypress/e2e/end2end.cy.ts create mode 100644 examples/react/urql-string-document-mode/cypress/support/commands.ts create mode 100644 examples/react/urql-string-document-mode/cypress/support/e2e.ts create mode 100644 examples/react/urql-string-document-mode/index.html create mode 100644 examples/react/urql-string-document-mode/package.json create mode 100644 examples/react/urql-string-document-mode/public/vite.svg create mode 100644 examples/react/urql-string-document-mode/src/App.css create mode 100644 examples/react/urql-string-document-mode/src/App.tsx create mode 100644 examples/react/urql-string-document-mode/src/Film.tsx create mode 100644 examples/react/urql-string-document-mode/src/gql/fragment-masking.ts create mode 100644 examples/react/urql-string-document-mode/src/gql/gql.ts create mode 100644 examples/react/urql-string-document-mode/src/gql/graphql.ts create mode 100644 examples/react/urql-string-document-mode/src/gql/index.ts create mode 100644 examples/react/urql-string-document-mode/src/logo.svg create mode 100644 examples/react/urql-string-document-mode/src/main.css create mode 100644 examples/react/urql-string-document-mode/src/main.tsx create mode 100644 examples/react/urql-string-document-mode/src/vite-env.d.ts create mode 100644 examples/react/urql-string-document-mode/tsconfig.json create mode 100644 examples/react/urql-string-document-mode/tsconfig.node.json create mode 100644 examples/react/urql-string-document-mode/vite.config.ts diff --git a/examples/react/urql-string-document-mode/.gitignore b/examples/react/urql-string-document-mode/.gitignore new file mode 100644 index 00000000000..4d29575de80 --- /dev/null +++ b/examples/react/urql-string-document-mode/.gitignore @@ -0,0 +1,23 @@ +# 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* diff --git a/examples/react/urql-string-document-mode/README.md b/examples/react/urql-string-document-mode/README.md new file mode 100644 index 00000000000..229c82db86a --- /dev/null +++ b/examples/react/urql-string-document-mode/README.md @@ -0,0 +1,17 @@ +# 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`). diff --git a/examples/react/urql-string-document-mode/codegen.ts b/examples/react/urql-string-document-mode/codegen.ts new file mode 100644 index 00000000000..abe3f780e4f --- /dev/null +++ b/examples/react/urql-string-document-mode/codegen.ts @@ -0,0 +1,18 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { type CodegenConfig } from '@graphql-codegen/cli'; + +const config: CodegenConfig = { + schema: 'https://swapi-graphql.netlify.app/.netlify/functions/index', + documents: ['src/**/*.tsx', '!src/gql/**/*'], + generates: { + './src/gql/': { + preset: 'client', + config: { + documentMode: 'string', + }, + }, + }, + hooks: { afterAllFileWrite: ['prettier --write'] }, +}; + +export default config; diff --git a/examples/react/urql-string-document-mode/cypress.config.ts b/examples/react/urql-string-document-mode/cypress.config.ts new file mode 100644 index 00000000000..b1c137b9e05 --- /dev/null +++ b/examples/react/urql-string-document-mode/cypress.config.ts @@ -0,0 +1,10 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { defineConfig } from 'cypress'; + +export default defineConfig({ + e2e: { + setupNodeEvents(_on, _config) { + // implement node event listeners here + }, + }, +}); diff --git a/examples/react/urql-string-document-mode/cypress/e2e/end2end.cy.ts b/examples/react/urql-string-document-mode/cypress/e2e/end2end.cy.ts new file mode 100644 index 00000000000..5a61258ecac --- /dev/null +++ b/examples/react/urql-string-document-mode/cypress/e2e/end2end.cy.ts @@ -0,0 +1,6 @@ +describe('template spec', () => { + it('renders everything correctly', () => { + cy.visit('http://localhost:3000'); + cy.get('h3').should('contain', 'A New Hope'); + }); +}); diff --git a/examples/react/urql-string-document-mode/cypress/support/commands.ts b/examples/react/urql-string-document-mode/cypress/support/commands.ts new file mode 100644 index 00000000000..6d4cbd5a68a --- /dev/null +++ b/examples/react/urql-string-document-mode/cypress/support/commands.ts @@ -0,0 +1 @@ +/// diff --git a/examples/react/urql-string-document-mode/cypress/support/e2e.ts b/examples/react/urql-string-document-mode/cypress/support/e2e.ts new file mode 100644 index 00000000000..1221b17e096 --- /dev/null +++ b/examples/react/urql-string-document-mode/cypress/support/e2e.ts @@ -0,0 +1 @@ +import './commands'; diff --git a/examples/react/urql-string-document-mode/index.html b/examples/react/urql-string-document-mode/index.html new file mode 100644 index 00000000000..ab66da90506 --- /dev/null +++ b/examples/react/urql-string-document-mode/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/react/urql-string-document-mode/package.json b/examples/react/urql-string-document-mode/package.json new file mode 100644 index 00000000000..24c941c69e2 --- /dev/null +++ b/examples/react/urql-string-document-mode/package.json @@ -0,0 +1,30 @@ +{ + "name": "example-react-urql-string-document-node", + "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": "^3.2.2", + "@graphql-codegen/client-preset": "^2.1.1", + "@vitejs/plugin-react": "^3.1.0", + "typescript": "4.9.5", + "serve": "14.2.0", + "cypress": "12.6.0", + "start-server-and-test": "2.0.0", + "vite": "^4.1.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" + } +} diff --git a/examples/react/urql-string-document-mode/public/vite.svg b/examples/react/urql-string-document-mode/public/vite.svg new file mode 100644 index 00000000000..ee9fadaf9c4 --- /dev/null +++ b/examples/react/urql-string-document-mode/public/vite.svg @@ -0,0 +1 @@ + diff --git a/examples/react/urql-string-document-mode/src/App.css b/examples/react/urql-string-document-mode/src/App.css new file mode 100644 index 00000000000..74b5e053450 --- /dev/null +++ b/examples/react/urql-string-document-mode/src/App.css @@ -0,0 +1,38 @@ +.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); + } +} diff --git a/examples/react/urql-string-document-mode/src/App.tsx b/examples/react/urql-string-document-mode/src/App.tsx new file mode 100644 index 00000000000..36ba14d5e09 --- /dev/null +++ b/examples/react/urql-string-document-mode/src/App.tsx @@ -0,0 +1,62 @@ +import { TypedDocumentString } from '@graphql-typed-document-node/core'; + +import './App.css'; +import Film from './Film'; +import { graphql } from './gql'; +import { AnyVariables, OperationContext, RequestPolicy, TypedDocumentNode, useQuery, UseQueryResponse } from 'urql'; +import type { DocumentNode } from 'graphql'; + +const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` + query allFilmsWithVariablesQuery($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 | TypedDocumentNode | TypedDocumentString; + 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, + variables: { + first: 10, + }, + }); + + return ( +
+ {data &&
    {data.allFilms?.edges?.map((e, i) => e?.node && )}
} +
+ ); +} + +export default App; diff --git a/examples/react/urql-string-document-mode/src/Film.tsx b/examples/react/urql-string-document-mode/src/Film.tsx new file mode 100644 index 00000000000..0681a716142 --- /dev/null +++ b/examples/react/urql-string-document-mode/src/Film.tsx @@ -0,0 +1,26 @@ +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; diff --git a/examples/react/urql-string-document-mode/src/gql/fragment-masking.ts b/examples/react/urql-string-document-mode/src/gql/fragment-masking.ts new file mode 100644 index 00000000000..dc2836d43e3 --- /dev/null +++ b/examples/react/urql-string-document-mode/src/gql/fragment-masking.ts @@ -0,0 +1,48 @@ +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; + +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 nullable +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: ReadonlyArray>> +): ReadonlyArray; +// return 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> + | ReadonlyArray>> + | null + | undefined +): TType | ReadonlyArray | null | undefined { + return fragmentType as any; +} + +export function makeFragmentData, FT extends ResultOf>( + data: FT, + _fragment: F +): FragmentType { + return data as FragmentType; +} diff --git a/examples/react/urql-string-document-mode/src/gql/gql.ts b/examples/react/urql-string-document-mode/src/gql/gql.ts new file mode 100644 index 00000000000..ab23ba6aa75 --- /dev/null +++ b/examples/react/urql-string-document-mode/src/gql/gql.ts @@ -0,0 +1,36 @@ +/* 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. + */ +const 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] ?? {}; +} diff --git a/examples/react/urql-string-document-mode/src/gql/graphql.ts b/examples/react/urql-string-document-mode/src/gql/graphql.ts new file mode 100644 index 00000000000..3a71621777f --- /dev/null +++ b/examples/react/urql-string-document-mode/src/gql/graphql.ts @@ -0,0 +1,1320 @@ +/* eslint-disable */ +import { TypedDocumentString } 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 }; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: string; + String: string; + Boolean: boolean; + Int: number; + Float: 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; +}; + +/** 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']; + /** When paginating backwards, are there more items? */ + hasPreviousPage: Scalars['Boolean']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; +}; + +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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** 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']; + /** The item at the end of the edge */ + node?: Maybe; +}; + +export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ + first: Scalars['Int']; +}>; + +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 = ` + fragment FilmItem on Film { + id + title + releaseDate + producers +} + ` as unknown as TypedDocumentString; +export const AllFilmsWithVariablesQueryDocument = ` + query allFilmsWithVariablesQuery($first: Int!) { + allFilms(first: $first) { + edges { + node { + ...FilmItem + } + } + } +} + ${FilmItemFragmentDoc}` as unknown as TypedDocumentString< + AllFilmsWithVariablesQueryQuery, + AllFilmsWithVariablesQueryQueryVariables +>; diff --git a/examples/react/urql-string-document-mode/src/gql/index.ts b/examples/react/urql-string-document-mode/src/gql/index.ts new file mode 100644 index 00000000000..c682b1e2f99 --- /dev/null +++ b/examples/react/urql-string-document-mode/src/gql/index.ts @@ -0,0 +1,2 @@ +export * from './fragment-masking'; +export * from './gql'; diff --git a/examples/react/urql-string-document-mode/src/logo.svg b/examples/react/urql-string-document-mode/src/logo.svg new file mode 100644 index 00000000000..9dfc1c058ce --- /dev/null +++ b/examples/react/urql-string-document-mode/src/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/react/urql-string-document-mode/src/main.css b/examples/react/urql-string-document-mode/src/main.css new file mode 100644 index 00000000000..7323ae85c54 --- /dev/null +++ b/examples/react/urql-string-document-mode/src/main.css @@ -0,0 +1,11 @@ +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; +} diff --git a/examples/react/urql-string-document-mode/src/main.tsx b/examples/react/urql-string-document-mode/src/main.tsx new file mode 100644 index 00000000000..09887543cb6 --- /dev/null +++ b/examples/react/urql-string-document-mode/src/main.tsx @@ -0,0 +1,19 @@ +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://swapi-graphql.netlify.app/.netlify/functions/index', +}); + +const root = ReactDOM.createRoot(document.getElementById('app') as HTMLElement); +root.render( + + + + + +); diff --git a/examples/react/urql-string-document-mode/src/vite-env.d.ts b/examples/react/urql-string-document-mode/src/vite-env.d.ts new file mode 100644 index 00000000000..11f02fe2a00 --- /dev/null +++ b/examples/react/urql-string-document-mode/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/react/urql-string-document-mode/tsconfig.json b/examples/react/urql-string-document-mode/tsconfig.json new file mode 100644 index 00000000000..b557c4047ca --- /dev/null +++ b/examples/react/urql-string-document-mode/tsconfig.json @@ -0,0 +1,18 @@ +{ + "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" }] +} diff --git a/examples/react/urql-string-document-mode/tsconfig.node.json b/examples/react/urql-string-document-mode/tsconfig.node.json new file mode 100644 index 00000000000..9d31e2aed93 --- /dev/null +++ b/examples/react/urql-string-document-mode/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/examples/react/urql-string-document-mode/vite.config.ts b/examples/react/urql-string-document-mode/vite.config.ts new file mode 100644 index 00000000000..779543405fa --- /dev/null +++ b/examples/react/urql-string-document-mode/vite.config.ts @@ -0,0 +1,8 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}); diff --git a/packages/plugins/typescript/gql-tag-operations/src/index.ts b/packages/plugins/typescript/gql-tag-operations/src/index.ts index ee6344abf59..a925fa00e5b 100644 --- a/packages/plugins/typescript/gql-tag-operations/src/index.ts +++ b/packages/plugins/typescript/gql-tag-operations/src/index.ts @@ -1,4 +1,5 @@ import { 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'; @@ -27,12 +28,48 @@ export const plugin: PluginFunction<{ augmentedModuleName?: string; gqlTagName?: string; emitLegacyCommonJSImports?: boolean; + documentMode?: DocumentMode; }> = ( _, __, - { sourcesWithOperations, useTypeImports, augmentedModuleName, gqlTagName = 'gql', emitLegacyCommonJSImports }, + { + sourcesWithOperations, + useTypeImports, + augmentedModuleName, + gqlTagName = 'gql', + emitLegacyCommonJSImports, + documentMode, + }, _info ) => { + if (documentMode === DocumentMode.string) { + const code = [`import * as types from './graphql${emitLegacyCommonJSImports ? '' : '.js'}';\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', emitLegacyCommonJSImports), `\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${emitLegacyCommonJSImports ? '' : '.js'}';\n`, diff --git a/packages/plugins/typescript/typed-document-node/src/index.ts b/packages/plugins/typescript/typed-document-node/src/index.ts index bbc95cd78a8..c5f78bf01ef 100644 --- a/packages/plugins/typescript/typed-document-node/src/index.ts +++ b/packages/plugins/typescript/typed-document-node/src/index.ts @@ -1,7 +1,6 @@ import { extname } from 'path'; import { oldVisit, PluginFunction, PluginValidateFn, Types } from '@graphql-codegen/plugin-helpers'; import { - DocumentMode, LoadedFragment, optimizeOperations, RawClientSideBasePluginConfig, @@ -40,15 +39,11 @@ export const plugin: PluginFunction = ( }; export const validate: PluginValidateFn = async ( - schema: GraphQLSchema, - documents: Types.DocumentFile[], - config, + _schema: GraphQLSchema, + _documents: Types.DocumentFile[], + _config, outputFile: string ) => { - if (config && config.documentMode === DocumentMode.string) { - throw new Error(`Plugin "typed-document-node" does not allow using 'documentMode: string' configuration!`); - } - if (extname(outputFile) !== '.ts' && extname(outputFile) !== '.tsx') { throw new Error(`Plugin "typed-document-node" requires extension to be ".ts" or ".tsx"!`); } diff --git a/packages/plugins/typescript/typed-document-node/src/visitor.ts b/packages/plugins/typescript/typed-document-node/src/visitor.ts index dd0977eae2f..beedd52eeec 100644 --- a/packages/plugins/typescript/typed-document-node/src/visitor.ts +++ b/packages/plugins/typescript/typed-document-node/src/visitor.ts @@ -29,9 +29,9 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor< schema, fragments, { - documentMode: DocumentMode.documentNodeImportFragments, documentNodeImport: '@graphql-typed-document-node/core#TypedDocumentNode', ...config, + documentMode: config.documentMode || DocumentMode.documentNodeImportFragments, }, {}, documents @@ -46,6 +46,13 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor< 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: 'TypedDocumentString' }, + 'TypedDocumentString', + true + ); + this._imports.add(tagImport); } } @@ -99,6 +106,10 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor< return ` as unknown as DocumentNode<${resultType}, ${variablesTypes}>`; } + if (this.config.documentMode === DocumentMode.string) { + return ` as unknown as TypedDocumentString<${resultType}, ${variablesTypes}>`; + } + return super.getDocumentNodeSignature(resultType, variablesTypes, node); } } diff --git a/packages/presets/client/src/fragment-masking-plugin.ts b/packages/presets/client/src/fragment-masking-plugin.ts index b8b63e276f5..df1224c21ce 100644 --- a/packages/presets/client/src/fragment-masking-plugin.ts +++ b/packages/presets/client/src/fragment-masking-plugin.ts @@ -1,7 +1,7 @@ import type { PluginFunction } from '@graphql-codegen/plugin-helpers'; const fragmentTypeHelper = ` -export type FragmentType> = TDocumentType extends DocumentNode< +export type FragmentType> = TDocumentType extends DocumentTypeDecoration< infer TType, any > @@ -14,7 +14,7 @@ export type FragmentType> = TDocume const makeFragmentDataHelper = ` export function makeFragmentData< - F extends DocumentNode, + F extends DocumentTypeDecoration, FT extends ResultOf >(data: FT, _fragment: F): FragmentType { return data as FragmentType; @@ -35,8 +35,8 @@ const createUnmaskFunctionTypeDefinition = ( unmaskFunctionName = defaultUnmaskFunctionName, opts: { nullable: boolean; list: 'with-list' | 'only-list' | false } ) => `export function ${unmaskFunctionName}( - _documentNode: DocumentNode, - fragmentType: ${modifyType('FragmentType>', opts)} + _documentNode: DocumentTypeDecoration, + fragmentType: ${modifyType('FragmentType>', opts)} ): ${modifyType('TType', opts)}`; const createUnmaskFunctionTypeDefinitions = (unmaskFunctionName = defaultUnmaskFunctionName) => [ @@ -76,7 +76,7 @@ export const plugin: PluginFunction<{ }> = (_, __, { useTypeImports, augmentedModuleName, unmaskFunctionName }, _info) => { const documentNodeImport = `${ useTypeImports ? 'import type' : 'import' - } { ResultOf, TypedDocumentNode as DocumentNode, } from '@graphql-typed-document-node/core';\n`; + } { ResultOf, DocumentTypeDecoration, } from '@graphql-typed-document-node/core';\n`; if (augmentedModuleName == null) { return [ diff --git a/packages/presets/client/src/index.ts b/packages/presets/client/src/index.ts index f72e1b6392c..92d4beddbab 100644 --- a/packages/presets/client/src/index.ts +++ b/packages/presets/client/src/index.ts @@ -118,6 +118,7 @@ export const preset: Types.OutputPreset = { dedupeFragments: options.config.dedupeFragments, nonOptionalTypename: options.config.nonOptionalTypename, avoidOptionals: options.config.avoidOptionals, + documentMode: options.config.documentMode, }; const visitor = new ClientSideBaseVisitor(options.schemaAst!, [], options.config, options.config); From c7105db1f1f14f3e67fab63e615f3a56c13dab9c Mon Sep 17 00:00:00 2001 From: beerose Date: Thu, 9 Mar 2023 11:51:18 +0100 Subject: [PATCH 03/28] Temporarily use snapshot version of @graphql-typed-document-node/core --- packages/presets/client/package.json | 2 +- yarn.lock | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/presets/client/package.json b/packages/presets/client/package.json index 7f9273f5587..5ca0fa95179 100644 --- a/packages/presets/client/package.json +++ b/packages/presets/client/package.json @@ -26,7 +26,7 @@ "@graphql-codegen/gql-tag-operations": "2.0.2", "@graphql-codegen/plugin-helpers": "^4.1.0", "@graphql-codegen/visitor-plugin-common": "^3.0.2", - "@graphql-typed-document-node/core": "3.1.2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", "@graphql-tools/documents": "^0.1.0", "@graphql-tools/utils": "^9.0.0", "tslib": "~2.5.0" diff --git a/yarn.lock b/yarn.lock index 747a4a8ff37..0439fbd6233 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2762,6 +2762,11 @@ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.2.tgz#6fc464307cbe3c8ca5064549b806360d84457b04" integrity sha512-9anpBMM9mEgZN4wr2v8wHJI2/u5TnnggewRN6OlvXTTnuVyoY19X6rOv9XTqKRw6dcGKwZsBi8n0kDE2I5i4VA== +"@graphql-typed-document-node/core@3.2.0-alpha-20230309104331-975d9d2": + version "3.2.0-alpha-20230309104331-975d9d2" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0-alpha-20230309104331-975d9d2.tgz#b2af94b5dd0e1aee4a35657015d503a12c536752" + integrity sha512-qXJvJJf8FdjxM+4Zk71pCRfw1WOU9Nky4riMKQ4FVKRTrK0EHcvbQCCQ5v+SAsJxBZceJuO/g+Czi5jh1h12YQ== + "@graphql-yoga/logger@^0.0.1": version "0.0.1" resolved "https://registry.yarnpkg.com/@graphql-yoga/logger/-/logger-0.0.1.tgz#48504fa6ecaee487d9df00fd44c28e356635a324" From 13e48a92e056461959b63b2941bbd9ef9f900c5b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 9 Mar 2023 10:52:08 +0000 Subject: [PATCH 04/28] chore(dependencies): updated changesets for modified dependencies --- .../@graphql-codegen_client-preset-9137-dependencies.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/@graphql-codegen_client-preset-9137-dependencies.md diff --git a/.changeset/@graphql-codegen_client-preset-9137-dependencies.md b/.changeset/@graphql-codegen_client-preset-9137-dependencies.md new file mode 100644 index 00000000000..923091d3e99 --- /dev/null +++ b/.changeset/@graphql-codegen_client-preset-9137-dependencies.md @@ -0,0 +1,5 @@ +--- +"@graphql-codegen/client-preset": patch +--- +dependencies updates: + - Updated dependency [`@graphql-typed-document-node/core@3.2.0-alpha-20230309104331-975d9d2` ↗︎](https://www.npmjs.com/package/@graphql-typed-document-node/core/v/3.2.0) (from `3.1.2`, in `dependencies`) From 02ed2b3c38bc83a33d479b3f46c196c1c14db42a Mon Sep 17 00:00:00 2001 From: beerose Date: Thu, 9 Mar 2023 11:59:30 +0100 Subject: [PATCH 05/28] Update fragment-masking.ts files --- .../src/gql/fragment-masking.ts | 42 +++++++++---------- .../src/gql/fragment-masking.ts | 42 +++++++++---------- .../apollo-client/src/gql/fragment-masking.ts | 42 +++++++++---------- .../src/gql/fragment-masking.ts | 42 +++++++++---------- .../react/nextjs-swr/gql/fragment-masking.ts | 42 +++++++++---------- .../src/gql/fragment-masking.ts | 42 +++++++++---------- .../react/urql/src/gql/fragment-masking.ts | 42 +++++++++---------- .../src/gql/fragment-masking.ts | 42 +++++++++---------- .../src/gql/fragment-masking.ts | 42 +++++++++---------- .../src/gql/fragment-masking.ts | 42 +++++++++---------- .../src/gql/fragment-masking.ts | 42 +++++++++---------- .../vite-react-ts/src/gql/fragment-masking.ts | 42 +++++++++---------- .../src/gql/fragment-masking.ts | 42 +++++++++---------- examples/vue/urql/src/gql/fragment-masking.ts | 42 +++++++++---------- .../vue/villus/src/gql/fragment-masking.ts | 42 +++++++++---------- .../yoga-tests/src/gql/fragment-masking.ts | 42 +++++++++---------- 16 files changed, 320 insertions(+), 352 deletions(-) diff --git a/examples/persisted-documents/src/gql/fragment-masking.ts b/examples/persisted-documents/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/persisted-documents/src/gql/fragment-masking.ts +++ b/examples/persisted-documents/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/react/apollo-client-swc-plugin/src/gql/fragment-masking.ts b/examples/react/apollo-client-swc-plugin/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/react/apollo-client-swc-plugin/src/gql/fragment-masking.ts +++ b/examples/react/apollo-client-swc-plugin/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/react/apollo-client/src/gql/fragment-masking.ts b/examples/react/apollo-client/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/react/apollo-client/src/gql/fragment-masking.ts +++ b/examples/react/apollo-client/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/react/graphql-request/src/gql/fragment-masking.ts b/examples/react/graphql-request/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/react/graphql-request/src/gql/fragment-masking.ts +++ b/examples/react/graphql-request/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/react/nextjs-swr/gql/fragment-masking.ts b/examples/react/nextjs-swr/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/react/nextjs-swr/gql/fragment-masking.ts +++ b/examples/react/nextjs-swr/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/react/tanstack-react-query/src/gql/fragment-masking.ts b/examples/react/tanstack-react-query/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/react/tanstack-react-query/src/gql/fragment-masking.ts +++ b/examples/react/tanstack-react-query/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/react/urql/src/gql/fragment-masking.ts b/examples/react/urql/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/react/urql/src/gql/fragment-masking.ts +++ b/examples/react/urql/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/typescript-esm/src/gql/fragment-masking.ts b/examples/typescript-esm/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/typescript-esm/src/gql/fragment-masking.ts +++ b/examples/typescript-esm/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/typescript-graphql-request/src/gql/fragment-masking.ts b/examples/typescript-graphql-request/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/typescript-graphql-request/src/gql/fragment-masking.ts +++ b/examples/typescript-graphql-request/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/vite/vite-react-cts/src/gql/fragment-masking.ts b/examples/vite/vite-react-cts/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/vite/vite-react-cts/src/gql/fragment-masking.ts +++ b/examples/vite/vite-react-cts/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/vite/vite-react-mts/src/gql/fragment-masking.ts b/examples/vite/vite-react-mts/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/vite/vite-react-mts/src/gql/fragment-masking.ts +++ b/examples/vite/vite-react-mts/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/vite/vite-react-ts/src/gql/fragment-masking.ts b/examples/vite/vite-react-ts/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/vite/vite-react-ts/src/gql/fragment-masking.ts +++ b/examples/vite/vite-react-ts/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/vue/apollo-composable/src/gql/fragment-masking.ts b/examples/vue/apollo-composable/src/gql/fragment-masking.ts index 6d54e46cde8..bb601eea66b 100644 --- a/examples/vue/apollo-composable/src/gql/fragment-masking.ts +++ b/examples/vue/apollo-composable/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import type { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import type { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/vue/urql/src/gql/fragment-masking.ts b/examples/vue/urql/src/gql/fragment-masking.ts index 6d54e46cde8..bb601eea66b 100644 --- a/examples/vue/urql/src/gql/fragment-masking.ts +++ b/examples/vue/urql/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import type { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import type { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/vue/villus/src/gql/fragment-masking.ts b/examples/vue/villus/src/gql/fragment-masking.ts index 6d54e46cde8..bb601eea66b 100644 --- a/examples/vue/villus/src/gql/fragment-masking.ts +++ b/examples/vue/villus/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import type { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import type { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { diff --git a/examples/yoga-tests/src/gql/fragment-masking.ts b/examples/yoga-tests/src/gql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/examples/yoga-tests/src/gql/fragment-masking.ts +++ b/examples/yoga-tests/src/gql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { From 2d5a4e75d03a565b98df8f5f189379bf1ddd4f14 Mon Sep 17 00:00:00 2001 From: beerose Date: Thu, 9 Mar 2023 12:08:25 +0100 Subject: [PATCH 06/28] Update fragment-masking in dev-test dir --- .../graphql/fragment-masking.ts | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/dev-test/gql-tag-operations/graphql/fragment-masking.ts b/dev-test/gql-tag-operations/graphql/fragment-masking.ts index 195a11ebd3e..dc2836d43e3 100644 --- a/dev-test/gql-tag-operations/graphql/fragment-masking.ts +++ b/dev-test/gql-tag-operations/graphql/fragment-masking.ts @@ -1,48 +1,46 @@ -import { ResultOf, TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentTypeDecoration + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable export function useFragment( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function useFragment( - _documentNode: DocumentNode, + _documentNode: DocumentTypeDecoration, fragmentType: - | FragmentType> - | ReadonlyArray>> + | FragmentType> + | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } -export function makeFragmentData>( +export function makeFragmentData, FT extends ResultOf>( data: FT, _fragment: F ): FragmentType { From 590b2e2cce45206b9339f3879f7f6a1447c59ae1 Mon Sep 17 00:00:00 2001 From: beerose Date: Thu, 9 Mar 2023 12:24:52 +0100 Subject: [PATCH 07/28] Update @graphql-typed-document-node/core version in examples --- examples/persisted-documents/package.json | 2 +- examples/typescript-esm/package.json | 2 +- examples/vite/vite-react-cts/package.json | 2 +- examples/vite/vite-react-mts/package.json | 2 +- examples/vite/vite-react-ts/package.json | 2 +- examples/yoga-tests/package.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/persisted-documents/package.json b/examples/persisted-documents/package.json index 27feced9f35..1b4d2c2ed71 100644 --- a/examples/persisted-documents/package.json +++ b/examples/persisted-documents/package.json @@ -7,7 +7,7 @@ "@graphql-yoga/plugin-persisted-operations": "1.7.2" }, "devDependencies": { - "@graphql-typed-document-node/core": "3.1.2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", "jest": "28.1.3", "babel-jest": "28.1.3", "@graphql-codegen/cli": "3.2.2", diff --git a/examples/typescript-esm/package.json b/examples/typescript-esm/package.json index 0667eff5b57..853d015293b 100644 --- a/examples/typescript-esm/package.json +++ b/examples/typescript-esm/package.json @@ -7,7 +7,7 @@ "@graphql-codegen/client-preset": "2.1.1" }, "dependencies": { - "@graphql-typed-document-node/core": "3.1.2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", "graphql": "16.6.0" }, "scripts": { diff --git a/examples/vite/vite-react-cts/package.json b/examples/vite/vite-react-cts/package.json index 775637d07cd..ffd9e823e38 100644 --- a/examples/vite/vite-react-cts/package.json +++ b/examples/vite/vite-react-cts/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@apollo/client": "^3.6.9", - "@graphql-typed-document-node/core": "3.1.2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.6.0", "react": "^18.2.0", diff --git a/examples/vite/vite-react-mts/package.json b/examples/vite/vite-react-mts/package.json index a0f97c721c7..4d0b5eb2c36 100644 --- a/examples/vite/vite-react-mts/package.json +++ b/examples/vite/vite-react-mts/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@apollo/client": "^3.6.9", - "@graphql-typed-document-node/core": "3.1.2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.6.0", "react": "^18.2.0", diff --git a/examples/vite/vite-react-ts/package.json b/examples/vite/vite-react-ts/package.json index c25a3042a2a..a7f42b1e71d 100644 --- a/examples/vite/vite-react-ts/package.json +++ b/examples/vite/vite-react-ts/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@apollo/client": "^3.6.9", - "@graphql-typed-document-node/core": "3.1.2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.6.0", "react": "^18.2.0", diff --git a/examples/yoga-tests/package.json b/examples/yoga-tests/package.json index c20f6d0d268..238cdbf176b 100644 --- a/examples/yoga-tests/package.json +++ b/examples/yoga-tests/package.json @@ -6,7 +6,7 @@ "graphql-yoga": "3.7.2" }, "devDependencies": { - "@graphql-typed-document-node/core": "3.1.2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", "jest": "28.1.3", "babel-jest": "28.1.3", "@graphql-codegen/cli": "3.2.2", From 7a5d42dfa66280bfc7ce63f3ac9ddcfeb538d795 Mon Sep 17 00:00:00 2001 From: beerose Date: Thu, 9 Mar 2023 15:22:03 +0100 Subject: [PATCH 08/28] Update test after latest implememntation changes --- .../client/tests/client-preset.spec.ts | 100 ++++++++---------- 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/packages/presets/client/tests/client-preset.spec.ts b/packages/presets/client/tests/client-preset.spec.ts index 060a9bc89d4..0190b0b60df 100644 --- a/packages/presets/client/tests/client-preset.spec.ts +++ b/packages/presets/client/tests/client-preset.spec.ts @@ -748,10 +748,10 @@ export * from "./gql";`); expect(result).toHaveLength(4); const gqlFile = result.find(file => file.filename === 'out1/fragment-masking.ts'); expect(gqlFile.content).toMatchInlineSnapshot(` - "import { ResultOf, TypedDocumentNode as DocumentNode, } from '@graphql-typed-document-node/core'; + "import { ResultOf, DocumentTypeDecoration, } from '@graphql-typed-document-node/core'; - export type FragmentType> = TDocumentType extends DocumentNode< + export type FragmentType> = TDocumentType extends DocumentTypeDecoration< infer TType, any > @@ -764,34 +764,34 @@ export * from "./gql";`); // return non-nullable if \`fragmentType\` is non-nullable export function iLikeTurtles( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; // return nullable if \`fragmentType\` is nullable export function iLikeTurtles( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _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: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if \`fragmentType\` is array of nullable export function iLikeTurtles( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; export function iLikeTurtles( - _documentNode: DocumentNode, - fragmentType: FragmentType> | ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } export function makeFragmentData< - F extends DocumentNode, + F extends DocumentTypeDecoration, FT extends ResultOf >(data: FT, _fragment: F): FragmentType { return data as FragmentType; @@ -800,32 +800,32 @@ export * from "./gql";`); expect(gqlFile.content).toBeSimilarStringTo(` export function iLikeTurtles( - _documentNode: DocumentNode, - fragmentType: FragmentType> + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> ): TType; `); expect(gqlFile.content).toBeSimilarStringTo(` export function iLikeTurtles( - _documentNode: DocumentNode, - fragmentType: FragmentType> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> | null | undefined ): TType | null | undefined; `); expect(gqlFile.content).toBeSimilarStringTo(` export function iLikeTurtles( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> ): ReadonlyArray; `); expect(gqlFile.content).toBeSimilarStringTo(` export function iLikeTurtles( - _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; `); expect(gqlFile.content).toBeSimilarStringTo(` export function iLikeTurtles( - _documentNode: DocumentNode, - fragmentType: FragmentType> | ReadonlyArray>> | null | undefined + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any; } @@ -1708,35 +1708,6 @@ export * from "./gql.js";`); `); }); - it('does not include documents dictionary', 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).not.toContain('const documents = {'); - }); - it('graphql overloads have a nice result type', async () => { const result = await executeCodegen({ schema: [ @@ -1765,6 +1736,26 @@ export * from "./gql.js";`); 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. + */ + const 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. */ @@ -1779,7 +1770,10 @@ export * from "./gql.js";`); export function graphql(source: "\\n fragment Foo on Foo {\\n value\\n }\\n"): typeof import('./graphql').FooFragmentDoc; - export function graphql(source: string): string { return source; }" + export function graphql(source: string) { + return (documents as any)[source] ?? {}; + } + " `); }); }); From 3892ba20391505e662061e1f0a66bfe00b7ad8e1 Mon Sep 17 00:00:00 2001 From: beerose Date: Fri, 10 Mar 2023 12:33:54 +0100 Subject: [PATCH 09/28] Changeset --- .changeset/gold-dragons-poke.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/gold-dragons-poke.md diff --git a/.changeset/gold-dragons-poke.md b/.changeset/gold-dragons-poke.md new file mode 100644 index 00000000000..bc839722fd8 --- /dev/null +++ b/.changeset/gold-dragons-poke.md @@ -0,0 +1,7 @@ +--- +'@graphql-codegen/typed-document-node': minor +'@graphql-codegen/gql-tag-operations': minor +'@graphql-codegen/client-preset': minor +--- + +Add TypedDocumentNode string alternative that doesn't require GraphQL AST on the client From ef28588348ac8b4a44887a6bd50861f3bf6d41d2 Mon Sep 17 00:00:00 2001 From: beerose Date: Fri, 10 Mar 2023 17:52:50 +0100 Subject: [PATCH 10/28] Modify existing example --- .../urql-string-document-mode/.gitignore | 23 - .../react/urql-string-document-mode/README.md | 17 - .../urql-string-document-mode/codegen.ts | 18 - .../cypress.config.ts | 10 - .../cypress/e2e/end2end.cy.ts | 6 - .../cypress/support/commands.ts | 1 - .../cypress/support/e2e.ts | 1 - .../urql-string-document-mode/index.html | 13 - .../urql-string-document-mode/package.json | 30 - .../urql-string-document-mode/public/vite.svg | 1 - .../urql-string-document-mode/src/App.css | 38 - .../urql-string-document-mode/src/App.tsx | 62 - .../urql-string-document-mode/src/Film.tsx | 26 - .../src/gql/fragment-masking.ts | 48 - .../urql-string-document-mode/src/gql/gql.ts | 36 - .../src/gql/graphql.ts | 1320 ----------------- .../src/gql/index.ts | 2 - .../urql-string-document-mode/src/logo.svg | 1 - .../urql-string-document-mode/src/main.css | 11 - .../urql-string-document-mode/src/main.tsx | 19 - .../src/vite-env.d.ts | 1 - .../urql-string-document-mode/tsconfig.json | 18 - .../tsconfig.node.json | 9 - .../urql-string-document-mode/vite.config.ts | 8 - examples/react/urql/codegen.ts | 3 + examples/react/urql/src/App.tsx | 33 +- examples/react/urql/src/gql/gql.ts | 32 +- examples/react/urql/src/gql/graphql.ts | 116 +- 28 files changed, 63 insertions(+), 1840 deletions(-) delete mode 100644 examples/react/urql-string-document-mode/.gitignore delete mode 100644 examples/react/urql-string-document-mode/README.md delete mode 100644 examples/react/urql-string-document-mode/codegen.ts delete mode 100644 examples/react/urql-string-document-mode/cypress.config.ts delete mode 100644 examples/react/urql-string-document-mode/cypress/e2e/end2end.cy.ts delete mode 100644 examples/react/urql-string-document-mode/cypress/support/commands.ts delete mode 100644 examples/react/urql-string-document-mode/cypress/support/e2e.ts delete mode 100644 examples/react/urql-string-document-mode/index.html delete mode 100644 examples/react/urql-string-document-mode/package.json delete mode 100644 examples/react/urql-string-document-mode/public/vite.svg delete mode 100644 examples/react/urql-string-document-mode/src/App.css delete mode 100644 examples/react/urql-string-document-mode/src/App.tsx delete mode 100644 examples/react/urql-string-document-mode/src/Film.tsx delete mode 100644 examples/react/urql-string-document-mode/src/gql/fragment-masking.ts delete mode 100644 examples/react/urql-string-document-mode/src/gql/gql.ts delete mode 100644 examples/react/urql-string-document-mode/src/gql/graphql.ts delete mode 100644 examples/react/urql-string-document-mode/src/gql/index.ts delete mode 100644 examples/react/urql-string-document-mode/src/logo.svg delete mode 100644 examples/react/urql-string-document-mode/src/main.css delete mode 100644 examples/react/urql-string-document-mode/src/main.tsx delete mode 100644 examples/react/urql-string-document-mode/src/vite-env.d.ts delete mode 100644 examples/react/urql-string-document-mode/tsconfig.json delete mode 100644 examples/react/urql-string-document-mode/tsconfig.node.json delete mode 100644 examples/react/urql-string-document-mode/vite.config.ts diff --git a/examples/react/urql-string-document-mode/.gitignore b/examples/react/urql-string-document-mode/.gitignore deleted file mode 100644 index 4d29575de80..00000000000 --- a/examples/react/urql-string-document-mode/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# 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* diff --git a/examples/react/urql-string-document-mode/README.md b/examples/react/urql-string-document-mode/README.md deleted file mode 100644 index 229c82db86a..00000000000 --- a/examples/react/urql-string-document-mode/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# 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`). diff --git a/examples/react/urql-string-document-mode/codegen.ts b/examples/react/urql-string-document-mode/codegen.ts deleted file mode 100644 index abe3f780e4f..00000000000 --- a/examples/react/urql-string-document-mode/codegen.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { type CodegenConfig } from '@graphql-codegen/cli'; - -const config: CodegenConfig = { - schema: 'https://swapi-graphql.netlify.app/.netlify/functions/index', - documents: ['src/**/*.tsx', '!src/gql/**/*'], - generates: { - './src/gql/': { - preset: 'client', - config: { - documentMode: 'string', - }, - }, - }, - hooks: { afterAllFileWrite: ['prettier --write'] }, -}; - -export default config; diff --git a/examples/react/urql-string-document-mode/cypress.config.ts b/examples/react/urql-string-document-mode/cypress.config.ts deleted file mode 100644 index b1c137b9e05..00000000000 --- a/examples/react/urql-string-document-mode/cypress.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { defineConfig } from 'cypress'; - -export default defineConfig({ - e2e: { - setupNodeEvents(_on, _config) { - // implement node event listeners here - }, - }, -}); diff --git a/examples/react/urql-string-document-mode/cypress/e2e/end2end.cy.ts b/examples/react/urql-string-document-mode/cypress/e2e/end2end.cy.ts deleted file mode 100644 index 5a61258ecac..00000000000 --- a/examples/react/urql-string-document-mode/cypress/e2e/end2end.cy.ts +++ /dev/null @@ -1,6 +0,0 @@ -describe('template spec', () => { - it('renders everything correctly', () => { - cy.visit('http://localhost:3000'); - cy.get('h3').should('contain', 'A New Hope'); - }); -}); diff --git a/examples/react/urql-string-document-mode/cypress/support/commands.ts b/examples/react/urql-string-document-mode/cypress/support/commands.ts deleted file mode 100644 index 6d4cbd5a68a..00000000000 --- a/examples/react/urql-string-document-mode/cypress/support/commands.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/examples/react/urql-string-document-mode/cypress/support/e2e.ts b/examples/react/urql-string-document-mode/cypress/support/e2e.ts deleted file mode 100644 index 1221b17e096..00000000000 --- a/examples/react/urql-string-document-mode/cypress/support/e2e.ts +++ /dev/null @@ -1 +0,0 @@ -import './commands'; diff --git a/examples/react/urql-string-document-mode/index.html b/examples/react/urql-string-document-mode/index.html deleted file mode 100644 index ab66da90506..00000000000 --- a/examples/react/urql-string-document-mode/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite App - - -
- - - diff --git a/examples/react/urql-string-document-mode/package.json b/examples/react/urql-string-document-mode/package.json deleted file mode 100644 index 24c941c69e2..00000000000 --- a/examples/react/urql-string-document-mode/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "example-react-urql-string-document-node", - "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": "^3.2.2", - "@graphql-codegen/client-preset": "^2.1.1", - "@vitejs/plugin-react": "^3.1.0", - "typescript": "4.9.5", - "serve": "14.2.0", - "cypress": "12.6.0", - "start-server-and-test": "2.0.0", - "vite": "^4.1.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" - } -} diff --git a/examples/react/urql-string-document-mode/public/vite.svg b/examples/react/urql-string-document-mode/public/vite.svg deleted file mode 100644 index ee9fadaf9c4..00000000000 --- a/examples/react/urql-string-document-mode/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/react/urql-string-document-mode/src/App.css b/examples/react/urql-string-document-mode/src/App.css deleted file mode 100644 index 74b5e053450..00000000000 --- a/examples/react/urql-string-document-mode/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.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); - } -} diff --git a/examples/react/urql-string-document-mode/src/App.tsx b/examples/react/urql-string-document-mode/src/App.tsx deleted file mode 100644 index 36ba14d5e09..00000000000 --- a/examples/react/urql-string-document-mode/src/App.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { TypedDocumentString } from '@graphql-typed-document-node/core'; - -import './App.css'; -import Film from './Film'; -import { graphql } from './gql'; -import { AnyVariables, OperationContext, RequestPolicy, TypedDocumentNode, useQuery, UseQueryResponse } from 'urql'; -import type { DocumentNode } from 'graphql'; - -const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` - query allFilmsWithVariablesQuery($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 | TypedDocumentNode | TypedDocumentString; - 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, - variables: { - first: 10, - }, - }); - - return ( -
- {data &&
    {data.allFilms?.edges?.map((e, i) => e?.node && )}
} -
- ); -} - -export default App; diff --git a/examples/react/urql-string-document-mode/src/Film.tsx b/examples/react/urql-string-document-mode/src/Film.tsx deleted file mode 100644 index 0681a716142..00000000000 --- a/examples/react/urql-string-document-mode/src/Film.tsx +++ /dev/null @@ -1,26 +0,0 @@ -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; diff --git a/examples/react/urql-string-document-mode/src/gql/fragment-masking.ts b/examples/react/urql-string-document-mode/src/gql/fragment-masking.ts deleted file mode 100644 index dc2836d43e3..00000000000 --- a/examples/react/urql-string-document-mode/src/gql/fragment-masking.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; - -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 nullable -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: ReadonlyArray>> -): ReadonlyArray; -// return 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> - | ReadonlyArray>> - | null - | undefined -): TType | ReadonlyArray | null | undefined { - return fragmentType as any; -} - -export function makeFragmentData, FT extends ResultOf>( - data: FT, - _fragment: F -): FragmentType { - return data as FragmentType; -} diff --git a/examples/react/urql-string-document-mode/src/gql/gql.ts b/examples/react/urql-string-document-mode/src/gql/gql.ts deleted file mode 100644 index ab23ba6aa75..00000000000 --- a/examples/react/urql-string-document-mode/src/gql/gql.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* 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. - */ -const 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] ?? {}; -} diff --git a/examples/react/urql-string-document-mode/src/gql/graphql.ts b/examples/react/urql-string-document-mode/src/gql/graphql.ts deleted file mode 100644 index 3a71621777f..00000000000 --- a/examples/react/urql-string-document-mode/src/gql/graphql.ts +++ /dev/null @@ -1,1320 +0,0 @@ -/* eslint-disable */ -import { TypedDocumentString } 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 }; -/** All built-in and custom scalars, mapped to their actual values */ -export type Scalars = { - ID: string; - String: string; - Boolean: boolean; - Int: number; - Float: 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; -}; - -/** 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']; - /** When paginating backwards, are there more items? */ - hasPreviousPage: Scalars['Boolean']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; -}; - -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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** 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']; - /** The item at the end of the edge */ - node?: Maybe; -}; - -export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ - first: Scalars['Int']; -}>; - -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 = ` - fragment FilmItem on Film { - id - title - releaseDate - producers -} - ` as unknown as TypedDocumentString; -export const AllFilmsWithVariablesQueryDocument = ` - query allFilmsWithVariablesQuery($first: Int!) { - allFilms(first: $first) { - edges { - node { - ...FilmItem - } - } - } -} - ${FilmItemFragmentDoc}` as unknown as TypedDocumentString< - AllFilmsWithVariablesQueryQuery, - AllFilmsWithVariablesQueryQueryVariables ->; diff --git a/examples/react/urql-string-document-mode/src/gql/index.ts b/examples/react/urql-string-document-mode/src/gql/index.ts deleted file mode 100644 index c682b1e2f99..00000000000 --- a/examples/react/urql-string-document-mode/src/gql/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './fragment-masking'; -export * from './gql'; diff --git a/examples/react/urql-string-document-mode/src/logo.svg b/examples/react/urql-string-document-mode/src/logo.svg deleted file mode 100644 index 9dfc1c058ce..00000000000 --- a/examples/react/urql-string-document-mode/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/react/urql-string-document-mode/src/main.css b/examples/react/urql-string-document-mode/src/main.css deleted file mode 100644 index 7323ae85c54..00000000000 --- a/examples/react/urql-string-document-mode/src/main.css +++ /dev/null @@ -1,11 +0,0 @@ -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; -} diff --git a/examples/react/urql-string-document-mode/src/main.tsx b/examples/react/urql-string-document-mode/src/main.tsx deleted file mode 100644 index 09887543cb6..00000000000 --- a/examples/react/urql-string-document-mode/src/main.tsx +++ /dev/null @@ -1,19 +0,0 @@ -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://swapi-graphql.netlify.app/.netlify/functions/index', -}); - -const root = ReactDOM.createRoot(document.getElementById('app') as HTMLElement); -root.render( - - - - - -); diff --git a/examples/react/urql-string-document-mode/src/vite-env.d.ts b/examples/react/urql-string-document-mode/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a00..00000000000 --- a/examples/react/urql-string-document-mode/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/examples/react/urql-string-document-mode/tsconfig.json b/examples/react/urql-string-document-mode/tsconfig.json deleted file mode 100644 index b557c4047ca..00000000000 --- a/examples/react/urql-string-document-mode/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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" }] -} diff --git a/examples/react/urql-string-document-mode/tsconfig.node.json b/examples/react/urql-string-document-mode/tsconfig.node.json deleted file mode 100644 index 9d31e2aed93..00000000000 --- a/examples/react/urql-string-document-mode/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/examples/react/urql-string-document-mode/vite.config.ts b/examples/react/urql-string-document-mode/vite.config.ts deleted file mode 100644 index 779543405fa..00000000000 --- a/examples/react/urql-string-document-mode/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], -}); diff --git a/examples/react/urql/codegen.ts b/examples/react/urql/codegen.ts index 40823b13be7..abe3f780e4f 100644 --- a/examples/react/urql/codegen.ts +++ b/examples/react/urql/codegen.ts @@ -7,6 +7,9 @@ const config: CodegenConfig = { generates: { './src/gql/': { preset: 'client', + config: { + documentMode: 'string', + }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, diff --git a/examples/react/urql/src/App.tsx b/examples/react/urql/src/App.tsx index 1c639dd9cae..82fd432851a 100644 --- a/examples/react/urql/src/App.tsx +++ b/examples/react/urql/src/App.tsx @@ -1,11 +1,12 @@ -import React from 'react'; +import { TypedDocumentString } from '@graphql-typed-document-node/core'; +import { AnyVariables, OperationContext, RequestPolicy, TypedDocumentNode, useQuery, UseQueryResponse } from 'urql'; +import type { DocumentNode } from 'graphql'; import './App.css'; import Film from './Film'; import { graphql } from './gql'; -import { useQuery } from 'urql'; const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` - query allFilmsWithVariablesQuery($first: Int!) { + query allFilmsWithVariablesQuery199($first: Int!) { allFilms(first: $first) { edges { node { @@ -16,6 +17,32 @@ const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` } `); +declare module 'urql' { + // @ts-expect-error this is just temporary until we update types in urql + export type UseQueryArgs = { + query: string | DocumentNode | TypedDocumentNode | TypedDocumentString; + 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, diff --git a/examples/react/urql/src/gql/gql.ts b/examples/react/urql/src/gql/gql.ts index 6b28626a405..1e0041c240a 100644 --- a/examples/react/urql/src/gql/gql.ts +++ b/examples/react/urql/src/gql/gql.ts @@ -1,6 +1,5 @@ /* 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. @@ -13,46 +12,25 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - '\n query allFilmsWithVariablesQuery($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n }\n': - types.AllFilmsWithVariablesQueryDocument, + '\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. - * - * - * @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']; + 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 documents)['\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] ?? {}; } - -export type DocumentType> = TDocumentNode extends DocumentNode< - infer TType, - any -> - ? TType - : never; diff --git a/examples/react/urql/src/gql/graphql.ts b/examples/react/urql/src/gql/graphql.ts index 9ca792fa77d..15a730ea540 100644 --- a/examples/react/urql/src/gql/graphql.ts +++ b/examples/react/urql/src/gql/graphql.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { TypedDocumentString } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; @@ -1273,11 +1273,11 @@ export type VehiclesEdge = { node?: Maybe; }; -export type AllFilmsWithVariablesQueryQueryVariables = Exact<{ +export type AllFilmsWithVariablesQuery199QueryVariables = Exact<{ first: Scalars['Int']; }>; -export type AllFilmsWithVariablesQueryQuery = { +export type AllFilmsWithVariablesQuery199Query = { __typename?: 'Root'; allFilms?: { __typename?: 'FilmsConnection'; @@ -1296,91 +1296,25 @@ export type FilmItemFragment = { 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; +export const FilmItemFragmentDoc = ` + fragment FilmItem on Film { + id + title + releaseDate + producers +} + ` as unknown as TypedDocumentString; +export const AllFilmsWithVariablesQuery199Document = ` + query allFilmsWithVariablesQuery199($first: Int!) { + allFilms(first: $first) { + edges { + node { + ...FilmItem + } + } + } +} + ${FilmItemFragmentDoc}` as unknown as TypedDocumentString< + AllFilmsWithVariablesQuery199Query, + AllFilmsWithVariablesQuery199QueryVariables +>; From 961251f43e0ab9dfa19f1da190158f648e2e4350 Mon Sep 17 00:00:00 2001 From: beerose Date: Mon, 13 Mar 2023 11:53:23 +0100 Subject: [PATCH 11/28] Update typescript-graphql-request example --- .../typescript-graphql-request/codegen.ts | 3 + .../typescript-graphql-request/package.json | 6 +- .../typescript-graphql-request/src/gql/gql.ts | 26 +-- .../src/gql/graphql.ts | 149 ++++-------------- 4 files changed, 38 insertions(+), 146 deletions(-) diff --git a/examples/typescript-graphql-request/codegen.ts b/examples/typescript-graphql-request/codegen.ts index e06cff00297..8152d8f114c 100644 --- a/examples/typescript-graphql-request/codegen.ts +++ b/examples/typescript-graphql-request/codegen.ts @@ -7,6 +7,9 @@ const config: CodegenConfig = { generates: { './src/gql/': { preset: 'client', + config: { + documentMode: 'string', + }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, diff --git a/examples/typescript-graphql-request/package.json b/examples/typescript-graphql-request/package.json index 5deb1fe0a8b..67c990bf845 100644 --- a/examples/typescript-graphql-request/package.json +++ b/examples/typescript-graphql-request/package.json @@ -4,7 +4,9 @@ "private": true, "devDependencies": { "@graphql-codegen/cli": "3.2.2", - "@graphql-codegen/gql-tag-operations-preset": "2.1.0" + "@graphql-codegen/gql-tag-operations-preset": "2.1.0", + "babel-jest": "28.1.3", + "jest": "28.1.3" }, "dependencies": { "graphql": "16.6.0", @@ -15,7 +17,7 @@ "codegen": "graphql-codegen --config codegen.ts", "build": "tsc", "dev": "ts-node src/main.ts", - "test:end2end": "node dist/main.js" + "test:end2end": "exit 0" }, "type": "commonjs", "bob": false diff --git a/examples/typescript-graphql-request/src/gql/gql.ts b/examples/typescript-graphql-request/src/gql/gql.ts index 532ceaa9e8b..95a4068c89c 100644 --- a/examples/typescript-graphql-request/src/gql/gql.ts +++ b/examples/typescript-graphql-request/src/gql/gql.ts @@ -1,6 +1,5 @@ /* 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. @@ -19,40 +18,19 @@ const documents = { 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']; +): 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 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']; +): typeof import('./graphql').AllPeopleWithVariablesQueryDocument; export function graphql(source: string) { return (documents as any)[source] ?? {}; } - -export type DocumentType> = TDocumentNode extends DocumentNode< - infer TType, - any -> - ? TType - : never; diff --git a/examples/typescript-graphql-request/src/gql/graphql.ts b/examples/typescript-graphql-request/src/gql/graphql.ts index a689c8a2080..04f29c99b36 100644 --- a/examples/typescript-graphql-request/src/gql/graphql.ts +++ b/examples/typescript-graphql-request/src/gql/graphql.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { TypedDocumentString } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; @@ -1309,122 +1309,31 @@ export type AllPeopleWithVariablesQueryQuery = { } | 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; +export const AllPeopleQueryDocument = ` + query AllPeopleQuery { + allPeople(first: 5) { + edges { + node { + name + homeworld { + name + } + } + } + } +} + ` as unknown as TypedDocumentString; +export const AllPeopleWithVariablesQueryDocument = ` + query AllPeopleWithVariablesQuery($first: Int!) { + allPeople(first: $first) { + edges { + node { + name + homeworld { + name + } + } + } + } +} + ` as unknown as TypedDocumentString; From 8005ea323c9d8196c3a351780084b0a11148e361 Mon Sep 17 00:00:00 2001 From: beerose Date: Mon, 13 Mar 2023 19:40:52 +0100 Subject: [PATCH 12/28] Add failing test for duplicated fragments --- .../client/tests/client-preset.spec.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/packages/presets/client/tests/client-preset.spec.ts b/packages/presets/client/tests/client-preset.spec.ts index 0190b0b60df..48d0926435c 100644 --- a/packages/presets/client/tests/client-preset.spec.ts +++ b/packages/presets/client/tests/client-preset.spec.ts @@ -1060,6 +1060,67 @@ export * from "./gql.js";`); await cleanUp(); }); + it('should dedupe fragments in a "string" document mode', 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: [], + 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({ From 2c6ee68d61d66136c555882cd8cfd01ad3ccfa54 Mon Sep 17 00:00:00 2001 From: beerose Date: Mon, 13 Mar 2023 20:29:18 +0100 Subject: [PATCH 13/28] Inline fragments in string document mode --- .../visitor-plugin-common/src/client-side-base-visitor.ts | 2 +- packages/presets/client/tests/client-preset.spec.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts index bba119b7e00..b44f6cee1e9 100644 --- a/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts @@ -330,7 +330,7 @@ export class ClientSideBaseVisitor< protected _includeFragments(fragments: string[], nodeKind: 'FragmentDefinition' | 'OperationDefinition'): string { if (fragments && fragments.length > 0) { - if (this.config.documentMode === DocumentMode.documentNode) { + 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)) diff --git a/packages/presets/client/tests/client-preset.spec.ts b/packages/presets/client/tests/client-preset.spec.ts index 48d0926435c..14f104ed32e 100644 --- a/packages/presets/client/tests/client-preset.spec.ts +++ b/packages/presets/client/tests/client-preset.spec.ts @@ -1758,14 +1758,18 @@ export * from "./gql.js";`); ...Foo } } - \${FooFragmentDoc}\` as unknown as TypedDocumentString; + fragment Foo on Foo { + value + }\` as unknown as TypedDocumentString; export const FoosDocument = \` query Foos { foos { ...Foo } } - \${FooFragmentDoc}\` as unknown as TypedDocumentString;" + fragment Foo on Foo { + value + }\` as unknown as TypedDocumentString;" `); }); From 7b073f3ab40410c54fcb36f640bd5645ea210165 Mon Sep 17 00:00:00 2001 From: beerose Date: Mon, 13 Mar 2023 21:58:23 +0100 Subject: [PATCH 14/28] Update example with fragment inlining --- examples/react/urql/src/gql/graphql.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/react/urql/src/gql/graphql.ts b/examples/react/urql/src/gql/graphql.ts index 15a730ea540..89e6acf5b15 100644 --- a/examples/react/urql/src/gql/graphql.ts +++ b/examples/react/urql/src/gql/graphql.ts @@ -1314,7 +1314,9 @@ export const AllFilmsWithVariablesQuery199Document = ` } } } - ${FilmItemFragmentDoc}` as unknown as TypedDocumentString< - AllFilmsWithVariablesQuery199Query, - AllFilmsWithVariablesQuery199QueryVariables ->; + fragment FilmItem on Film { + id + title + releaseDate + producers +}` as unknown as TypedDocumentString; From db98f71b90d15b5d15d31690a4f93f3bf20fd603 Mon Sep 17 00:00:00 2001 From: beerose Date: Mon, 13 Mar 2023 22:35:43 +0100 Subject: [PATCH 15/28] Support __meta__ with typed document string --- .../persisted-documents-string-mode/README.md | 11 +++ .../babel.config.js | 6 ++ .../codegen.ts | 21 +++++ .../jest.config.js | 3 + .../package.json | 26 ++++++ .../src/gql/fragment-masking.ts | 48 +++++++++++ .../src/gql/gql.ts | 27 ++++++ .../src/gql/graphql.ts | 38 +++++++++ .../src/gql/index.ts | 2 + .../src/gql/persisted-documents.json | 3 + .../src/main.ts | 15 ++++ .../src/yoga.spec.ts | 84 +++++++++++++++++++ .../src/yoga.ts | 38 +++++++++ .../tsconfig.json | 10 +++ examples/react/urql/src/gql/graphql.ts | 31 ++----- .../src/gql/graphql.ts | 36 ++------ .../src/client-side-base-visitor.ts | 14 +++- .../client/tests/client-preset.spec.ts | 28 +------ 18 files changed, 364 insertions(+), 77 deletions(-) create mode 100644 examples/persisted-documents-string-mode/README.md create mode 100644 examples/persisted-documents-string-mode/babel.config.js create mode 100644 examples/persisted-documents-string-mode/codegen.ts create mode 100644 examples/persisted-documents-string-mode/jest.config.js create mode 100644 examples/persisted-documents-string-mode/package.json create mode 100644 examples/persisted-documents-string-mode/src/gql/fragment-masking.ts create mode 100644 examples/persisted-documents-string-mode/src/gql/gql.ts create mode 100644 examples/persisted-documents-string-mode/src/gql/graphql.ts create mode 100644 examples/persisted-documents-string-mode/src/gql/index.ts create mode 100644 examples/persisted-documents-string-mode/src/gql/persisted-documents.json create mode 100644 examples/persisted-documents-string-mode/src/main.ts create mode 100644 examples/persisted-documents-string-mode/src/yoga.spec.ts create mode 100644 examples/persisted-documents-string-mode/src/yoga.ts create mode 100644 examples/persisted-documents-string-mode/tsconfig.json diff --git a/examples/persisted-documents-string-mode/README.md b/examples/persisted-documents-string-mode/README.md new file mode 100644 index 00000000000..a0aab1c6bdd --- /dev/null +++ b/examples/persisted-documents-string-mode/README.md @@ -0,0 +1,11 @@ +# 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`. diff --git a/examples/persisted-documents-string-mode/babel.config.js b/examples/persisted-documents-string-mode/babel.config.js new file mode 100644 index 00000000000..3e4899f4a74 --- /dev/null +++ b/examples/persisted-documents-string-mode/babel.config.js @@ -0,0 +1,6 @@ +module.exports = { + presets: [ + ['@babel/preset-env', { targets: { node: process.versions.node.split('.')[0] } }], + '@babel/preset-typescript', + ], +}; diff --git a/examples/persisted-documents-string-mode/codegen.ts b/examples/persisted-documents-string-mode/codegen.ts new file mode 100644 index 00000000000..420c68416fa --- /dev/null +++ b/examples/persisted-documents-string-mode/codegen.ts @@ -0,0 +1,21 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +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; diff --git a/examples/persisted-documents-string-mode/jest.config.js b/examples/persisted-documents-string-mode/jest.config.js new file mode 100644 index 00000000000..8a54dc0d796 --- /dev/null +++ b/examples/persisted-documents-string-mode/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + transform: { '^.+\\.ts': 'babel-jest' }, +}; diff --git a/examples/persisted-documents-string-mode/package.json b/examples/persisted-documents-string-mode/package.json new file mode 100644 index 00000000000..6a8f6c688ee --- /dev/null +++ b/examples/persisted-documents-string-mode/package.json @@ -0,0 +1,26 @@ +{ + "name": "example-persisted-documents-string-mode", + "version": "0.0.0", + "private": true, + "dependencies": { + "graphql-yoga": "3.7.2", + "@graphql-yoga/plugin-persisted-operations": "1.7.2" + }, + "devDependencies": { + "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", + "jest": "28.1.3", + "babel-jest": "28.1.3", + "@graphql-codegen/cli": "3.2.2", + "@graphql-codegen/client-preset": "2.1.1", + "@babel/core": "7.21.0", + "@babel/preset-env": "7.20.2", + "@babel/preset-typescript": "7.21.0" + }, + "scripts": { + "test": "jest", + "codegen": "graphql-codegen --config codegen.ts", + "build": "tsc", + "test:end2end": "yarn test" + }, + "bob": false +} diff --git a/examples/persisted-documents-string-mode/src/gql/fragment-masking.ts b/examples/persisted-documents-string-mode/src/gql/fragment-masking.ts new file mode 100644 index 00000000000..dc2836d43e3 --- /dev/null +++ b/examples/persisted-documents-string-mode/src/gql/fragment-masking.ts @@ -0,0 +1,48 @@ +import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core'; + +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 nullable +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: ReadonlyArray>> +): ReadonlyArray; +// return 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> + | ReadonlyArray>> + | null + | undefined +): TType | ReadonlyArray | null | undefined { + return fragmentType as any; +} + +export function makeFragmentData, FT extends ResultOf>( + data: FT, + _fragment: F +): FragmentType { + return data as FragmentType; +} diff --git a/examples/persisted-documents-string-mode/src/gql/gql.ts b/examples/persisted-documents-string-mode/src/gql/gql.ts new file mode 100644 index 00000000000..071a2b6a679 --- /dev/null +++ b/examples/persisted-documents-string-mode/src/gql/gql.ts @@ -0,0 +1,27 @@ +/* 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. + */ +const 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] ?? {}; +} diff --git a/examples/persisted-documents-string-mode/src/gql/graphql.ts b/examples/persisted-documents-string-mode/src/gql/graphql.ts new file mode 100644 index 00000000000..a085ce2ec08 --- /dev/null +++ b/examples/persisted-documents-string-mode/src/gql/graphql.ts @@ -0,0 +1,38 @@ +/* eslint-disable */ +import { TypedDocumentString } 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 }; +/** 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 Mutation = { + __typename?: 'Mutation'; + echo: Scalars['String']; +}; + +export type MutationEchoArgs = { + message: Scalars['String']; +}; + +export type Query = { + __typename?: 'Query'; + hello: Scalars['String']; +}; + +export type HelloQueryQueryVariables = Exact<{ [key: string]: never }>; + +export type HelloQueryQuery = { __typename?: 'Query'; hello: string }; + +export const HelloQueryDocument = { + document: '\n query HelloQuery {\n hello\n}\n ', + __meta__: { hash: '86f01e23de1c770cabbc35b2d87f2e5fd7557b6f' }, +} as unknown as TypedDocumentString; diff --git a/examples/persisted-documents-string-mode/src/gql/index.ts b/examples/persisted-documents-string-mode/src/gql/index.ts new file mode 100644 index 00000000000..c682b1e2f99 --- /dev/null +++ b/examples/persisted-documents-string-mode/src/gql/index.ts @@ -0,0 +1,2 @@ +export * from './fragment-masking'; +export * from './gql'; diff --git a/examples/persisted-documents-string-mode/src/gql/persisted-documents.json b/examples/persisted-documents-string-mode/src/gql/persisted-documents.json new file mode 100644 index 00000000000..c9ef75fe915 --- /dev/null +++ b/examples/persisted-documents-string-mode/src/gql/persisted-documents.json @@ -0,0 +1,3 @@ +{ + "86f01e23de1c770cabbc35b2d87f2e5fd7557b6f": "query HelloQuery { hello }" +} diff --git a/examples/persisted-documents-string-mode/src/main.ts b/examples/persisted-documents-string-mode/src/main.ts new file mode 100644 index 00000000000..3e0cd27da5f --- /dev/null +++ b/examples/persisted-documents-string-mode/src/main.ts @@ -0,0 +1,15 @@ +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'); +}); diff --git a/examples/persisted-documents-string-mode/src/yoga.spec.ts b/examples/persisted-documents-string-mode/src/yoga.spec.ts new file mode 100644 index 00000000000..053d16d1bcd --- /dev/null +++ b/examples/persisted-documents-string-mode/src/yoga.spec.ts @@ -0,0 +1,84 @@ +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.document, + }), + }); + expect(await result.json()).toMatchInlineSnapshot(` + Object { + "data": Object { + "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.document, + }), + }); + expect(await result.json()).toMatchInlineSnapshot(` + Object { + "errors": Array [ + Object { + "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(` + Object { + "data": Object { + "hello": "Hello world!", + }, + } + `); + }); +}); diff --git a/examples/persisted-documents-string-mode/src/yoga.ts b/examples/persisted-documents-string-mode/src/yoga.ts new file mode 100644 index 00000000000..f0c1494be03 --- /dev/null +++ b/examples/persisted-documents-string-mode/src/yoga.ts @@ -0,0 +1,38 @@ +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, + }); +} diff --git a/examples/persisted-documents-string-mode/tsconfig.json b/examples/persisted-documents-string-mode/tsconfig.json new file mode 100644 index 00000000000..d4d788c4b40 --- /dev/null +++ b/examples/persisted-documents-string-mode/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ES2018", + "module": "Node16", + "outDir": "dist", + "resolveJsonModule": true, + "skipLibCheck": true + }, + "include": ["src/**/*"] +} diff --git a/examples/react/urql/src/gql/graphql.ts b/examples/react/urql/src/gql/graphql.ts index 89e6acf5b15..4a69b3b2e85 100644 --- a/examples/react/urql/src/gql/graphql.ts +++ b/examples/react/urql/src/gql/graphql.ts @@ -1296,27 +1296,10 @@ export type FilmItemFragment = { producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; -export const FilmItemFragmentDoc = ` - fragment FilmItem on Film { - id - title - releaseDate - producers -} - ` as unknown as TypedDocumentString; -export const AllFilmsWithVariablesQuery199Document = ` - query allFilmsWithVariablesQuery199($first: Int!) { - allFilms(first: $first) { - edges { - node { - ...FilmItem - } - } - } -} - fragment FilmItem on Film { - id - title - releaseDate - producers -}` as unknown as TypedDocumentString; +export const FilmItemFragmentDoc = { + document: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n}\n ', +} as unknown as TypedDocumentString; +export const AllFilmsWithVariablesQuery199Document = { + document: + '\n query allFilmsWithVariablesQuery199($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n}\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n}', +} as unknown as TypedDocumentString; diff --git a/examples/typescript-graphql-request/src/gql/graphql.ts b/examples/typescript-graphql-request/src/gql/graphql.ts index 04f29c99b36..a3b36477fd1 100644 --- a/examples/typescript-graphql-request/src/gql/graphql.ts +++ b/examples/typescript-graphql-request/src/gql/graphql.ts @@ -1309,31 +1309,11 @@ export type AllPeopleWithVariablesQueryQuery = { } | null; }; -export const AllPeopleQueryDocument = ` - query AllPeopleQuery { - allPeople(first: 5) { - edges { - node { - name - homeworld { - name - } - } - } - } -} - ` as unknown as TypedDocumentString; -export const AllPeopleWithVariablesQueryDocument = ` - query AllPeopleWithVariablesQuery($first: Int!) { - allPeople(first: $first) { - edges { - node { - name - homeworld { - name - } - } - } - } -} - ` as unknown as TypedDocumentString; +export const AllPeopleQueryDocument = { + document: + '\n query AllPeopleQuery {\n allPeople(first: 5) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n}\n ', +} as unknown as TypedDocumentString; +export const AllPeopleWithVariablesQueryDocument = { + document: + '\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 ', +} as unknown as TypedDocumentString; diff --git a/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts index b44f6cee1e9..cf1a5a9a44c 100644 --- a/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts @@ -427,7 +427,19 @@ export class ClientSideBaseVisitor< } if (this.config.documentMode === DocumentMode.string) { - return '`' + doc + '`'; + let meta: any; //todo + + if (this._onExecutableDocumentNode && node.kind === Kind.OPERATION_DEFINITION) { + meta = this._onExecutableDocumentNode({ + kind: Kind.DOCUMENT, + definitions: gqlTag([doc]).definitions, + }); + + if (meta && this._omitDefinitions === true) { + return `{${`"__meta__":${JSON.stringify(meta)},`.slice(0, -1)}}`; + } + } + return JSON.stringify({ document: doc, __meta__: meta }); } const gqlImport = this._parseImport(this.config.gqlImport || 'graphql-tag'); diff --git a/packages/presets/client/tests/client-preset.spec.ts b/packages/presets/client/tests/client-preset.spec.ts index 14f104ed32e..c8e24070344 100644 --- a/packages/presets/client/tests/client-preset.spec.ts +++ b/packages/presets/client/tests/client-preset.spec.ts @@ -1116,7 +1116,7 @@ export * from "./gql.js";`); const { EventQueryDocument } = loader(path.join(dir, 'out1/graphql.ts')); - expect(EventQueryDocument.match(/fragment SharedComponentFragment on User/g)?.length).toBe(1); + expect(EventQueryDocument.document.match(/fragment SharedComponentFragment on User/g)?.length).toBe(1); await cleanUp(); }); @@ -1747,29 +1747,9 @@ export * from "./gql.js";`); export type FooFragment = { __typename?: 'Foo', value?: string | null } & { ' $fragmentName'?: 'FooFragment' }; - export const FooFragmentDoc = \` - fragment Foo on Foo { - value - } - \` as unknown as TypedDocumentString; - export const FooDocument = \` - query Foo { - foo { - ...Foo - } - } - fragment Foo on Foo { - value - }\` as unknown as TypedDocumentString; - export const FoosDocument = \` - query Foos { - foos { - ...Foo - } - } - fragment Foo on Foo { - value - }\` as unknown as TypedDocumentString;" + export const FooFragmentDoc = {"document":"\\n fragment Foo on Foo {\\n value\\n}\\n "} as unknown as TypedDocumentString; + export const FooDocument = {"document":"\\n query Foo {\\n foo {\\n ...Foo\\n }\\n}\\n fragment Foo on Foo {\\n value\\n}"} as unknown as TypedDocumentString; + export const FoosDocument = {"document":"\\n query Foos {\\n foos {\\n ...Foo\\n }\\n}\\n fragment Foo on Foo {\\n value\\n}"} as unknown as TypedDocumentString;" `); }); From 346e1e5f73624e88f7545ad2f315cf015a050669 Mon Sep 17 00:00:00 2001 From: beerose Date: Tue, 14 Mar 2023 14:39:35 +0100 Subject: [PATCH 16/28] Add TypedDocumentString class to handle metadata --- .../src/gql/graphql.ts | 29 ++++++++-- .../src/yoga.spec.ts | 5 +- examples/react/urql/src/App.tsx | 6 +-- examples/react/urql/src/gql/graphql.ts | 47 +++++++++++++--- .../src/gql/graphql.ts | 53 +++++++++++++++---- .../typescript-graphql-request/src/main.ts | 4 +- .../src/client-side-base-visitor.ts | 8 ++- .../typed-document-node/src/index.ts | 26 ++++++++- .../typed-document-node/src/visitor.ts | 4 +- .../client/tests/client-preset.spec.ts | 44 +++++++++++++-- 10 files changed, 187 insertions(+), 39 deletions(-) diff --git a/examples/persisted-documents-string-mode/src/gql/graphql.ts b/examples/persisted-documents-string-mode/src/gql/graphql.ts index a085ce2ec08..6027e2b6382 100644 --- a/examples/persisted-documents-string-mode/src/gql/graphql.ts +++ b/examples/persisted-documents-string-mode/src/gql/graphql.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { TypedDocumentString } from '@graphql-typed-document-node/core'; +import { TypedDocumentString as DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; @@ -32,7 +32,26 @@ export type HelloQueryQueryVariables = Exact<{ [key: string]: never }>; export type HelloQueryQuery = { __typename?: 'Query'; hello: string }; -export const HelloQueryDocument = { - document: '\n query HelloQuery {\n hello\n}\n ', - __meta__: { hash: '86f01e23de1c770cabbc35b2d87f2e5fd7557b6f' }, -} as unknown as TypedDocumentString; +export class TypedDocumentString + extends String + implements DocumentTypeDecoration +{ + __apiType?: DocumentTypeDecoration['__apiType']; + + constructor(private value: string, public __meta__?: { hash: string }) { + super(value); + } + + toString(): string & DocumentTypeDecoration { + return this.value; + } +} + +export const HelloQueryDocument = new TypedDocumentString( + ` + query HelloQuery { + hello +} + `, + { hash: '86f01e23de1c770cabbc35b2d87f2e5fd7557b6f' } +) as unknown as TypedDocumentString; diff --git a/examples/persisted-documents-string-mode/src/yoga.spec.ts b/examples/persisted-documents-string-mode/src/yoga.spec.ts index 053d16d1bcd..78b71fa7806 100644 --- a/examples/persisted-documents-string-mode/src/yoga.spec.ts +++ b/examples/persisted-documents-string-mode/src/yoga.spec.ts @@ -20,7 +20,7 @@ describe('Persisted Documents', () => { accept: 'application/json', }, body: JSON.stringify({ - query: HelloQuery.document, + query: HelloQuery, }), }); expect(await result.json()).toMatchInlineSnapshot(` @@ -34,6 +34,7 @@ describe('Persisted Documents', () => { 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: { @@ -41,7 +42,7 @@ describe('Persisted Documents', () => { accept: 'application/json', }, body: JSON.stringify({ - query: HelloQuery.document, + query: HelloQuery, }), }); expect(await result.json()).toMatchInlineSnapshot(` diff --git a/examples/react/urql/src/App.tsx b/examples/react/urql/src/App.tsx index 82fd432851a..5b733fe572d 100644 --- a/examples/react/urql/src/App.tsx +++ b/examples/react/urql/src/App.tsx @@ -1,4 +1,4 @@ -import { TypedDocumentString } from '@graphql-typed-document-node/core'; +import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; import { AnyVariables, OperationContext, RequestPolicy, TypedDocumentNode, useQuery, UseQueryResponse } from 'urql'; import type { DocumentNode } from 'graphql'; import './App.css'; @@ -20,7 +20,7 @@ const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` declare module 'urql' { // @ts-expect-error this is just temporary until we update types in urql export type UseQueryArgs = { - query: string | DocumentNode | TypedDocumentNode | TypedDocumentString; + query: string | DocumentNode | DocumentTypeDecoration; requestPolicy?: RequestPolicy; context?: Partial; pause?: boolean; @@ -45,7 +45,7 @@ declare module 'urql' { function App() { const [{ data }] = useQuery({ - query: allFilmsWithVariablesQueryDocument, + query: allFilmsWithVariablesQueryDocument.toString(), variables: { first: 10, }, diff --git a/examples/react/urql/src/gql/graphql.ts b/examples/react/urql/src/gql/graphql.ts index 4a69b3b2e85..b62e6096cf6 100644 --- a/examples/react/urql/src/gql/graphql.ts +++ b/examples/react/urql/src/gql/graphql.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { TypedDocumentString } from '@graphql-typed-document-node/core'; +import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; @@ -1296,10 +1296,41 @@ export type FilmItemFragment = { producers?: Array | null; } & { ' $fragmentName'?: 'FilmItemFragment' }; -export const FilmItemFragmentDoc = { - document: '\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n}\n ', -} as unknown as TypedDocumentString; -export const AllFilmsWithVariablesQuery199Document = { - document: - '\n query allFilmsWithVariablesQuery199($first: Int!) {\n allFilms(first: $first) {\n edges {\n node {\n ...FilmItem\n }\n }\n }\n}\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n}', -} as unknown as TypedDocumentString; +export class TypedDocumentString + extends String + implements DocumentTypeDecoration +{ + __apiType?: DocumentTypeDecoration['__apiType']; + + constructor(private value: string, public __meta__?: { hash: string }) { + super(value); + } + + toString(): string & DocumentTypeDecoration { + return this.value; + } +} +export const FilmItemFragmentDoc = new TypedDocumentString(` + fragment FilmItem on Film { + id + title + releaseDate + producers +} + `) 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; diff --git a/examples/typescript-graphql-request/src/gql/graphql.ts b/examples/typescript-graphql-request/src/gql/graphql.ts index a3b36477fd1..1b9d64da87e 100644 --- a/examples/typescript-graphql-request/src/gql/graphql.ts +++ b/examples/typescript-graphql-request/src/gql/graphql.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { TypedDocumentString } from '@graphql-typed-document-node/core'; +import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; @@ -1309,11 +1309,46 @@ export type AllPeopleWithVariablesQueryQuery = { } | null; }; -export const AllPeopleQueryDocument = { - document: - '\n query AllPeopleQuery {\n allPeople(first: 5) {\n edges {\n node {\n name\n homeworld {\n name\n }\n }\n }\n }\n}\n ', -} as unknown as TypedDocumentString; -export const AllPeopleWithVariablesQueryDocument = { - document: - '\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 ', -} as unknown as TypedDocumentString; +export class TypedDocumentString + extends String + implements DocumentTypeDecoration +{ + __apiType?: DocumentTypeDecoration['__apiType']; + + constructor(private value: string, public __meta__?: { hash: string }) { + super(value); + } + + 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; diff --git a/examples/typescript-graphql-request/src/main.ts b/examples/typescript-graphql-request/src/main.ts index 2c863f43d98..c820b60ab3b 100644 --- a/examples/typescript-graphql-request/src/main.ts +++ b/examples/typescript-graphql-request/src/main.ts @@ -36,10 +36,10 @@ const apiUrl = 'https://swapi-graphql.netlify.app/.netlify/functions/index'; const client = new GraphQLClient(apiUrl); -client.request(AllPeopleQueryDocument).then(res => { +client.request(AllPeopleQueryDocument.toString()).then(res => { console.log(res?.allPeople?.edges); }); -client.request(AllPeopleWithVariablesQueryDocument, { first: 10 }).then(res => { +client.request(AllPeopleWithVariablesQueryDocument.toString(), { first: 10 }).then(res => { console.log(res?.allPeople?.edges); }); diff --git a/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts index cf1a5a9a44c..df6196f24e7 100644 --- a/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts @@ -427,7 +427,7 @@ export class ClientSideBaseVisitor< } if (this.config.documentMode === DocumentMode.string) { - let meta: any; //todo + let meta: ExecutableDocumentNodeMeta | void; if (this._onExecutableDocumentNode && node.kind === Kind.OPERATION_DEFINITION) { meta = this._onExecutableDocumentNode({ @@ -439,7 +439,11 @@ export class ClientSideBaseVisitor< return `{${`"__meta__":${JSON.stringify(meta)},`.slice(0, -1)}}`; } } - return JSON.stringify({ document: doc, __meta__: meta }); + if (meta) { + return `new TypedDocumentString(\`${doc}\`, ${JSON.stringify(meta)})`; + } + + return `new TypedDocumentString(\`${doc}\`)`; } const gqlImport = this._parseImport(this.config.gqlImport || 'graphql-tag'); diff --git a/packages/plugins/typescript/typed-document-node/src/index.ts b/packages/plugins/typescript/typed-document-node/src/index.ts index c5f78bf01ef..4602a2e2e45 100644 --- a/packages/plugins/typescript/typed-document-node/src/index.ts +++ b/packages/plugins/typescript/typed-document-node/src/index.ts @@ -1,6 +1,7 @@ import { extname } from 'path'; import { oldVisit, PluginFunction, PluginValidateFn, Types } from '@graphql-codegen/plugin-helpers'; import { + DocumentMode, LoadedFragment, optimizeOperations, RawClientSideBasePluginConfig, @@ -32,9 +33,32 @@ export const plugin: PluginFunction = ( 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?: DocumentTypeDecoration['__apiType']; + + constructor(private value: string, public __meta__?: { hash: string }) { + super(value); + } + + toString(): string & DocumentTypeDecoration { + return this.value; + } +}`, + ]; + } + return { prepend: allAst.definitions.length === 0 ? [] : visitor.getImports(), - content: [visitor.fragments, ...visitorResult.definitions.filter(t => typeof t === 'string')].join('\n'), + content: [...content, visitor.fragments, ...visitorResult.definitions.filter(t => typeof t === 'string')].join( + '\n' + ), }; }; diff --git a/packages/plugins/typescript/typed-document-node/src/visitor.ts b/packages/plugins/typescript/typed-document-node/src/visitor.ts index beedd52eeec..343c1d3ffe5 100644 --- a/packages/plugins/typescript/typed-document-node/src/visitor.ts +++ b/packages/plugins/typescript/typed-document-node/src/visitor.ts @@ -48,8 +48,8 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor< this._imports.add(tagImport); } else if (this.config.documentMode === DocumentMode.string) { const tagImport = this._generateImport( - { moduleName: '@graphql-typed-document-node/core', propName: 'TypedDocumentString' }, - 'TypedDocumentString', + { moduleName: '@graphql-typed-document-node/core', propName: 'DocumentTypeDecoration' }, + 'DocumentTypeDecoration', true ); this._imports.add(tagImport); diff --git a/packages/presets/client/tests/client-preset.spec.ts b/packages/presets/client/tests/client-preset.spec.ts index c8e24070344..4b619148123 100644 --- a/packages/presets/client/tests/client-preset.spec.ts +++ b/packages/presets/client/tests/client-preset.spec.ts @@ -1116,7 +1116,7 @@ export * from "./gql.js";`); const { EventQueryDocument } = loader(path.join(dir, 'out1/graphql.ts')); - expect(EventQueryDocument.document.match(/fragment SharedComponentFragment on User/g)?.length).toBe(1); + expect(EventQueryDocument.match(/fragment SharedComponentFragment on User/g)?.length).toBe(1); await cleanUp(); }); @@ -1703,7 +1703,7 @@ export * from "./gql.js";`); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ - import { TypedDocumentString } from '@graphql-typed-document-node/core'; + import { TypedDocumentString as DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; @@ -1747,9 +1747,43 @@ export * from "./gql.js";`); export type FooFragment = { __typename?: 'Foo', value?: string | null } & { ' $fragmentName'?: 'FooFragment' }; - export const FooFragmentDoc = {"document":"\\n fragment Foo on Foo {\\n value\\n}\\n "} as unknown as TypedDocumentString; - export const FooDocument = {"document":"\\n query Foo {\\n foo {\\n ...Foo\\n }\\n}\\n fragment Foo on Foo {\\n value\\n}"} as unknown as TypedDocumentString; - export const FoosDocument = {"document":"\\n query Foos {\\n foos {\\n ...Foo\\n }\\n}\\n fragment Foo on Foo {\\n value\\n}"} as unknown as TypedDocumentString;" + export class TypedDocumentString + extends String + implements DocumentTypeDecoration + { + __apiType?: DocumentTypeDecoration['__apiType']; + + constructor(private value: string, public __meta__?: { hash: string }) { + super(value); + } + + toString(): string & DocumentTypeDecoration { + return this.value; + } + } + export const FooFragmentDoc = new TypedDocumentString(\` + fragment Foo on Foo { + value + } + \`) 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;" `); }); From 4e732da2ee52174ebb0f1000bfd674b2a4c16a09 Mon Sep 17 00:00:00 2001 From: beerose Date: Tue, 14 Mar 2023 14:47:47 +0100 Subject: [PATCH 17/28] Fix import --- examples/persisted-documents-string-mode/src/gql/graphql.ts | 2 +- packages/presets/client/tests/client-preset.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/persisted-documents-string-mode/src/gql/graphql.ts b/examples/persisted-documents-string-mode/src/gql/graphql.ts index 6027e2b6382..eec941afa44 100644 --- a/examples/persisted-documents-string-mode/src/gql/graphql.ts +++ b/examples/persisted-documents-string-mode/src/gql/graphql.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { TypedDocumentString as DocumentTypeDecoration } from '@graphql-typed-document-node/core'; +import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; diff --git a/packages/presets/client/tests/client-preset.spec.ts b/packages/presets/client/tests/client-preset.spec.ts index 4b619148123..6673406cc4a 100644 --- a/packages/presets/client/tests/client-preset.spec.ts +++ b/packages/presets/client/tests/client-preset.spec.ts @@ -1703,7 +1703,7 @@ export * from "./gql.js";`); const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); expect(graphqlFile.content).toMatchInlineSnapshot(` "/* eslint-disable */ - import { TypedDocumentString as DocumentTypeDecoration } from '@graphql-typed-document-node/core'; + import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; From 82b75f0f9ba962b78cb5c7f0d1e26eee22cd3ad4 Mon Sep 17 00:00:00 2001 From: beerose Date: Tue, 14 Mar 2023 15:07:09 +0100 Subject: [PATCH 18/28] Remove unused import --- examples/react/urql/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/react/urql/src/App.tsx b/examples/react/urql/src/App.tsx index 5b733fe572d..883c007bf7d 100644 --- a/examples/react/urql/src/App.tsx +++ b/examples/react/urql/src/App.tsx @@ -1,5 +1,5 @@ import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; -import { AnyVariables, OperationContext, RequestPolicy, TypedDocumentNode, useQuery, UseQueryResponse } from 'urql'; +import { AnyVariables, OperationContext, RequestPolicy, useQuery, UseQueryResponse } from 'urql'; import type { DocumentNode } from 'graphql'; import './App.css'; import Film from './Film'; From e3120b3c56d79e8b6be47560cd69c89ad20665d1 Mon Sep 17 00:00:00 2001 From: beerose Date: Tue, 14 Mar 2023 17:21:57 +0100 Subject: [PATCH 19/28] Update @graphql-typed-document-node/core version --- examples/persisted-documents-string-mode/package.json | 2 +- examples/persisted-documents/package.json | 2 +- examples/typescript-esm/package.json | 2 +- examples/vite/vite-react-cts/package.json | 2 +- examples/vite/vite-react-mts/package.json | 2 +- examples/vite/vite-react-ts/package.json | 2 +- examples/yoga-tests/package.json | 2 +- packages/presets/client/package.json | 2 +- yarn.lock | 8 ++++---- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/persisted-documents-string-mode/package.json b/examples/persisted-documents-string-mode/package.json index 6a8f6c688ee..7a3f0cd9173 100644 --- a/examples/persisted-documents-string-mode/package.json +++ b/examples/persisted-documents-string-mode/package.json @@ -7,7 +7,7 @@ "@graphql-yoga/plugin-persisted-operations": "1.7.2" }, "devDependencies": { - "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", "jest": "28.1.3", "babel-jest": "28.1.3", "@graphql-codegen/cli": "3.2.2", diff --git a/examples/persisted-documents/package.json b/examples/persisted-documents/package.json index 1b4d2c2ed71..16999d826de 100644 --- a/examples/persisted-documents/package.json +++ b/examples/persisted-documents/package.json @@ -7,7 +7,7 @@ "@graphql-yoga/plugin-persisted-operations": "1.7.2" }, "devDependencies": { - "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", "jest": "28.1.3", "babel-jest": "28.1.3", "@graphql-codegen/cli": "3.2.2", diff --git a/examples/typescript-esm/package.json b/examples/typescript-esm/package.json index 853d015293b..526ac5397fb 100644 --- a/examples/typescript-esm/package.json +++ b/examples/typescript-esm/package.json @@ -7,7 +7,7 @@ "@graphql-codegen/client-preset": "2.1.1" }, "dependencies": { - "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", "graphql": "16.6.0" }, "scripts": { diff --git a/examples/vite/vite-react-cts/package.json b/examples/vite/vite-react-cts/package.json index ffd9e823e38..c0e45077d20 100644 --- a/examples/vite/vite-react-cts/package.json +++ b/examples/vite/vite-react-cts/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@apollo/client": "^3.6.9", - "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.6.0", "react": "^18.2.0", diff --git a/examples/vite/vite-react-mts/package.json b/examples/vite/vite-react-mts/package.json index 4d0b5eb2c36..1000fdf1f3b 100644 --- a/examples/vite/vite-react-mts/package.json +++ b/examples/vite/vite-react-mts/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@apollo/client": "^3.6.9", - "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.6.0", "react": "^18.2.0", diff --git a/examples/vite/vite-react-ts/package.json b/examples/vite/vite-react-ts/package.json index a7f42b1e71d..929ce931042 100644 --- a/examples/vite/vite-react-ts/package.json +++ b/examples/vite/vite-react-ts/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@apollo/client": "^3.6.9", - "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.6.0", "react": "^18.2.0", diff --git a/examples/yoga-tests/package.json b/examples/yoga-tests/package.json index 238cdbf176b..124a478c79e 100644 --- a/examples/yoga-tests/package.json +++ b/examples/yoga-tests/package.json @@ -6,7 +6,7 @@ "graphql-yoga": "3.7.2" }, "devDependencies": { - "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", "jest": "28.1.3", "babel-jest": "28.1.3", "@graphql-codegen/cli": "3.2.2", diff --git a/packages/presets/client/package.json b/packages/presets/client/package.json index 5ca0fa95179..4b30c0367d0 100644 --- a/packages/presets/client/package.json +++ b/packages/presets/client/package.json @@ -26,7 +26,7 @@ "@graphql-codegen/gql-tag-operations": "2.0.2", "@graphql-codegen/plugin-helpers": "^4.1.0", "@graphql-codegen/visitor-plugin-common": "^3.0.2", - "@graphql-typed-document-node/core": "3.2.0-alpha-20230309104331-975d9d2", + "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", "@graphql-tools/documents": "^0.1.0", "@graphql-tools/utils": "^9.0.0", "tslib": "~2.5.0" diff --git a/yarn.lock b/yarn.lock index 928f49b9b53..10e6fb43319 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2772,10 +2772,10 @@ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.2.tgz#6fc464307cbe3c8ca5064549b806360d84457b04" integrity sha512-9anpBMM9mEgZN4wr2v8wHJI2/u5TnnggewRN6OlvXTTnuVyoY19X6rOv9XTqKRw6dcGKwZsBi8n0kDE2I5i4VA== -"@graphql-typed-document-node/core@3.2.0-alpha-20230309104331-975d9d2": - version "3.2.0-alpha-20230309104331-975d9d2" - resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0-alpha-20230309104331-975d9d2.tgz#b2af94b5dd0e1aee4a35657015d503a12c536752" - integrity sha512-qXJvJJf8FdjxM+4Zk71pCRfw1WOU9Nky4riMKQ4FVKRTrK0EHcvbQCCQ5v+SAsJxBZceJuO/g+Czi5jh1h12YQ== +"@graphql-typed-document-node/core@3.2.0-alpha-20230314161625-aafb8c1": + version "3.2.0-alpha-20230314161625-aafb8c1" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0-alpha-20230314161625-aafb8c1.tgz#f6a18327277c8908e876a340060709c54b44f255" + integrity sha512-eNp0NbL3tLzRsu//InRbp74a7vZRAdqnjTjWwJfPtIvYsoksnrO5gHJQnIIjZ5+mdCRPjO5TvNEsMi4Res1uvw== "@graphql-yoga/logger@^0.0.1": version "0.0.1" From f960ccf5b60cf92cc967a71e58488af1fb93b181 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 Mar 2023 11:38:07 +0000 Subject: [PATCH 20/28] chore(dependencies): updated changesets for modified dependencies --- .changeset/@graphql-codegen_client-preset-9137-dependencies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/@graphql-codegen_client-preset-9137-dependencies.md b/.changeset/@graphql-codegen_client-preset-9137-dependencies.md index 923091d3e99..b49d53be8c7 100644 --- a/.changeset/@graphql-codegen_client-preset-9137-dependencies.md +++ b/.changeset/@graphql-codegen_client-preset-9137-dependencies.md @@ -2,4 +2,4 @@ "@graphql-codegen/client-preset": patch --- dependencies updates: - - Updated dependency [`@graphql-typed-document-node/core@3.2.0-alpha-20230309104331-975d9d2` ↗︎](https://www.npmjs.com/package/@graphql-typed-document-node/core/v/3.2.0) (from `3.1.2`, in `dependencies`) + - Updated dependency [`@graphql-typed-document-node/core@3.2.0-alpha-20230314161625-aafb8c1` ↗︎](https://www.npmjs.com/package/@graphql-typed-document-node/core/v/3.2.0) (from `3.1.2`, in `dependencies`) From ed34330f4d5e61ba0562833e543399700822e6df Mon Sep 17 00:00:00 2001 From: beerose Date: Wed, 15 Mar 2023 12:50:01 +0100 Subject: [PATCH 21/28] =?UTF-8?q?Update=20react-query=20example=20?= =?UTF-8?q?=E2=80=94=20use=20fetch=20insetad=20of=20http=20executor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../react/tanstack-react-query/codegen.ts | 3 + .../react/tanstack-react-query/package.json | 1 - .../react/tanstack-react-query/src/gql/gql.ts | 26 +--- .../tanstack-react-query/src/gql/graphql.ts | 128 ++++++------------ .../tanstack-react-query/src/use-graphql.ts | 32 ++--- 5 files changed, 60 insertions(+), 130 deletions(-) diff --git a/examples/react/tanstack-react-query/codegen.ts b/examples/react/tanstack-react-query/codegen.ts index 6d94d628656..1a100a3ccf1 100644 --- a/examples/react/tanstack-react-query/codegen.ts +++ b/examples/react/tanstack-react-query/codegen.ts @@ -7,6 +7,9 @@ const config: CodegenConfig = { generates: { './src/gql/': { preset: 'client', + config: { + documentMode: 'string', + }, }, }, hooks: { afterAllFileWrite: ['prettier --write'] }, diff --git a/examples/react/tanstack-react-query/package.json b/examples/react/tanstack-react-query/package.json index 8c80af4c098..1d3628cbd5a 100644 --- a/examples/react/tanstack-react-query/package.json +++ b/examples/react/tanstack-react-query/package.json @@ -3,7 +3,6 @@ "version": "0.1.0", "private": true, "dependencies": { - "@graphql-tools/executor-http": "^0.1.8", "@tanstack/react-query": "4.26.1", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/examples/react/tanstack-react-query/src/gql/gql.ts b/examples/react/tanstack-react-query/src/gql/gql.ts index 6b28626a405..ab23ba6aa75 100644 --- a/examples/react/tanstack-react-query/src/gql/gql.ts +++ b/examples/react/tanstack-react-query/src/gql/gql.ts @@ -1,6 +1,5 @@ /* 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. @@ -19,40 +18,19 @@ const documents = { 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']; +): 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 documents)['\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] ?? {}; } - -export type DocumentType> = TDocumentNode extends DocumentNode< - infer TType, - any -> - ? TType - : never; diff --git a/examples/react/tanstack-react-query/src/gql/graphql.ts b/examples/react/tanstack-react-query/src/gql/graphql.ts index 9ca792fa77d..239024a493c 100644 --- a/examples/react/tanstack-react-query/src/gql/graphql.ts +++ b/examples/react/tanstack-react-query/src/gql/graphql.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; @@ -1296,91 +1296,41 @@ export type FilmItemFragment = { 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; +export class TypedDocumentString + extends String + implements DocumentTypeDecoration +{ + __apiType?: DocumentTypeDecoration['__apiType']; + + constructor(private value: string, public __meta__?: { hash: string }) { + super(value); + } + + toString(): string & DocumentTypeDecoration { + return this.value; + } +} +export const FilmItemFragmentDoc = new TypedDocumentString(` + fragment FilmItem on Film { + id + title + releaseDate + producers +} + `) 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; diff --git a/examples/react/tanstack-react-query/src/use-graphql.ts b/examples/react/tanstack-react-query/src/use-graphql.ts index eab06ff2171..97131041e0d 100644 --- a/examples/react/tanstack-react-query/src/use-graphql.ts +++ b/examples/react/tanstack-react-query/src/use-graphql.ts @@ -1,29 +1,29 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { buildHTTPExecutor } from '@graphql-tools/executor-http'; -import { TypedDocumentNode } from '@graphql-typed-document-node/core'; -import { ASTNode, ExecutionResult, Kind, OperationDefinitionNode } from 'graphql'; +import { ExecutionResult } from 'graphql'; import { useQuery } from '@tanstack/react-query'; - -const executor = buildHTTPExecutor({ - endpoint: 'https://swapi-graphql.netlify.app/.netlify/functions/index', -}); - -const isOperationDefinition = (def: ASTNode): def is OperationDefinitionNode => def.kind === Kind.OPERATION_DEFINITION; +import { TypedDocumentString } from './gql/graphql'; export function useGraphQL( - document: TypedDocumentNode, + document: TypedDocumentString, ...[variables]: TVariables extends Record ? [] : [TVariables] ) { return useQuery( [ // This logic can be customized as desired - document.definitions.find(isOperationDefinition)?.name, + document, variables, ] as const, - async ({ queryKey }) => - executor({ - document: document as any, - variables: queryKey[1] as any, - }) as Promise> + async ({ queryKey }) => { + return fetch('https://swapi-graphql.netlify.app/.netlify/functions/index', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query: queryKey[0].toString(), + variables: queryKey[1], + }), + }).then(response => response.json()) as Promise>; + } ); } From cfd9380391118254ded9fdb5a2a274d47b3a56bb Mon Sep 17 00:00:00 2001 From: beerose Date: Wed, 15 Mar 2023 15:36:54 +0100 Subject: [PATCH 22/28] Add docs --- .../pages/plugins/presets/preset-client.mdx | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/website/src/pages/plugins/presets/preset-client.mdx b/website/src/pages/plugins/presets/preset-client.mdx index 681b26a26ab..e89a81e943d 100644 --- a/website/src/pages/plugins/presets/preset-client.mdx +++ b/website/src/pages/plugins/presets/preset-client.mdx @@ -51,6 +51,7 @@ The `client` preset allows the following `config` options: - [`dedupeFragments`](/plugins/typescript/typescript#dedupefragments): Removes fragment duplicates for reducing data transfer. It is done by removing sub-fragments imports from fragment definition. - [`nonOptionalTypename`](/plugins/typescript/typescript#nonoptionaltypename): Automatically adds `__typename` field to the generated types, even when they are not specified in the selection set, and makes it non-optional. - [`avoidOptionals`](/plugins/typescript/typescript#avoidoptionals): This will cause the generator to avoid using TypeScript optionals (`?`) on types. +- [`documentMode`](#documentmode): Allows you to control how the documents are generated. For more information or feature request, please [refer to the repository discussions](https://github.com/dotansimha/graphql-code-generator/discussions). @@ -525,3 +526,82 @@ const nextConfig = { ``` Note that you will need to provide the `artifactDirectory` path that should be the same as the one configured in your `codegen.ts` + +### DocumentMode + +The `DocumentMode` option can be used to control how the plugin will generate the document nodes. + +By default, the generated documents are of type `TypedDocumentNode` which is a fully typed GraphQL operation AST. Example: + +```ts filename="out/gql.ts" +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 +``` + +The `documentMode` option can be used to change the generated documents to `string`: + +```ts filename="codegen.ts" {9-11} +import { type CodegenConfig } from '@graphql-codegen/cli' + +const config: CodegenConfig = { + schema: 'schema.graphql', + documents: ['src/**/*.tsx'], + generates: { + './src/gql/': { + preset: 'client', + config: { + documentMode: 'string' + } + } + } +} +``` + +This will generate the following: + +```ts filename="out/gql.ts" +export type HelloQueryVariables = Exact<{ [key: string]: never }> + +export type HelloQuery = { __typename?: 'Query'; hello: string } + +export const HelloDocument = new TypedDocumentString(` + query hello { + hello + } +`) as unknown as TypedDocumentString +``` + +It can then be used as follow: + +```ts filename="Fetch example" +import { graphql } from './gql' + +const helloQuery = graphql(` + query hello { + hello + } +`) + +fetch('https:', { + method: 'POST', + headers: { + 'content-type': 'application/json' + }, + body: JSON.stringify({ + query: helloQuery.toString() + }) +}) +``` From a97276b7826fd4634a33a6ac05a77280def28e0d Mon Sep 17 00:00:00 2001 From: beerose Date: Mon, 20 Mar 2023 12:05:45 +0100 Subject: [PATCH 23/28] Update @graphql-typed-document-node/code version --- .../package.json | 2 +- examples/persisted-documents/package.json | 2 +- examples/typescript-esm/package.json | 2 +- examples/vite/vite-react-cts/package.json | 2 +- examples/vite/vite-react-mts/package.json | 2 +- examples/vite/vite-react-ts/package.json | 2 +- examples/yoga-tests/package.json | 2 +- packages/presets/client/package.json | 2 +- yarn.lock | 52 ++----------------- 9 files changed, 13 insertions(+), 55 deletions(-) diff --git a/examples/persisted-documents-string-mode/package.json b/examples/persisted-documents-string-mode/package.json index 7a3f0cd9173..0c90cd29a55 100644 --- a/examples/persisted-documents-string-mode/package.json +++ b/examples/persisted-documents-string-mode/package.json @@ -7,7 +7,7 @@ "@graphql-yoga/plugin-persisted-operations": "1.7.2" }, "devDependencies": { - "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", + "@graphql-typed-document-node/core": "3.2.0", "jest": "28.1.3", "babel-jest": "28.1.3", "@graphql-codegen/cli": "3.2.2", diff --git a/examples/persisted-documents/package.json b/examples/persisted-documents/package.json index 16999d826de..7ab95e50ce1 100644 --- a/examples/persisted-documents/package.json +++ b/examples/persisted-documents/package.json @@ -7,7 +7,7 @@ "@graphql-yoga/plugin-persisted-operations": "1.7.2" }, "devDependencies": { - "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", + "@graphql-typed-document-node/core": "3.2.0", "jest": "28.1.3", "babel-jest": "28.1.3", "@graphql-codegen/cli": "3.2.2", diff --git a/examples/typescript-esm/package.json b/examples/typescript-esm/package.json index 526ac5397fb..ad5379b7ebf 100644 --- a/examples/typescript-esm/package.json +++ b/examples/typescript-esm/package.json @@ -7,7 +7,7 @@ "@graphql-codegen/client-preset": "2.1.1" }, "dependencies": { - "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", + "@graphql-typed-document-node/core": "3.2.0", "graphql": "16.6.0" }, "scripts": { diff --git a/examples/vite/vite-react-cts/package.json b/examples/vite/vite-react-cts/package.json index c0e45077d20..4220f39d878 100644 --- a/examples/vite/vite-react-cts/package.json +++ b/examples/vite/vite-react-cts/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@apollo/client": "^3.6.9", - "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", + "@graphql-typed-document-node/core": "3.2.0", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.6.0", "react": "^18.2.0", diff --git a/examples/vite/vite-react-mts/package.json b/examples/vite/vite-react-mts/package.json index 1000fdf1f3b..0d661515208 100644 --- a/examples/vite/vite-react-mts/package.json +++ b/examples/vite/vite-react-mts/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@apollo/client": "^3.6.9", - "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", + "@graphql-typed-document-node/core": "3.2.0", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.6.0", "react": "^18.2.0", diff --git a/examples/vite/vite-react-ts/package.json b/examples/vite/vite-react-ts/package.json index 929ce931042..17e5adf66da 100644 --- a/examples/vite/vite-react-ts/package.json +++ b/examples/vite/vite-react-ts/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@apollo/client": "^3.6.9", - "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", + "@graphql-typed-document-node/core": "3.2.0", "@vitejs/plugin-react-swc": "^3.0.0", "graphql": "16.6.0", "react": "^18.2.0", diff --git a/examples/yoga-tests/package.json b/examples/yoga-tests/package.json index 124a478c79e..809517ffbe8 100644 --- a/examples/yoga-tests/package.json +++ b/examples/yoga-tests/package.json @@ -6,7 +6,7 @@ "graphql-yoga": "3.7.2" }, "devDependencies": { - "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", + "@graphql-typed-document-node/core": "3.2.0", "jest": "28.1.3", "babel-jest": "28.1.3", "@graphql-codegen/cli": "3.2.2", diff --git a/packages/presets/client/package.json b/packages/presets/client/package.json index 4b30c0367d0..c38c9e9736b 100644 --- a/packages/presets/client/package.json +++ b/packages/presets/client/package.json @@ -26,7 +26,7 @@ "@graphql-codegen/gql-tag-operations": "2.0.2", "@graphql-codegen/plugin-helpers": "^4.1.0", "@graphql-codegen/visitor-plugin-common": "^3.0.2", - "@graphql-typed-document-node/core": "3.2.0-alpha-20230314161625-aafb8c1", + "@graphql-typed-document-node/core": "3.2.0", "@graphql-tools/documents": "^0.1.0", "@graphql-tools/utils": "^9.0.0", "tslib": "~2.5.0" diff --git a/yarn.lock b/yarn.lock index 21e1b3ead97..8546d44cf3e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2557,21 +2557,6 @@ tslib "^2.4.0" unixify "^1.0.0" -"@graphql-tools/load@6.2.4": - version "6.2.4" - resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-6.2.4.tgz#a1a860bdc9d9e0bd93e1dffdbd2cf8839a521c41" - integrity sha512-FlQC50VELwRxoWUbJMMMs5gG0Dl8BaQYMrXUHTsxwqR7UmksUYnysC21rdousvs6jVZ7pf4unZfZFtBjz+8Edg== - dependencies: - "@graphql-tools/merge" "^6.2.4" - "@graphql-tools/utils" "^6.2.4" - globby "11.0.1" - import-from "3.0.0" - is-glob "4.0.1" - p-limit "3.0.2" - tslib "~2.0.1" - unixify "1.0.0" - valid-url "1.0.9" - "@graphql-tools/load@7.8.13", "@graphql-tools/load@^7.5.5", "@graphql-tools/load@^7.8.0": version "7.8.13" resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-7.8.13.tgz#a813bfc8195d27f465739c15fb1672a6def6e9ee" @@ -2582,14 +2567,6 @@ p-limit "3.1.0" tslib "^2.4.0" -"@graphql-tools/merge@8.3.1": - version "8.3.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.1.tgz#06121942ad28982a14635dbc87b5d488a041d722" - integrity sha512-BMm99mqdNZbEYeTPK3it9r9S6rsZsQKtlqJsSBknAclXq2pGEfOxjcIZi+kBSkHZKPKCRrYDd5vY0+rUmIHVLg== - dependencies: - "@graphql-tools/utils" "8.9.0" - tslib "^2.4.0" - "@graphql-tools/merge@8.3.18": version "8.3.18" resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.18.tgz#bfbb517c68598a885809f16ce5c3bb1ebb8f04a2" @@ -2606,15 +2583,6 @@ "@graphql-tools/utils" "9.2.1" tslib "^2.4.0" -"@graphql-tools/merge@^6.2.4": - version "6.2.17" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-6.2.17.tgz#4dedf87d8435a5e1091d7cc8d4f371ed1e029f1f" - integrity sha512-G5YrOew39fZf16VIrc49q3c8dBqQDD0ax5LYPiNja00xsXDi0T9zsEWVt06ApjtSdSF6HDddlu5S12QjeN8Tow== - dependencies: - "@graphql-tools/schema" "^8.0.2" - "@graphql-tools/utils" "8.0.2" - tslib "~2.3.0" - "@graphql-tools/optimize@^1.3.0": version "1.3.1" resolved "https://registry.yarnpkg.com/@graphql-tools/optimize/-/optimize-1.3.1.tgz#29407991478dbbedc3e7deb8c44f46acb4e9278b" @@ -2676,16 +2644,6 @@ tslib "^2.4.0" value-or-promise "1.0.12" -"@graphql-tools/schema@^8.0.2": - version "8.5.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.5.1.tgz#c2f2ff1448380919a330312399c9471db2580b58" - integrity sha512-0Esilsh0P/qYcB5DKQpiKeQs/jevzIadNTaT0jeWklPMwNbT7yMX4EqZany7mbeRRlSRwMzNzL5olyFdffHBZg== - dependencies: - "@graphql-tools/merge" "8.3.1" - "@graphql-tools/utils" "8.9.0" - tslib "^2.4.0" - value-or-promise "1.0.11" - "@graphql-tools/url-loader@7.17.13", "@graphql-tools/url-loader@^7.13.2", "@graphql-tools/url-loader@^7.9.7": version "7.17.13" resolved "https://registry.yarnpkg.com/@graphql-tools/url-loader/-/url-loader-7.17.13.tgz#d4ee8193792ab1c42db2fbdf5f6ca75fa819ac40" @@ -2736,15 +2694,15 @@ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052" integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== -"@graphql-typed-document-node/core@3.1.2", "@graphql-typed-document-node/core@^3.1.1": +"@graphql-typed-document-node/core@3.1.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.2.tgz#6fc464307cbe3c8ca5064549b806360d84457b04" integrity sha512-9anpBMM9mEgZN4wr2v8wHJI2/u5TnnggewRN6OlvXTTnuVyoY19X6rOv9XTqKRw6dcGKwZsBi8n0kDE2I5i4VA== -"@graphql-typed-document-node/core@3.2.0-alpha-20230314161625-aafb8c1": - version "3.2.0-alpha-20230314161625-aafb8c1" - resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0-alpha-20230314161625-aafb8c1.tgz#f6a18327277c8908e876a340060709c54b44f255" - integrity sha512-eNp0NbL3tLzRsu//InRbp74a7vZRAdqnjTjWwJfPtIvYsoksnrO5gHJQnIIjZ5+mdCRPjO5TvNEsMi4Res1uvw== +"@graphql-typed-document-node/core@3.2.0", "@graphql-typed-document-node/core@^3.1.1": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== "@graphql-yoga/logger@^0.0.1": version "0.0.1" From 2e99784ee3b9a186cdef73034ef60bb3ab3202b9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 20 Mar 2023 11:06:49 +0000 Subject: [PATCH 24/28] chore(dependencies): updated changesets for modified dependencies --- .changeset/@graphql-codegen_client-preset-9137-dependencies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/@graphql-codegen_client-preset-9137-dependencies.md b/.changeset/@graphql-codegen_client-preset-9137-dependencies.md index b49d53be8c7..c899084638a 100644 --- a/.changeset/@graphql-codegen_client-preset-9137-dependencies.md +++ b/.changeset/@graphql-codegen_client-preset-9137-dependencies.md @@ -2,4 +2,4 @@ "@graphql-codegen/client-preset": patch --- dependencies updates: - - Updated dependency [`@graphql-typed-document-node/core@3.2.0-alpha-20230314161625-aafb8c1` ↗︎](https://www.npmjs.com/package/@graphql-typed-document-node/core/v/3.2.0) (from `3.1.2`, in `dependencies`) + - 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`) From bdc1e7d10b2ae9fec52b9ca96762195c43b6363b Mon Sep 17 00:00:00 2001 From: beerose Date: Mon, 20 Mar 2023 12:32:26 +0100 Subject: [PATCH 25/28] Add more info to the dosc --- website/src/pages/plugins/presets/preset-client.mdx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/website/src/pages/plugins/presets/preset-client.mdx b/website/src/pages/plugins/presets/preset-client.mdx index e89a81e943d..76d0a722056 100644 --- a/website/src/pages/plugins/presets/preset-client.mdx +++ b/website/src/pages/plugins/presets/preset-client.mdx @@ -527,7 +527,7 @@ const nextConfig = { Note that you will need to provide the `artifactDirectory` path that should be the same as the one configured in your `codegen.ts` -### DocumentMode +## DocumentMode The `DocumentMode` option can be used to control how the plugin will generate the document nodes. @@ -605,3 +605,7 @@ fetch('https:', { }) }) ``` + +### When to use a string DocumentMode? + +The `string` DocumentMode is useful when you want to reduce the bundle size of your application as you will get string literals instead of typed ASTs. This is useful when your GraphQL client allows you to send a string literal as the query and you don't need to use the AST on the client. From 0f155b4c61a6138e16c551b801975d2c63485ed3 Mon Sep 17 00:00:00 2001 From: beerose Date: Tue, 21 Mar 2023 12:11:11 +0100 Subject: [PATCH 26/28] Update docs --- website/src/pages/plugins/presets/preset-client.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/plugins/presets/preset-client.mdx b/website/src/pages/plugins/presets/preset-client.mdx index 76d0a722056..df230ca740d 100644 --- a/website/src/pages/plugins/presets/preset-client.mdx +++ b/website/src/pages/plugins/presets/preset-client.mdx @@ -608,4 +608,4 @@ fetch('https:', { ### When to use a string DocumentMode? -The `string` DocumentMode is useful when you want to reduce the bundle size of your application as you will get string literals instead of typed ASTs. This is useful when your GraphQL client allows you to send a string literal as the query and you don't need to use the AST on the client. +The `string` DocumentMode is useful when you want to reduce the bundle size of your application as you will get string literals instead of typed ASTs. This is useful when your GraphQL client allows you to send a string literal as the query and you don't need to use the AST on the client, e.g. when using `graphql-request`, SWR, React Query, etc. From 5771e6df1eceb3993a23e94022219710cf936b56 Mon Sep 17 00:00:00 2001 From: beerose Date: Tue, 21 Mar 2023 12:15:54 +0100 Subject: [PATCH 27/28] Update changeset --- .changeset/gold-dragons-poke.md | 2 +- website/src/pages/docs/getting-started/esm-typescript-usage.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/gold-dragons-poke.md b/.changeset/gold-dragons-poke.md index bc839722fd8..aac30f98dfa 100644 --- a/.changeset/gold-dragons-poke.md +++ b/.changeset/gold-dragons-poke.md @@ -4,4 +4,4 @@ '@graphql-codegen/client-preset': minor --- -Add TypedDocumentNode string alternative that doesn't require GraphQL AST on the client +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. diff --git a/website/src/pages/docs/getting-started/esm-typescript-usage.mdx b/website/src/pages/docs/getting-started/esm-typescript-usage.mdx index 811be608a93..a573d447977 100644 --- a/website/src/pages/docs/getting-started/esm-typescript-usage.mdx +++ b/website/src/pages/docs/getting-started/esm-typescript-usage.mdx @@ -76,7 +76,7 @@ This step, however, is fully optional. "@graphql-codegen/gql-tag-operations-preset": "1.5.2" }, "dependencies": { - "@graphql-typed-document-node/core": "3.1.1", + "@graphql-typed-document-node/core": "3.2.0", "graphql": "16.5.0" }, "scripts": { From 5ce6b4f2b262314ae65991f39a6bd132643668d0 Mon Sep 17 00:00:00 2001 From: beerose Date: Tue, 21 Mar 2023 13:02:04 +0100 Subject: [PATCH 28/28] Update versions in changeset --- .changeset/gold-dragons-poke.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.changeset/gold-dragons-poke.md b/.changeset/gold-dragons-poke.md index aac30f98dfa..e63476db204 100644 --- a/.changeset/gold-dragons-poke.md +++ b/.changeset/gold-dragons-poke.md @@ -1,7 +1,8 @@ --- -'@graphql-codegen/typed-document-node': minor -'@graphql-codegen/gql-tag-operations': minor -'@graphql-codegen/client-preset': minor +'@graphql-codegen/typed-document-node': major +'@graphql-codegen/gql-tag-operations': major +'@graphql-codegen/client-preset': major +'@graphql-codegen/gql-tag-operations-preset': major --- 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.