Skip to content

Commit

Permalink
findDeprecatedUsages()
Browse files Browse the repository at this point in the history
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
  • Loading branch information
leebyron committed Jan 19, 2017
1 parent 5cf4cef commit 3adaaa4
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ export {

// Compares two GraphQLSchemas and detects breaking changes.
findBreakingChanges,

// Report all deprecated usage within a GraphQL document.
findDeprecatedUsages,
} from './utilities';

export type {
Expand Down
84 changes: 84 additions & 0 deletions src/utilities/__tests__/findDeprecatedUsages-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2016, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

import { expect } from 'chai';
import { describe, it } from 'mocha';
import { findDeprecatedUsages } from '../findDeprecatedUsages';
import { parse } from '../../language';
import {
GraphQLEnumType,
GraphQLObjectType,
GraphQLSchema,
GraphQLString,
} from '../../type';

describe('findDeprecatedUsages', () => {

const enumType = new GraphQLEnumType({
name: 'EnumType',
values: {
ONE: {},
TWO: { deprecationReason: 'Some enum reason.' }
}
});

const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
normalField: {
args: {
enumArg: { type: enumType },
},
type: GraphQLString,
},
deprecatedField: {
type: GraphQLString,
deprecationReason: 'Some field reason.',
}
}
})
});

it('should report empty set for no deprecated usages', () => {
const errors = findDeprecatedUsages(
schema,
parse('{ normalField(enumArg: ONE) }')
);

expect(errors.length).to.equal(0);
});

it('should report usage of deprecated fields', () => {
const errors = findDeprecatedUsages(
schema,
parse('{ normalField, deprecatedField }')
);

const errorMessages = errors.map(err => err.message);

expect(errorMessages).to.deep.equal([
'The field Query.deprecatedField is deprecated. Some field reason.'
]);
});

it('should report usage of deprecated enums', () => {
const errors = findDeprecatedUsages(
schema,
parse('{ normalField(enumArg: TWO) }')
);

const errorMessages = errors.map(err => err.message);

expect(errorMessages).to.deep.equal([
'The enum value EnumType.TWO is deprecated. Some enum reason.'
]);
});

});
62 changes: 62 additions & 0 deletions src/utilities/findDeprecatedUsages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* @flow */
/**
* Copyright (c) Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

import { GraphQLError } from '../error/GraphQLError';
import { visit, visitWithTypeInfo } from '../language/visitor';
import type { DocumentNode } from '../language/ast';
import { getNamedType } from '../type/definition';
import { GraphQLSchema } from '../type/schema';
import { TypeInfo } from './TypeInfo';

/**
* A validation rule which reports deprecated usages.
*
* Returns a list of GraphQLError instances describing every deprecated use.
*/
export function findDeprecatedUsages(
schema: GraphQLSchema,
ast: DocumentNode,
): Array<GraphQLError> {
const errors = [];
const typeInfo = new TypeInfo(schema);

visit(ast, visitWithTypeInfo(typeInfo, {
Field(node) {
const fieldDef = typeInfo.getFieldDef();
if (fieldDef && fieldDef.isDeprecated) {
const parentType = typeInfo.getParentType();
if (parentType) {
const reason = fieldDef.deprecationReason;
errors.push(new GraphQLError(
`The field ${parentType.name}.${fieldDef.name} is deprecated.` +
(reason ? ' ' + reason : ''),
[ node ]
));
}
}
},
EnumValue(node) {
const enumVal = typeInfo.getEnumValue();
if (enumVal && enumVal.isDeprecated) {
const type = getNamedType(typeInfo.getInputType());
if (type) {
const reason = enumVal.deprecationReason;
errors.push(new GraphQLError(
`The enum value ${type.name}.${enumVal.name} is deprecated.` +
(reason ? ' ' + reason : ''),
[ node ]
));
}
}
}
}));

return errors;
}
3 changes: 3 additions & 0 deletions src/utilities/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,6 @@ export { assertValidName } from './assertValidName';
// Compares two GraphQLSchemas and detects breaking changes.
export { findBreakingChanges } from './findBreakingChanges';
export type { BreakingChange } from './findBreakingChanges';

// Report all deprecated usage within a GraphQL document.
export { findDeprecatedUsages } from './findDeprecatedUsages';

0 comments on commit 3adaaa4

Please sign in to comment.