From 27f495e469af565d3a51c481d9f8acf67fa750a7 Mon Sep 17 00:00:00 2001 From: Ivan Goncharov Date: Tue, 24 Nov 2020 12:28:46 +0200 Subject: [PATCH] introspection: Add missing support for deprecated input values (#2855) Fixes #2834 --- .../__tests__/buildClientSchema-test.js | 35 +++++++++++++++- .../__tests__/getIntrospectionQuery-test.js | 42 +++++++++++++++++++ src/utilities/buildClientSchema.js | 1 + src/utilities/getIntrospectionQuery.d.ts | 6 +++ src/utilities/getIntrospectionQuery.js | 19 +++++++-- src/utilities/introspectionFromSchema.js | 1 + 6 files changed, 100 insertions(+), 4 deletions(-) diff --git a/src/utilities/__tests__/buildClientSchema-test.js b/src/utilities/__tests__/buildClientSchema-test.js index 738659143ea..33a4fe3a616 100644 --- a/src/utilities/__tests__/buildClientSchema-test.js +++ b/src/utilities/__tests__/buildClientSchema-test.js @@ -486,6 +486,14 @@ describe('Type System: build schema from introspection', () => { it('builds a schema aware of deprecation', () => { const sdl = dedent` + directive @someDirective( + """This is a shiny new argument""" + shinyArg: SomeInputObject + + """This was our design mistake :(""" + oldArg: String @deprecated(reason: "Use shinyArg") + ) on QUERY + enum Color { """So rosy""" RED @@ -500,13 +508,32 @@ describe('Type System: build schema from introspection', () => { MAUVE @deprecated(reason: "No longer in fashion") } + input SomeInputObject { + """Nothing special about it, just deprecated for some unknown reason""" + oldField: String @deprecated(reason: "Don't use it, use newField instead!") + + """Same field but with a new name""" + newField: String + } + type Query { """This is a shiny string field""" shinyString: String """This is a deprecated string field""" deprecatedString: String @deprecated(reason: "Use shinyString") + + """Color of a week""" color: Color + + """Some random field""" + someField( + """This is a shiny new argument""" + shinyArg: SomeInputObject + + """This was our design mistake :(""" + oldArg: String @deprecated(reason: "Use shinyArg") + ): String } `; @@ -515,8 +542,14 @@ describe('Type System: build schema from introspection', () => { it('builds a schema with empty deprecation reasons', () => { const sdl = dedent` + directive @someDirective(someArg: SomeInputObject @deprecated(reason: "")) on QUERY + type Query { - someField: String @deprecated(reason: "") + someField(someArg: SomeInputObject @deprecated(reason: "")): SomeEnum @deprecated(reason: "") + } + + input SomeInputObject { + someInputField: String @deprecated(reason: "") } enum SomeEnum { diff --git a/src/utilities/__tests__/getIntrospectionQuery-test.js b/src/utilities/__tests__/getIntrospectionQuery-test.js index 14509ed5638..3f0c36298f4 100644 --- a/src/utilities/__tests__/getIntrospectionQuery-test.js +++ b/src/utilities/__tests__/getIntrospectionQuery-test.js @@ -74,4 +74,46 @@ describe('getIntrospectionQuery', () => { 'specifiedByUrl', ); }); + + it('include "isDeprecated" field on input values', () => { + expectIntrospectionQuery().toMatch('isDeprecated', 2); + + expectIntrospectionQuery({ inputValueDeprecation: true }).toMatch( + 'isDeprecated', + 3, + ); + + expectIntrospectionQuery({ inputValueDeprecation: false }).toMatch( + 'isDeprecated', + 2, + ); + }); + + it('include "deprecationReason" field on input values', () => { + expectIntrospectionQuery().toMatch('deprecationReason', 2); + + expectIntrospectionQuery({ inputValueDeprecation: true }).toMatch( + 'deprecationReason', + 3, + ); + + expectIntrospectionQuery({ inputValueDeprecation: false }).toMatch( + 'deprecationReason', + 2, + ); + }); + + it('include deprecated input field and args', () => { + expectIntrospectionQuery().toMatch('includeDeprecated: true', 2); + + expectIntrospectionQuery({ inputValueDeprecation: true }).toMatch( + 'includeDeprecated: true', + 5, + ); + + expectIntrospectionQuery({ inputValueDeprecation: false }).toMatch( + 'includeDeprecated: true', + 2, + ); + }); }); diff --git a/src/utilities/buildClientSchema.js b/src/utilities/buildClientSchema.js index 59498e849bf..bdf44200018 100644 --- a/src/utilities/buildClientSchema.js +++ b/src/utilities/buildClientSchema.js @@ -377,6 +377,7 @@ export function buildClientSchema( description: inputValueIntrospection.description, type, defaultValue, + deprecationReason: inputValueIntrospection.deprecationReason, }; } diff --git a/src/utilities/getIntrospectionQuery.d.ts b/src/utilities/getIntrospectionQuery.d.ts index b1822168ec7..6e5fad16e6d 100644 --- a/src/utilities/getIntrospectionQuery.d.ts +++ b/src/utilities/getIntrospectionQuery.d.ts @@ -18,6 +18,10 @@ export interface IntrospectionOptions { // Whether to include `description` field on schema. // Default: false schemaDescription?: boolean; + + // Whether target GraphQL server support deprecation of input values. + // Default: false + inputValueDeprecation?: boolean; } export function getIntrospectionQuery(options?: IntrospectionOptions): string; @@ -169,6 +173,8 @@ export interface IntrospectionInputValue { readonly description?: Maybe; readonly type: IntrospectionInputTypeRef; readonly defaultValue?: Maybe; + readonly isDeprecated?: boolean; + readonly deprecationReason?: Maybe; } export interface IntrospectionEnumValue { diff --git a/src/utilities/getIntrospectionQuery.js b/src/utilities/getIntrospectionQuery.js index d54e77e510c..1c9abb42040 100644 --- a/src/utilities/getIntrospectionQuery.js +++ b/src/utilities/getIntrospectionQuery.js @@ -16,6 +16,10 @@ export type IntrospectionOptions = {| // Whether to include `description` field on schema. // Default: false schemaDescription?: boolean, + + // Whether target GraphQL server support deprecation of input values. + // Default: false + inputValueDeprecation?: boolean, |}; export function getIntrospectionQuery(options?: IntrospectionOptions): string { @@ -24,6 +28,7 @@ export function getIntrospectionQuery(options?: IntrospectionOptions): string { specifiedByUrl: false, directiveIsRepeatable: false, schemaDescription: false, + inputValueDeprecation: false, ...options, }; @@ -38,6 +43,10 @@ export function getIntrospectionQuery(options?: IntrospectionOptions): string { ? descriptions : ''; + function inputDeprecation(str) { + return optionsWithDefault.inputValueDeprecation ? str : ''; + } + return ` query IntrospectionQuery { __schema { @@ -53,7 +62,7 @@ export function getIntrospectionQuery(options?: IntrospectionOptions): string { ${descriptions} ${directiveIsRepeatable} locations - args { + args${inputDeprecation('(includeDeprecated: true)')} { ...InputValue } } @@ -68,7 +77,7 @@ export function getIntrospectionQuery(options?: IntrospectionOptions): string { fields(includeDeprecated: true) { name ${descriptions} - args { + args${inputDeprecation('(includeDeprecated: true)')} { ...InputValue } type { @@ -77,7 +86,7 @@ export function getIntrospectionQuery(options?: IntrospectionOptions): string { isDeprecated deprecationReason } - inputFields { + inputFields${inputDeprecation('(includeDeprecated: true)')} { ...InputValue } interfaces { @@ -99,6 +108,8 @@ export function getIntrospectionQuery(options?: IntrospectionOptions): string { ${descriptions} type { ...TypeRef } defaultValue + ${inputDeprecation('isDeprecated')} + ${inputDeprecation('deprecationReason')} } fragment TypeRef on __Type { @@ -280,6 +291,8 @@ export type IntrospectionInputValue = {| +description?: ?string, +type: IntrospectionInputTypeRef, +defaultValue: ?string, + +isDeprecated?: boolean, + +deprecationReason?: ?string, |}; export type IntrospectionEnumValue = {| diff --git a/src/utilities/introspectionFromSchema.js b/src/utilities/introspectionFromSchema.js index 74c90ef38e4..45d2c042c55 100644 --- a/src/utilities/introspectionFromSchema.js +++ b/src/utilities/introspectionFromSchema.js @@ -29,6 +29,7 @@ export function introspectionFromSchema( specifiedByUrl: true, directiveIsRepeatable: true, schemaDescription: true, + inputValueDeprecation: true, ...options, };