From 5b800e763cb428c972ff0bfb85592405bb513754 Mon Sep 17 00:00:00 2001 From: mitchellhamilton Date: Tue, 26 Apr 2022 11:31:10 +1000 Subject: [PATCH] Fix fields incorrectly being optional --- .changeset/light-experts-serve.md | 5 ++ .changeset/strange-readers-clean.md | 8 ++ packages/compiler/src/operation-types.ts | 6 ++ packages/compiler/src/schema-types.ts | 6 ++ .../src/test/__snapshots__/index.test.ts.snap | 8 +- packages/compiler/src/test/index.test.ts | 88 ++++++++++++++++--- 6 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 .changeset/light-experts-serve.md create mode 100644 .changeset/strange-readers-clean.md diff --git a/.changeset/light-experts-serve.md b/.changeset/light-experts-serve.md new file mode 100644 index 0000000..bccbe5f --- /dev/null +++ b/.changeset/light-experts-serve.md @@ -0,0 +1,5 @@ +--- +"@ts-gql/compiler": patch +--- + +Fixed nullable fields being optional in the generated types diff --git a/.changeset/strange-readers-clean.md b/.changeset/strange-readers-clean.md new file mode 100644 index 0000000..ab1956f --- /dev/null +++ b/.changeset/strange-readers-clean.md @@ -0,0 +1,8 @@ +--- +"@ts-gql/apollo": patch +"@ts-gql/eslint-plugin": patch +"@ts-gql/fetch": patch +"@ts-gql/next": patch +--- + +Republish after broken release diff --git a/packages/compiler/src/operation-types.ts b/packages/compiler/src/operation-types.ts index a77f5c7..92d6c98 100644 --- a/packages/compiler/src/operation-types.ts +++ b/packages/compiler/src/operation-types.ts @@ -48,6 +48,12 @@ async function generateOperationTypes( namespacedImportName: "SchemaTypes", immutableTypes: config.readonlyTypes, noExport: true, + avoidOptionals: { + field: true, + inputValue: false, + object: false, + defaultValue: false, + }, nonOptionalTypename: config.addTypename, skipTypename: !config.addTypename, namingConvention: "keep", diff --git a/packages/compiler/src/schema-types.ts b/packages/compiler/src/schema-types.ts index 9e4c4f1..fd1b952 100644 --- a/packages/compiler/src/schema-types.ts +++ b/packages/compiler/src/schema-types.ts @@ -69,6 +69,12 @@ function generateSchemaTypes( immutableTypes: config.readonlyTypes, nonOptionalTypename: true, namingConvention: "keep", + avoidOptionals: { + field: true, + inputValue: false, + object: false, + defaultValue: false, + }, }, }, ], diff --git a/packages/compiler/src/test/__snapshots__/index.test.ts.snap b/packages/compiler/src/test/__snapshots__/index.test.ts.snap index 5673129..362f876 100644 --- a/packages/compiler/src/test/__snapshots__/index.test.ts.snap +++ b/packages/compiler/src/test/__snapshots__/index.test.ts.snap @@ -171,7 +171,7 @@ Object { "errors": Array [], "fsOperations": Array [ Object { - "content": "// ts-gql-integrity:d63b0d76f8941e6fa31e36de1ef6f553 + "content": "// ts-gql-integrity:8863c8f285259624d86cf9ea58c8e3cf /* ts-gql-meta-begin { @@ -184,7 +184,7 @@ import * as SchemaTypes from \\"./@schema\\"; import { TypedDocumentNode } from \\"@ts-gql/tag\\"; type ThingQueryVariables = SchemaTypes.Exact<{ - optional?: SchemaTypes.InputMaybe; + optional: SchemaTypes.InputMaybe; required: SchemaTypes.Scalars['String']; }>; @@ -221,7 +221,7 @@ Object { "errors": Array [], "fsOperations": Array [ Object { - "content": "// ts-gql-integrity:7830dea677fdaea0679792ddce6ca199 + "content": "// ts-gql-integrity:aef83417457632256cd8091ba15be34e /* ts-gql-meta-begin { @@ -234,7 +234,7 @@ import * as SchemaTypes from \\"./@schema\\"; import { TypedDocumentNode } from \\"@ts-gql/tag\\"; type ThingQueryVariables = SchemaTypes.Exact<{ - optional?: SchemaTypes.InputMaybe; + optional: SchemaTypes.InputMaybe; }>; diff --git a/packages/compiler/src/test/index.test.ts b/packages/compiler/src/test/index.test.ts index 9866ed5..98a3ab1 100644 --- a/packages/compiler/src/test/index.test.ts +++ b/packages/compiler/src/test/index.test.ts @@ -21,7 +21,7 @@ async function setupEnv(specificSchema: string = schema) { JSON.stringify( { name: "something", - "ts-gql": { schema: "schema.graphql" }, + "ts-gql": { schema: "schema.graphql" } }, null, 2 @@ -38,13 +38,13 @@ async function setupEnv(specificSchema: string = schema) { async function build(cwd: string) { let result = await getGeneratedTypes(await getConfig(cwd), true); return { - errors: result.errors.map((x) => + errors: result.errors.map(x => stripAnsi(x.replace(slash(cwd), "CURRENT_WORKING_DIRECTORY")) ), fsOperations: result.fsOperations - .filter((x) => !path.parse(x.filename).name.startsWith("@")) + .filter(x => !path.parse(x.filename).name.startsWith("@")) .sort((a, b) => a.filename.localeCompare(b.filename)) - .map((x) => ({ ...x, filename: slash(path.relative(cwd, x.filename)) })), + .map(x => ({ ...x, filename: slash(path.relative(cwd, x.filename)) })) }; } @@ -79,7 +79,7 @@ test("basic", async () => { query Thing { hello } - `, + ` ]) ); expect(await build(dir)).toMatchSnapshot(); @@ -110,7 +110,7 @@ test("list with fragment works as expected", async () => { other } } - `, + ` ]) ); @@ -143,7 +143,7 @@ test("something", async () => { ...Frag_b } } - `, + ` ]) ); expect(await build(dir)).toMatchSnapshot(); @@ -173,7 +173,7 @@ test("errors in fragments are not shown for usages", async () => { i } } - `, + ` ]) ); expect((await build(dir)).errors).toMatchInlineSnapshot(` @@ -208,7 +208,7 @@ test("with directory that ends with .ts", async () => { query Thing { hello } - `, + ` ]) ); const dirEndsWithTs = path.join(dir, "thing.ts"); @@ -229,7 +229,7 @@ test("optional variable", async () => { query Thing($optional: String) { optional(thing: $optional) } - `, + ` ]) ); const dirEndsWithTs = path.join(dir, "thing.ts"); @@ -251,7 +251,7 @@ test("optional and required variables", async () => { optional(thing: $optional) other: optional(thing: $required) } - `, + ` ]) ); const dirEndsWithTs = path.join(dir, "thing.ts"); @@ -272,7 +272,7 @@ test("required variable", async () => { query Thing($required: String!) { optional(thing: $required) } - `, + ` ]) ); const dirEndsWithTs = path.join(dir, "thing.ts"); @@ -309,7 +309,7 @@ test.skip("fragments with circular dependencies error well", async () => { ...Frag_b } } - `, + ` ]) ); const dirEndsWithTs = path.join(dir, "thing.ts"); @@ -319,3 +319,65 @@ test.skip("fragments with circular dependencies error well", async () => { expect(await build(dir)).toMatchSnapshot(); }); + +test("returned nullable fields are not nullable", async () => { + let dir = await setupEnv(); + + await fs.writeFile( + path.join(dir, "index.tsx"), + makeSourceFile([ + graphql` + query Thing { + something + } + ` + ]) + ); + + expect(await build(dir)).toMatchInlineSnapshot(` + Object { + "errors": Array [], + "fsOperations": Array [ + Object { + "content": "// ts-gql-integrity:dfdfd721d6fff5c53f80455b9f87f5fe + /* + ts-gql-meta-begin + { + \\"hash\\": \\"ab3ae6d6a5717aa0534198074d098314\\" + } + ts-gql-meta-end + */ + + import * as SchemaTypes from \\"./@schema\\"; + import { TypedDocumentNode } from \\"@ts-gql/tag\\"; + + type ThingQueryVariables = SchemaTypes.Exact<{ [key: string]: never; }>; + + + type ThingQuery = { readonly __typename: 'Query', readonly something: string | null }; + + + + export type type = TypedDocumentNode<{ + type: \\"query\\"; + result: ThingQuery; + variables: ThingQueryVariables; + documents: SchemaTypes.TSGQLDocuments; + fragments: SchemaTypes.TSGQLRequiredFragments<\\"none\\"> + }> + + declare module \\"./@schema\\" { + interface TSGQLDocuments { + Thing: type; + } + } + + export const document = JSON.parse(\\"{\\\\\\"kind\\\\\\":\\\\\\"Document\\\\\\",\\\\\\"definitions\\\\\\":[{\\\\\\"kind\\\\\\":\\\\\\"OperationDefinition\\\\\\",\\\\\\"operation\\\\\\":\\\\\\"query\\\\\\",\\\\\\"name\\\\\\":{\\\\\\"kind\\\\\\":\\\\\\"Name\\\\\\",\\\\\\"value\\\\\\":\\\\\\"Thing\\\\\\"},\\\\\\"variableDefinitions\\\\\\":[],\\\\\\"directives\\\\\\":[],\\\\\\"selectionSet\\\\\\":{\\\\\\"kind\\\\\\":\\\\\\"SelectionSet\\\\\\",\\\\\\"selections\\\\\\":[{\\\\\\"kind\\\\\\":\\\\\\"Field\\\\\\",\\\\\\"name\\\\\\":{\\\\\\"kind\\\\\\":\\\\\\"Name\\\\\\",\\\\\\"value\\\\\\":\\\\\\"something\\\\\\"},\\\\\\"arguments\\\\\\":[],\\\\\\"directives\\\\\\":[]}]}}]}\\") + ", + "filename": "__generated__/ts-gql/Thing.ts", + "type": "output", + }, + ], + } + `); +});