Skip to content

Commit 063148d

Browse files
committed
findDeprecatedUsages()
This adds a utility for finding field and enum deprecation usages. The function signature is very similar to validation which should make using it easy where validation is already being used in a reporting flow. Closes #389
1 parent 5cf4cef commit 063148d

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,9 @@ export {
325325

326326
// Compares two GraphQLSchemas and detects breaking changes.
327327
findBreakingChanges,
328+
329+
// Report all deprecated usage within a GraphQL document.
330+
findDeprecatedUsages,
328331
} from './utilities';
329332

330333
export type {
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Copyright (c) 2016, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
import { expect } from 'chai';
11+
import { describe, it } from 'mocha';
12+
import { findDeprecatedUsages } from '../findDeprecatedUsages';
13+
import { parse } from '../../language';
14+
import {
15+
GraphQLEnumType,
16+
GraphQLObjectType,
17+
GraphQLSchema,
18+
GraphQLString,
19+
} from '../../type';
20+
21+
describe('findDeprecatedUsages', () => {
22+
23+
const enumType = new GraphQLEnumType({
24+
name: 'EnumType',
25+
values: {
26+
ONE: {},
27+
TWO: { deprecationReason: 'Some enum reason.' }
28+
}
29+
});
30+
31+
const schema = new GraphQLSchema({
32+
query: new GraphQLObjectType({
33+
name: 'Query',
34+
fields: {
35+
normalField: {
36+
args: {
37+
enumArg: { type: enumType },
38+
},
39+
type: GraphQLString,
40+
},
41+
deprecatedField: {
42+
type: GraphQLString,
43+
deprecationReason: 'Some field reason.',
44+
}
45+
}
46+
})
47+
});
48+
49+
it('should report empty set for no deprecated usages', () => {
50+
const errors = findDeprecatedUsages(
51+
schema,
52+
parse('{ normalField(enumArg: ONE) }')
53+
);
54+
55+
expect(errors.length).to.equal(0);
56+
});
57+
58+
it('should report usage of deprecated fields', () => {
59+
const errors = findDeprecatedUsages(
60+
schema,
61+
parse('{ normalField, deprecatedField }')
62+
);
63+
64+
const errorMessages = errors.map(err => err.message);
65+
66+
expect(errorMessages).to.deep.equal([
67+
'The field Query.deprecatedField is deprecated. Some field reason.'
68+
]);
69+
});
70+
71+
it('should report usage of deprecated enums', () => {
72+
const errors = findDeprecatedUsages(
73+
schema,
74+
parse('{ normalField(enumArg: TWO) }')
75+
);
76+
77+
const errorMessages = errors.map(err => err.message);
78+
79+
expect(errorMessages).to.deep.equal([
80+
'The enum value EnumType.TWO is deprecated. Some enum reason.'
81+
]);
82+
});
83+
84+
});

src/utilities/findDeprecatedUsages.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* @flow */
2+
/**
3+
* Copyright (c) Facebook, Inc.
4+
* All rights reserved.
5+
*
6+
* This source code is licensed under the BSD-style license found in the
7+
* LICENSE file in the root directory of this source tree. An additional grant
8+
* of patent rights can be found in the PATENTS file in the same directory.
9+
*/
10+
11+
import { GraphQLError } from '../error/GraphQLError';
12+
import { visit, visitWithTypeInfo } from '../language/visitor';
13+
import type { DocumentNode } from '../language/ast';
14+
import { getNamedType } from '../type/definition';
15+
import { GraphQLSchema } from '../type/schema';
16+
import { TypeInfo } from './TypeInfo';
17+
18+
/**
19+
* A validation rule which reports deprecated usages.
20+
*
21+
* Returns a list of GraphQLError instances describing each deprecated use.
22+
*/
23+
export function findDeprecatedUsages(
24+
schema: GraphQLSchema,
25+
ast: DocumentNode,
26+
): Array<GraphQLError> {
27+
const errors = [];
28+
const typeInfo = new TypeInfo(schema);
29+
30+
visit(ast, visitWithTypeInfo(typeInfo, {
31+
Field(node) {
32+
const fieldDef = typeInfo.getFieldDef();
33+
if (fieldDef && fieldDef.isDeprecated) {
34+
const parentType = typeInfo.getParentType();
35+
if (parentType) {
36+
const reason = fieldDef.deprecationReason;
37+
errors.push(new GraphQLError(
38+
`The field ${parentType.name}.${fieldDef.name} is deprecated.` +
39+
(reason ? ' ' + reason : ''),
40+
[ node ]
41+
));
42+
}
43+
}
44+
},
45+
EnumValue(node) {
46+
const enumVal = typeInfo.getEnumValue();
47+
if (enumVal && enumVal.isDeprecated) {
48+
const type = getNamedType(typeInfo.getInputType());
49+
if (type) {
50+
const reason = enumVal.deprecationReason;
51+
errors.push(new GraphQLError(
52+
`The enum value ${type.name}.${enumVal.name} is deprecated.` +
53+
(reason ? ' ' + reason : ''),
54+
[ node ]
55+
));
56+
}
57+
}
58+
}
59+
}));
60+
61+
return errors;
62+
}

src/utilities/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,6 @@ export { assertValidName } from './assertValidName';
8787
// Compares two GraphQLSchemas and detects breaking changes.
8888
export { findBreakingChanges } from './findBreakingChanges';
8989
export type { BreakingChange } from './findBreakingChanges';
90+
91+
// Report all deprecated usage within a GraphQL document.
92+
export { findDeprecatedUsages } from './findDeprecatedUsages';

0 commit comments

Comments
 (0)