Skip to content

Commit

Permalink
Add @specified directive
Browse files Browse the repository at this point in the history
This in an implementation for a spec proposal:

* Spec proposal: [[RFC] Custom Scalar Specification URIs](graphql/graphql-spec#649)
* Original issue: [[RFC] Custom Scalar Specification URIs](graphql/graphql-spec#635)

Please let me know if I forgot something.
  • Loading branch information
m14t committed Dec 6, 2019
1 parent 61a07b1 commit 2e9ca2e
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 6 deletions.
19 changes: 19 additions & 0 deletions src/type/__tests__/introspection-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,25 @@ describe('Introspection', () => {
},
],
},
{
name: 'specified',
locations: ['FIELD_DEFINITION'],
args: [
{
defaultValue: null,
name: 'by',
type: {
kind: 'NON_NULL',
name: null,
ofType: {
kind: 'SCALAR',
name: 'String',
ofType: null,
},
},
},
],
},
{
name: 'deprecated',
locations: ['FIELD_DEFINITION', 'ENUM_VALUE'],
Expand Down
6 changes: 6 additions & 0 deletions src/type/directives.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ export const GraphQLIncludeDirective: GraphQLDirective;
*/
export const GraphQLSkipDirective: GraphQLDirective;

/**
* Used to provide an RFC3986-compliant URI for specifying the behaviour of
* custom scalar definitions.
*/
export const GraphQLSpecifiedDirective: GraphQLDirective;

/**
* Constant string used for default reason for a deprecation.
*/
Expand Down
19 changes: 19 additions & 0 deletions src/type/directives.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,24 @@ export const GraphQLSkipDirective = new GraphQLDirective({
},
});

/**
* Used to provide an RFC3986-compliant URI for specifying the behaviour of
* custom scalar definitions.
*/
export const GraphQLSpecifiedDirective = new GraphQLDirective({
name: 'specified',
description:
'Exposes a RFC3986-compliant URI that specifies the behaviour of this scalar.',
locations: [DirectiveLocation.FIELD_DEFINITION],
args: {
by: {
type: GraphQLNonNull(GraphQLString),
description:
'The RFC3986-compliant URI that specifies the behaviour of this scalar.',
},
},
});

/**
* Constant string used for default reason for a deprecation.
*/
Expand Down Expand Up @@ -195,6 +213,7 @@ export const GraphQLDeprecatedDirective = new GraphQLDirective({
export const specifiedDirectives = Object.freeze([
GraphQLIncludeDirective,
GraphQLSkipDirective,
GraphQLSpecifiedDirective,
GraphQLDeprecatedDirective,
]);

Expand Down
19 changes: 14 additions & 5 deletions src/utilities/__tests__/buildASTSchema-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
assertDirective,
GraphQLSkipDirective,
GraphQLIncludeDirective,
GraphQLSpecifiedDirective,
GraphQLDeprecatedDirective,
} from '../../type/directives';
import {
Expand Down Expand Up @@ -182,12 +183,15 @@ describe('Schema Builder', () => {
expect(cycleSDL(sdl, { commentDescriptions: true })).to.equal(sdl);
});

it('Maintains @skip & @include', () => {
it('Maintains @include, @skip & @specified', () => {
const schema = buildSchema('type Query');

expect(schema.getDirectives()).to.have.lengthOf(3);
expect(schema.getDirectives()).to.have.lengthOf(4);
expect(schema.getDirective('skip')).to.equal(GraphQLSkipDirective);
expect(schema.getDirective('include')).to.equal(GraphQLIncludeDirective);
expect(schema.getDirective('specified')).to.equal(
GraphQLSpecifiedDirective,
);
expect(schema.getDirective('deprecated')).to.equal(
GraphQLDeprecatedDirective,
);
Expand All @@ -197,27 +201,32 @@ describe('Schema Builder', () => {
const schema = buildSchema(`
directive @skip on FIELD
directive @include on FIELD
directive @specified on FIELD_DEFINITION
directive @deprecated on FIELD_DEFINITION
`);

expect(schema.getDirectives()).to.have.lengthOf(3);
expect(schema.getDirectives()).to.have.lengthOf(4);
expect(schema.getDirective('skip')).to.not.equal(GraphQLSkipDirective);
expect(schema.getDirective('include')).to.not.equal(
GraphQLIncludeDirective,
);
expect(schema.getDirective('specified')).to.not.equal(
GraphQLSpecifiedDirective,
);
expect(schema.getDirective('deprecated')).to.not.equal(
GraphQLDeprecatedDirective,
);
});

it('Adding directives maintains @skip & @include', () => {
it('Adding directives maintains @include, @skip & @specified', () => {
const schema = buildSchema(`
directive @foo(arg: Int) on FIELD
`);

expect(schema.getDirectives()).to.have.lengthOf(4);
expect(schema.getDirectives()).to.have.lengthOf(5);
expect(schema.getDirective('skip')).to.not.equal(undefined);
expect(schema.getDirective('include')).to.not.equal(undefined);
expect(schema.getDirective('specified')).to.not.equal(undefined);
expect(schema.getDirective('deprecated')).to.not.equal(undefined);
});

Expand Down
7 changes: 6 additions & 1 deletion src/utilities/__tests__/findBreakingChanges-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { GraphQLSchema } from '../../type/schema';
import {
GraphQLSkipDirective,
GraphQLIncludeDirective,
GraphQLSpecifiedDirective,
GraphQLDeprecatedDirective,
} from '../../type/directives';

Expand Down Expand Up @@ -790,7 +791,11 @@ describe('findBreakingChanges', () => {
const oldSchema = new GraphQLSchema({});

const newSchema = new GraphQLSchema({
directives: [GraphQLSkipDirective, GraphQLIncludeDirective],
directives: [
GraphQLSkipDirective,
GraphQLIncludeDirective,
GraphQLSpecifiedDirective,
],
});

expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([
Expand Down
14 changes: 14 additions & 0 deletions src/utilities/__tests__/schemaPrinter-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,14 @@ describe('Type System Printer', () => {
if: Boolean!
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"""
Exposes a RFC3986-compliant URI that specifies the behaviour of this scalar.
"""
directive @specified(
"""The RFC3986-compliant URI that specifies the behaviour of this scalar."""
by: String!
) on FIELD_DEFINITION
"""Marks an element of a GraphQL schema as no longer supported."""
directive @deprecated(
"""
Expand Down Expand Up @@ -803,6 +811,12 @@ describe('Type System Printer', () => {
if: Boolean!
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
# Exposes a RFC3986-compliant URI that specifies the behaviour of this scalar.
directive @specified(
# The RFC3986-compliant URI that specifies the behaviour of this scalar.
by: String!
) on FIELD_DEFINITION
# Marks an element of a GraphQL schema as no longer supported.
directive @deprecated(
# Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax (as specified by [CommonMark](https://commonmark.org/).
Expand Down
5 changes: 5 additions & 0 deletions src/utilities/buildASTSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
GraphQLSkipDirective,
GraphQLIncludeDirective,
GraphQLDeprecatedDirective,
GraphQLSpecifiedDirective,
} from '../type/directives';
import {
type GraphQLType,
Expand Down Expand Up @@ -170,6 +171,10 @@ export function buildASTSchema(
directives.push(GraphQLIncludeDirective);
}

if (!directives.some(directive => directive.name === 'specified')) {
directives.push(GraphQLSpecifiedDirective);
}

if (!directives.some(directive => directive.name === 'deprecated')) {
directives.push(GraphQLDeprecatedDirective);
}
Expand Down

0 comments on commit 2e9ca2e

Please sign in to comment.