Skip to content

Commit

Permalink
Rename GraphQLSchemaDirective to SchemaDirectiveVisitor.
Browse files Browse the repository at this point in the history
TODO(@benjamn): File a bug with VS Code because their class renaming
feature renamed `this` references in the static `create` method to
`SchemaDirectiveVisitor`, instead of leaving them alone. This broke some
tests because `this` is very much meant to refer to a subclass of
`SchemaDirectiveVisitor` within the `create` method.
  • Loading branch information
benjamn committed Mar 14, 2018
1 parent 866a7a5 commit af91add
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 50 deletions.
75 changes: 39 additions & 36 deletions src/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,37 +37,39 @@ export type VisitableType =

const hasOwn = Object.prototype.hasOwnProperty;

export class GraphQLSchemaDirective extends GraphQLDirective {
// Subclasses of GraphQLSchemaDirective should define their own static
export class SchemaDirectiveVisitor extends GraphQLDirective {
// Subclasses of SchemaDirectiveVisitor should define their own static
// .description property, which will be passed to the GraphQLDirective
// constructor by the static create method.
public static description: string;

// All GraphQLSchemaDirective instances are created while visiting a
// All SchemaDirectiveVisitor instances are created while visiting a
// specific GraphQLSchema object, and this property holds a reference to
// that object.
public schema: GraphQLSchema;

// Although you might think a GraphQLSchemaDirective subclass should also
// define an appropriate static .name property, that turns out not to be
// necessary, since the names of directives will be provided as keys of the
// directiveClasses object passed to visitSchema. In other words, directive
// implementations are effectively anonymous, and it's up to the caller of
// GraphQLSchemaDirective.visitSchema to assign names to them.
// Although you might think a SchemaDirectiveVisitor subclass should
// also define an appropriate static .name property, that turns out not
// to be necessary, since the names of directives will be provided as
// keys of the directiveClasses object passed to visitSchema. In other
// words, directive implementations are effectively anonymous, and it's
// up to the caller of SchemaDirectiveVisitor.visitSchema to assign
// names to them.

// Call GraphQLSchemaDirective.visitSchema(schema, directiveClasses) to
// Call SchemaDirectiveVisitor.visitSchema(schema, directiveClasses) to
// visit every @directive in the schema and instantiate an appropriate
// GraphQLSchemaDirective subclass to visit/handle/transform the object
// SchemaDirectiveVisitor subclass to visit/handle/transform the object
// decorated by the @directive.
public static visitSchema(
schema: GraphQLSchema,
directiveClasses: {
// Because a new GraphQLSchemaDirective class will be instantiated each
// time a specific directive is found in the schema AST, callers of the
// visitSchema method should provide GraphQLSchemaDirective sub*classes*
// rather than instances as the values in this object. The keys of the
// object correspond to directive names as they appear in the schema.
[name: string]: typeof GraphQLSchemaDirective
// Because a new SchemaDirectiveVisitor class will be instantiated
// each time a certain directive is found in the schema AST, callers
// of the visitSchema method should provide SchemaDirectiveVisitor
// sub*classes* rather than instances as the values in this object.
// The keys of the object correspond to directive names as they
// appear in the schema.
[name: string]: typeof SchemaDirectiveVisitor
},
) {
// If the schema declares any directives for public consumption, collect
Expand Down Expand Up @@ -140,14 +142,15 @@ export class GraphQLSchemaDirective extends GraphQLDirective {
});

// The GraphQL schema parser currently does not support @directive
// syntax for union member types, so there's no point visiting them
// here. That's a blessing in disguise, really, because the types
// returned from type.getTypes() are references to GraphQLObjectType
// objects defined elsewhere in the schema, which might already have
// directives of their own, so it would be tricky to prevent this loop
// from re-visiting those directives. If you really need to access the
// member types of a union, just implement a GraphQLSchemaDirective that
// overrides visitUnion, and call unionType.getTypes() yourself.
// syntax for union member types, so there's no point visiting
// them here. That's a blessing in disguise, really, because the
// types returned from type.getTypes() are references to
// GraphQLObjectType objects defined elsewhere in the schema,
// which might already have directives of their own, so it would
// be hard to prevent this loop from re-visiting those directives.
// If you really need to access the member types of a union, just
// implement a SchemaDirectiveVisitor that overrides visitUnion,
// and call unionType.getTypes() yourself.

// type.getTypes().forEach(visit);

Expand Down Expand Up @@ -199,8 +202,8 @@ export class GraphQLSchemaDirective extends GraphQLDirective {

// Given a schema type, returns an (often empty) array of directives that
// should be applied to the given type.
function getDirectives(type: VisitableType): GraphQLSchemaDirective[] {
const directiveInstances: GraphQLSchemaDirective[] = [];
function getDirectives(type: VisitableType): SchemaDirectiveVisitor[] {
const directiveInstances: SchemaDirectiveVisitor[] = [];
const directiveNodes = type.astNode && type.astNode.directives;
if (! directiveNodes) {
return directiveInstances;
Expand Down Expand Up @@ -229,9 +232,9 @@ export class GraphQLSchemaDirective extends GraphQLDirective {
});
}

// As described near the top of the visitSchema method, this is where
// instances of the GraphQLSchemaDirective class get created and
// assigned names.
// As described near the top of the visitSchema method, this is
// where instances of the SchemaDirectiveVisitor class get created
// and assigned names.
directiveInstances.push(
directiveClass.create(name, args, schema)
);
Expand All @@ -245,10 +248,10 @@ export class GraphQLSchemaDirective extends GraphQLDirective {
}

// The constructor method cannot access static members like .description
// because TypeScript doesn't understand this.constructor.description, and
// GraphQLSchemaDirective.description would be wrong for subclasses. Instead
// we define an inheritable static create method that returns new instances of
// whatever subclass this is.
// because TypeScript doesn't understand this.constructor.description,
// and SchemaDirectiveVisitor.description would be wrong for subclasses.
// Instead we define an inheritable static create method that returns
// new instances of whatever subclass this is.
public static create(
name: string,
args: GraphQLFieldConfigArgumentMap,
Expand Down Expand Up @@ -348,10 +351,10 @@ const methodToLocationMap: {
};

// Used to check that a visit* method is not an empty stub inherited from
// GraphQLSchemaDirective.prototype.
// SchemaDirectiveVisitor.prototype.
const visitMethodStubSet = new Set(
Object.keys(methodToLocationMap).map(
key => GraphQLSchemaDirective.prototype[key]
key => SchemaDirectiveVisitor.prototype[key]
)
);

Expand Down
4 changes: 2 additions & 2 deletions src/schemaGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {
GraphQLParseOptions,
} from './Interfaces';

import { GraphQLSchemaDirective } from './directives';
import { SchemaDirectiveVisitor } from './directives';
import { deprecated } from 'deprecated-decorator';
import mergeDeep from './mergeDeep';

Expand Down Expand Up @@ -143,7 +143,7 @@ function makeExecutableSchema<TContext = any>({
}

// Visit the schema without providing any directive implementations, yet.
GraphQLSchemaDirective.visitSchema(jsSchema, {});
SchemaDirectiveVisitor.visitSchema(jsSchema, {});

return jsSchema;
}
Expand Down
24 changes: 12 additions & 12 deletions src/test/testDirectives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
} from '../schemaGenerator';
import {
VisitableType,
GraphQLSchemaDirective,
SchemaDirectiveVisitor,
} from '../directives';
import {
GraphQLObjectType,
Expand Down Expand Up @@ -133,14 +133,14 @@ describe('@directives', () => {
checkDirectives(schema.getType('WhateverUnion'), ['unionDirective']);
});

it('can be implemented with GraphQLSchemaDirective', () => {
it('can be implemented with SchemaDirectiveVisitor', () => {
const visited: Set<GraphQLObjectType> = new Set;
const schema = makeExecutableSchema({ typeDefs });
let visitCount = 0;

GraphQLSchemaDirective.visitSchema(schema, {
SchemaDirectiveVisitor.visitSchema(schema, {
// The directive subclass can be defined anonymously inline!
queryTypeDirective: class extends GraphQLSchemaDirective {
queryTypeDirective: class extends SchemaDirectiveVisitor {
public static description = 'A @directive for query object types';
public visitObject(object: GraphQLObjectType) {
visited.add(object);
Expand All @@ -164,15 +164,15 @@ describe('@directives', () => {
let enumObjectType: GraphQLEnumType;
let inputObjectType: GraphQLInputObjectType;

GraphQLSchemaDirective.visitSchema(schema, {
mutationTypeDirective: class extends GraphQLSchemaDirective {
SchemaDirectiveVisitor.visitSchema(schema, {
mutationTypeDirective: class extends SchemaDirectiveVisitor {
public visitObject(object: GraphQLObjectType) {
mutationObjectType = object;
assert.strictEqual(object.name, 'Mutation');
}
},

mutationMethodDirective: class extends GraphQLSchemaDirective {
mutationMethodDirective: class extends SchemaDirectiveVisitor {
public visitFieldDefinition(field: GraphQLField<any, any>, details: {
objectType: GraphQLObjectType,
}) {
Expand All @@ -183,7 +183,7 @@ describe('@directives', () => {
}
},

mutationArgumentDirective: class extends GraphQLSchemaDirective {
mutationArgumentDirective: class extends SchemaDirectiveVisitor {
public visitArgumentDefinition(arg: GraphQLArgument, details: {
field: GraphQLField<any, any>,
objectType: GraphQLObjectType,
Expand All @@ -195,14 +195,14 @@ describe('@directives', () => {
}
},

enumTypeDirective: class extends GraphQLSchemaDirective {
enumTypeDirective: class extends SchemaDirectiveVisitor {
public visitEnum(enumType: GraphQLEnumType) {
assert.strictEqual(enumType.name, 'Gender');
enumObjectType = enumType;
}
},

enumValueDirective: class extends GraphQLSchemaDirective {
enumValueDirective: class extends SchemaDirectiveVisitor {
public visitEnumValue(value: GraphQLEnumValue, details: {
enumType: GraphQLEnumType,
}) {
Expand All @@ -212,14 +212,14 @@ describe('@directives', () => {
}
},

inputTypeDirective: class extends GraphQLSchemaDirective {
inputTypeDirective: class extends SchemaDirectiveVisitor {
public visitInputObject(object: GraphQLInputObjectType) {
inputObjectType = object;
assert.strictEqual(object.name, 'PersonInput');
}
},

inputFieldDirective: class extends GraphQLSchemaDirective {
inputFieldDirective: class extends SchemaDirectiveVisitor {
public visitInputFieldDefinition(field: GraphQLInputField, details: {
objectType: GraphQLInputObjectType,
}) {
Expand Down

0 comments on commit af91add

Please sign in to comment.