Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add deprecated directive to arguments and input values #1560

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/type/__tests__/definition-test.js
Expand Up @@ -281,6 +281,8 @@ describe('Type System: Objects', () => {
description: undefined,
type: ScalarType,
defaultValue: undefined,
isDeprecated: false,
deprecationReason: undefined,
extensions: undefined,
astNode: undefined,
},
Expand Down Expand Up @@ -772,6 +774,8 @@ describe('Type System: Input Objects', () => {
description: undefined,
type: ScalarType,
defaultValue: undefined,
isDeprecated: false,
deprecationReason: undefined,
extensions: undefined,
astNode: undefined,
},
Expand All @@ -792,6 +796,8 @@ describe('Type System: Input Objects', () => {
type: ScalarType,
defaultValue: undefined,
extensions: undefined,
isDeprecated: false,
deprecationReason: undefined,
astNode: undefined,
},
});
Expand Down
4 changes: 4 additions & 0 deletions src/type/__tests__/directive-test.js
Expand Up @@ -39,6 +39,8 @@ describe('Type System: Directive', () => {
description: undefined,
type: GraphQLString,
defaultValue: undefined,
isDeprecated: false,
deprecationReason: undefined,
extensions: undefined,
astNode: undefined,
},
Expand All @@ -47,6 +49,8 @@ describe('Type System: Directive', () => {
description: undefined,
type: GraphQLInt,
defaultValue: undefined,
isDeprecated: false,
deprecationReason: undefined,
extensions: undefined,
astNode: undefined,
},
Expand Down
57 changes: 54 additions & 3 deletions src/type/__tests__/introspection-test.js
Expand Up @@ -342,7 +342,17 @@ describe('Introspection', () => {
},
{
name: 'inputFields',
args: [],
args: [
{
name: 'includeDeprecated',
type: {
kind: 'SCALAR',
name: 'Boolean',
ofType: null,
},
defaultValue: 'false',
},
],
type: {
kind: 'LIST',
name: null,
Expand Down Expand Up @@ -460,7 +470,17 @@ describe('Introspection', () => {
},
{
name: 'args',
args: [],
args: [
{
name: 'includeDeprecated',
type: {
kind: 'SCALAR',
name: 'Boolean',
ofType: null,
},
defaultValue: 'false',
},
],
type: {
kind: 'NON_NULL',
name: null,
Expand Down Expand Up @@ -585,6 +605,32 @@ describe('Introspection', () => {
isDeprecated: false,
deprecationReason: null,
},
{
name: 'isDeprecated',
args: [],
type: {
kind: 'NON_NULL',
name: null,
ofType: {
kind: 'SCALAR',
name: 'Boolean',
ofType: null,
},
},
isDeprecated: false,
deprecationReason: null,
},
{
name: 'deprecationReason',
args: [],
type: {
kind: 'SCALAR',
name: 'String',
ofType: null,
},
isDeprecated: false,
deprecationReason: null,
},
],
inputFields: null,
interfaces: [],
Expand Down Expand Up @@ -903,7 +949,12 @@ describe('Introspection', () => {
{
name: 'deprecated',
isRepeatable: false,
locations: ['FIELD_DEFINITION', 'ENUM_VALUE'],
locations: [
'FIELD_DEFINITION',
'ARGUMENT_DEFINITION',
'ENUM_VALUE',
'INPUT_FIELD_DEFINITION',
],
args: [
{
defaultValue: '"No longer supported"',
Expand Down
4 changes: 4 additions & 0 deletions src/type/__tests__/predicate-test.js
Expand Up @@ -549,6 +549,8 @@ describe('Type predicates', () => {
name: 'someArg',
description: undefined,
defaultValue: undefined,
isDeprecated: false,
deprecationReason: null,
extensions: undefined,
astNode: undefined,
...config,
Expand Down Expand Up @@ -593,6 +595,8 @@ describe('Type predicates', () => {
name: 'someInputField',
description: undefined,
defaultValue: undefined,
isDeprecated: false,
deprecationReason: null,
extensions: undefined,
astNode: undefined,
...config,
Expand Down
6 changes: 6 additions & 0 deletions src/type/definition.d.ts
Expand Up @@ -546,6 +546,7 @@ export interface GraphQLArgumentConfig {
description?: Maybe<string>;
type: GraphQLInputType;
defaultValue?: any;
deprecationReason?: Maybe<string>;
extensions?: Maybe<Readonly<GraphQLArgumentExtensions>>;
astNode?: Maybe<InputValueDefinitionNode>;
}
Expand Down Expand Up @@ -576,6 +577,8 @@ export interface GraphQLArgument {
description: Maybe<string>;
type: GraphQLInputType;
defaultValue: any;
isDeprecated: boolean;
deprecationReason: Maybe<string>;
extensions: Maybe<Readonly<GraphQLArgumentExtensions>>;
astNode: Maybe<InputValueDefinitionNode>;
}
Expand Down Expand Up @@ -915,6 +918,7 @@ export interface GraphQLInputFieldConfig {
description?: Maybe<string>;
type: GraphQLInputType;
defaultValue?: any;
deprecationReason?: Maybe<string>;
extensions?: Maybe<Readonly<GraphQLInputFieldExtensions>>;
astNode?: Maybe<InputValueDefinitionNode>;
}
Expand All @@ -928,6 +932,8 @@ export interface GraphQLInputField {
description?: Maybe<string>;
type: GraphQLInputType;
defaultValue?: any;
isDeprecated: boolean;
deprecationReason: Maybe<string>;
extensions: Maybe<Readonly<GraphQLInputFieldExtensions>>;
astNode?: Maybe<InputValueDefinitionNode>;
}
Expand Down
39 changes: 31 additions & 8 deletions src/type/definition.js
Expand Up @@ -848,14 +848,23 @@ function defineFieldMap<TSource, TContext>(
`${config.name}.${fieldName} args must be an object with argument names as keys.`,
);

const args = objectEntries(argsConfig).map(([argName, argConfig]) => ({
name: argName,
description: argConfig.description,
type: argConfig.type,
defaultValue: argConfig.defaultValue,
extensions: argConfig.extensions && toObjMap(argConfig.extensions),
astNode: argConfig.astNode,
}));
const args = objectEntries(argsConfig).map(([argName, argConfig]) => {
devAssert(
!('isDeprecated' in argConfig),
`${config.name}.${fieldName}.${argName} should provide "deprecationReason" instead of "isDeprecated".`,
);

return {
name: argName,
description: argConfig.description,
type: argConfig.type,
defaultValue: argConfig.defaultValue,
isDeprecated: argConfig.deprecationReason != null,
deprecationReason: argConfig.deprecationReason,
extensions: argConfig.extensions && toObjMap(argConfig.extensions),
astNode: argConfig.astNode,
};
});

return {
name: fieldName,
Expand Down Expand Up @@ -902,6 +911,7 @@ export function argsToArgsConfig(
description: arg.description,
type: arg.type,
defaultValue: arg.defaultValue,
deprecationReason: arg.deprecationReason,
extensions: arg.extensions,
astNode: arg.astNode,
}),
Expand Down Expand Up @@ -978,6 +988,7 @@ export type GraphQLArgumentConfig = {|
type: GraphQLInputType,
defaultValue?: mixed,
extensions?: ?ReadOnlyObjMapLike<mixed>,
deprecationReason?: ?string,
astNode?: ?InputValueDefinitionNode,
|};

Expand Down Expand Up @@ -1007,6 +1018,8 @@ export type GraphQLArgument = {|
description: ?string,
type: GraphQLInputType,
defaultValue: mixed,
isDeprecated: boolean,
deprecationReason: ?string,
extensions: ?ReadOnlyObjMap<mixed>,
astNode: ?InputValueDefinitionNode,
|};
Expand Down Expand Up @@ -1566,17 +1579,24 @@ function defineInputFieldMap(
isPlainObj(fieldMap),
`${config.name} fields must be an object with field names as keys or a function which returns such an object.`,
);

return mapValue(fieldMap, (fieldConfig, fieldName) => {
devAssert(
!('resolve' in fieldConfig),
`${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`,
);
devAssert(
!('isDeprecated' in fieldConfig),
`${config.name}.${fieldName} should provide "deprecationReason" instead of "isDeprecated".`,
);

return {
name: fieldName,
description: fieldConfig.description,
type: fieldConfig.type,
defaultValue: fieldConfig.defaultValue,
isDeprecated: fieldConfig.deprecationReason != null,
deprecationReason: fieldConfig.deprecationReason,
extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions),
astNode: fieldConfig.astNode,
};
Expand All @@ -1596,6 +1616,7 @@ export type GraphQLInputFieldConfig = {|
description?: ?string,
type: GraphQLInputType,
defaultValue?: mixed,
deprecationReason?: ?string,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isDeprecated missing here?

extensions?: ?ReadOnlyObjMapLike<mixed>,
astNode?: ?InputValueDefinitionNode,
|};
Expand All @@ -1607,6 +1628,8 @@ export type GraphQLInputField = {|
description: ?string,
type: GraphQLInputType,
defaultValue: mixed,
isDeprecated: boolean,
deprecationReason: ?string,
extensions: ?ReadOnlyObjMap<mixed>,
astNode: ?InputValueDefinitionNode,
|};
Expand Down
32 changes: 23 additions & 9 deletions src/type/directives.js
Expand Up @@ -75,14 +75,23 @@ export class GraphQLDirective {
`@${config.name} args must be an object with argument names as keys.`,
);

this.args = objectEntries(args).map(([argName, argConfig]) => ({
name: argName,
description: argConfig.description,
type: argConfig.type,
defaultValue: argConfig.defaultValue,
extensions: argConfig.extensions && toObjMap(argConfig.extensions),
astNode: argConfig.astNode,
}));
this.args = objectEntries(args).map(([argName, argConfig]) => {
devAssert(
!('isDeprecated' in argConfig),
`@${config.name}.${argName} should provide "deprecationReason" instead of "isDeprecated".`,
);

return {
name: argName,
description: argConfig.description,
type: argConfig.type,
defaultValue: argConfig.defaultValue,
isDeprecated: argConfig.deprecationReason != null,
deprecationReason: argConfig.deprecationReason,
extensions: argConfig.extensions && toObjMap(argConfig.extensions),
astNode: argConfig.astNode,
};
});
}

toConfig(): {|
Expand Down Expand Up @@ -180,7 +189,12 @@ export const DEFAULT_DEPRECATION_REASON = 'No longer supported';
export const GraphQLDeprecatedDirective = new GraphQLDirective({
name: 'deprecated',
description: 'Marks an element of a GraphQL schema as no longer supported.',
locations: [DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.ENUM_VALUE],
locations: [
DirectiveLocation.FIELD_DEFINITION,
DirectiveLocation.ARGUMENT_DEFINITION,
DirectiveLocation.ENUM_VALUE,
DirectiveLocation.INPUT_FIELD_DEFINITION,
],
args: {
reason: {
type: GraphQLString,
Expand Down
41 changes: 38 additions & 3 deletions src/type/introspection.js
Expand Up @@ -293,9 +293,19 @@ export const __Type = new GraphQLObjectType({
},
inputFields: {
type: GraphQLList(GraphQLNonNull(__InputValue)),
resolve(type) {
args: {
includeDeprecated: {
type: GraphQLBoolean,
defaultValue: false,
},
},
resolve(type, { includeDeprecated }) {
if (isInputObjectType(type)) {
return objectValues(type.getFields());
let values = objectValues(type.getFields());
if (!includeDeprecated) {
values = values.filter((value) => !value.deprecationReason);
}
return values;
}
},
},
Expand Down Expand Up @@ -323,7 +333,22 @@ export const __Field = new GraphQLObjectType({
},
args: {
type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))),
resolve: (field) => field.args,
args: {
includeDeprecated: {
type: GraphQLBoolean,
defaultValue: false,
},
},
// resolve: field => field.args || [],
resolve(field, { includeDeprecated }) {
let args = field.args || [];

if (!includeDeprecated) {
args = args.filter((arg) => !arg.deprecationReason);
}

return args;
},
},
type: {
type: GraphQLNonNull(__Type),
Expand Down Expand Up @@ -368,6 +393,14 @@ export const __InputValue = new GraphQLObjectType({
return valueAST ? print(valueAST) : null;
},
},
isDeprecated: {
type: GraphQLNonNull(GraphQLBoolean),
resolve: (obj) => obj.isDeprecated,
},
deprecationReason: {
type: GraphQLString,
resolve: (obj) => obj.deprecationReason,
},
}: GraphQLFieldConfigMap<GraphQLInputField, mixed>),
});

Expand Down Expand Up @@ -479,6 +512,8 @@ export const TypeMetaFieldDef: GraphQLField<mixed, mixed> = {
description: undefined,
type: GraphQLNonNull(GraphQLString),
defaultValue: undefined,
isDeprecated: false,
deprecationReason: undefined,
extensions: undefined,
astNode: undefined,
},
Expand Down