Skip to content

Commit

Permalink
Merging #1173, fixes tests
Browse files Browse the repository at this point in the history
  • Loading branch information
leebyron committed Dec 20, 2017
1 parent f4047b7 commit 637ee10
Show file tree
Hide file tree
Showing 11 changed files with 55 additions and 39 deletions.
1 change: 0 additions & 1 deletion src/language/__tests__/schema-parser-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,6 @@ type Hello {
{
kind: 'ScalarTypeDefinition',
name: nameNode('Hello', { start: 7, end: 12 }),
type: null,
directives: [],
loc: { start: 0, end: 12 },
},
Expand Down
2 changes: 1 addition & 1 deletion src/language/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ export type ScalarTypeDefinitionNode = {
+loc?: Location,
+description?: StringValueNode,
+name: NameNode,
+type?: NamedTypeNode;
+type?: NamedTypeNode,
+directives?: $ReadOnlyArray<DirectiveNode>,
};

Expand Down
7 changes: 5 additions & 2 deletions src/language/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,12 @@ const printDocASTReducer = {

OperationTypeDefinition: ({ operation, type }) => operation + ': ' + type,

ScalarTypeDefinition: ({ description, name, directives }) =>
ScalarTypeDefinition: ({ description, name, type, directives }) =>
join(
[description, join(['scalar', name, wrap(' as ', type), join(directives, ' ')], ' ')],
[
description,
join(['scalar', name, wrap('as ', type), join(directives, ' ')], ' '),
],
'\n',
),

Expand Down
2 changes: 1 addition & 1 deletion src/type/__tests__/introspection-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,7 @@ describe('Introspection', () => {
description:
'Indicates this type is a scalar. ' +
'`ofType` may represent how this scalar is serialized.',
name: 'SCALAR'
name: 'SCALAR',
},
{
description:
Expand Down
19 changes: 5 additions & 14 deletions src/type/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,18 +461,6 @@ export class GraphQLScalarType {
this.astNode = config.astNode;
this._scalarConfig = config;
invariant(typeof config.name === 'string', 'Must provide name.');
if (this.ofType) {
const ofTypeName = this.ofType.name;
invariant(
ofTypeName === 'String' ||
ofTypeName === 'Int' ||
ofTypeName === 'Float' ||
ofTypeName === 'Boolean' ||
ofTypeName === 'ID',
`${this.name} may only be described in terms of a built-in scalar ` +
`type. However ${ofTypeName} is not a built-in scalar type.`
);
}
invariant(
typeof config.serialize === 'function',
`${this.name} must provide "serialize" function. If this custom Scalar ` +
Expand All @@ -498,7 +486,8 @@ export class GraphQLScalarType {

// Parses an externally provided value to use as an input.
parseValue(value: mixed): mixed {
const parser = this._scalarConfig.parseValue || (this.ofType && this.ofType.parseValue);
const parser =
this._scalarConfig.parseValue || (this.ofType && this.ofType.parseValue);
if (isInvalid(value)) {
return undefined;
}
Expand All @@ -507,7 +496,9 @@ export class GraphQLScalarType {

// Parses an externally provided literal value to use as an input.
parseLiteral(valueNode: ValueNode, variables: ?ObjMap<mixed>): mixed {
const parser = this._scalarConfig.parseLiteral || (this.ofType && this.ofType.parseLiteral);
const parser =
this._scalarConfig.parseLiteral ||
(this.ofType && this.ofType.parseLiteral);
return parser
? parser(valueNode, variables)
: valueFromASTUntyped(valueNode, variables);
Expand Down
2 changes: 1 addition & 1 deletion src/type/introspection.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ export const __Type = new GraphQLObjectType({
'The fundamental unit of any GraphQL Schema is the type. There are ' +
'many kinds of types in GraphQL as represented by the `__TypeKind` enum.' +
'\n\nDepending on the kind of a type, certain fields describe ' +
'information about that type. Scalar types provide a name, description' +
'information about that type. Scalar types provide a name, description ' +
'and how they serialize, while Enum types provide their possible values. ' +
'Object and Interface types provide the fields they describe. Abstract ' +
'types, Union and Interface, provide the Object types possible ' +
Expand Down
22 changes: 21 additions & 1 deletion src/type/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import {
isScalarType,
isObjectType,
isInterfaceType,
isUnionType,
Expand All @@ -19,6 +20,7 @@ import {
isOutputType,
} from './definition';
import type {
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
Expand All @@ -28,6 +30,7 @@ import type {
import { isDirective } from './directives';
import type { GraphQLDirective } from './directives';
import { isIntrospectionType } from './introspection';
import { isSpecifiedScalarType } from './scalars';
import { isSchema } from './schema';
import type { GraphQLSchema } from './schema';
import find from '../jsutils/find';
Expand Down Expand Up @@ -239,7 +242,10 @@ function validateTypes(context: SchemaValidationContext): void {
// Ensure they are named correctly.
validateName(context, type);

if (isObjectType(type)) {
if (isScalarType(type)) {
// Ensure Scalars can serialize as expected.
validateScalarSerialization(context, type);
} else if (isObjectType(type)) {
// Ensure fields are valid
validateFields(context, type);

Expand All @@ -261,6 +267,20 @@ function validateTypes(context: SchemaValidationContext): void {
});
}

function validateScalarSerialization(
context: SchemaValidationContext,
scalarType: GraphQLScalarType,
): void {
if (scalarType.ofType && !isSpecifiedScalarType(scalarType.ofType)) {
context.reportError(
`Scalar type ${scalarType.name} may only be described in terms of a ` +
`spec-defined scalar type. However ${String(scalarType.ofType)} is ` +
'not a built-in scalar type.',
scalarType.astNode && scalarType.astNode.type,
);
}
}

function validateFields(
context: SchemaValidationContext,
type: GraphQLObjectType | GraphQLInterfaceType,
Expand Down
18 changes: 10 additions & 8 deletions src/utilities/__tests__/schemaPrinter-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ describe('Type System Printer', () => {
ofType: GraphQLInt,
serialize(value) {
return value % 2 === 1 ? value : null;
}
},
});

const OddType = new GraphQLScalarType({
Expand Down Expand Up @@ -793,10 +793,10 @@ describe('Type System Printer', () => {
types in GraphQL as represented by the \`__TypeKind\` enum.
Depending on the kind of a type, certain fields describe information about that
type. Scalar types provide no information beyond a name and description, while
Enum types provide their values. Object and Interface types provide the fields
they describe. Abstract types, Union and Interface, provide the Object types
possible at runtime. List and NonNull types compose other types.
type. Scalar types provide a name, description and how they serialize, while
Enum types provide their possible values. Object and Interface types provide the
fields they describe. Abstract types, Union and Interface, provide the Object
types possible at runtime. List and NonNull types compose other types.
"""
type __Type {
kind: __TypeKind!
Expand All @@ -812,7 +812,9 @@ describe('Type System Printer', () => {
"""An enum describing what kind of type a given \`__Type\` is."""
enum __TypeKind {
"""Indicates this type is a scalar."""
"""
Indicates this type is a scalar. \`ofType\` may represent how this scalar is serialized.
"""
SCALAR
"""
Expand Down Expand Up @@ -1013,8 +1015,8 @@ describe('Type System Printer', () => {
# types in GraphQL as represented by the \`__TypeKind\` enum.
#
# Depending on the kind of a type, certain fields describe information about that
# type. Scalar types provide a name, descriptionand how they serialize, while Enum
# types provide their possible values. Object and Interface types provide the
# type. Scalar types provide a name, description and how they serialize, while
# Enum types provide their possible values. Object and Interface types provide the
# fields they describe. Abstract types, Union and Interface, provide the Object
# types possible at runtime. List and NonNull types compose other types.
type __Type {
Expand Down
5 changes: 4 additions & 1 deletion src/utilities/buildASTSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,10 @@ export class ASTDefinitionBuilder {
return new GraphQLScalarType({
name: def.name.value,
description: getDescription(def, this._options),
ofType: def.type && this.buildType(def.type),
// Note: While this could make assertions to get the correctly typed
// values below, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
ofType: def.type && (this.buildType(def.type): any),
astNode: def,
serialize: value => value,
});
Expand Down
6 changes: 3 additions & 3 deletions src/utilities/buildClientSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,9 @@ export function buildClientSchema(
function buildScalarDef(
scalarIntrospection: IntrospectionScalarType,
): GraphQLScalarType {
const ofType = scalarIntrospection.ofType ?
getType(scalarIntrospection.ofType) :
undefined;
const ofType = scalarIntrospection.ofType
? (getType(scalarIntrospection.ofType): any)
: undefined;
return new GraphQLScalarType({
name: scalarIntrospection.name,
description: scalarIntrospection.description,
Expand Down
10 changes: 4 additions & 6 deletions src/utilities/findBreakingChanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,16 @@ export function findTypesThatChangedKind(
`${typeName} changed from ` +
`${typeKindName(oldType)} to ${typeKindName(newType)}.`,
});
} else if (
oldType instanceof GraphQLScalarType &&
newType instanceof GraphQLScalarType
) {
} else if (isScalarType(oldType) && isScalarType(newType)) {
const oldOfType = oldType.ofType;
const newOfType = newType.ofType;
if (oldOfType && newOfType && oldOfType !== newOfType) {
breakingChanges.push({
type: BreakingChangeType.TYPE_CHANGED_KIND,
description: `${typeName} changed from ` +
description:
`${typeName} changed from ` +
`${typeKindName(oldType)} serialized as ${oldOfType.name} ` +
`to ${typeKindName(newType)} serialized as ${newOfType.name}.`
`to ${typeKindName(newType)} serialized as ${newOfType.name}.`,
});
}
}
Expand Down

0 comments on commit 637ee10

Please # to comment.