88 */
99
1010import inspect from '../jsutils/inspect' ;
11+ import isFinite from '../jsutils/isFinite' ;
1112import isInteger from '../jsutils/isInteger' ;
1213import { GraphQLScalarType , isNamedType } from './definition' ;
1314import { Kind } from '../language/kinds' ;
@@ -20,38 +21,46 @@ import { Kind } from '../language/kinds';
2021const MAX_INT = 2147483647 ;
2122const MIN_INT = - 2147483648 ;
2223
23- function coerceInt ( value : mixed ) : number {
24+ function serializeInt ( value : mixed ) : number {
2425 if ( Array . isArray ( value ) ) {
2526 throw new TypeError (
26- `Int cannot represent an array value: [ ${ String ( value ) } ] ` ,
27+ `Int cannot represent an array value: ${ inspect ( value ) } ` ,
2728 ) ;
2829 }
29- if ( value === '' ) {
30+ const num = Number ( value ) ;
31+ if ( value === '' || ! isInteger ( num ) ) {
3032 throw new TypeError (
31- ' Int cannot represent non-integer value: (empty string)' ,
33+ ` Int cannot represent non-integer value: ${ inspect ( value ) } ` ,
3234 ) ;
3335 }
34- const num = Number ( value ) ;
35- if ( ! isInteger ( num ) ) {
36+ if ( num > MAX_INT || num < MIN_INT ) {
3637 throw new TypeError (
37- ' Int cannot represent non- integer value: ' + inspect ( value ) ,
38+ ` Int cannot represent non 32-bit signed integer value: ${ inspect ( value ) } ` ,
3839 ) ;
3940 }
41+ return num ;
42+ }
4043
41- if ( num > MAX_INT || num < MIN_INT ) {
44+ function coerceInt ( value : mixed ) : number {
45+ if ( ! isInteger ( value ) ) {
4246 throw new TypeError (
43- ' Int cannot represent non 32-bit signed integer value: ' + inspect ( value ) ,
47+ ` Int cannot represent non- integer value: ${ inspect ( value ) } ` ,
4448 ) ;
4549 }
46- return num ;
50+ if ( value > MAX_INT || value < MIN_INT ) {
51+ throw new TypeError (
52+ `Int cannot represent non 32-bit signed integer value: ${ inspect ( value ) } ` ,
53+ ) ;
54+ }
55+ return value ;
4756}
4857
4958export const GraphQLInt = new GraphQLScalarType ( {
5059 name : 'Int' ,
5160 description :
5261 'The `Int` scalar type represents non-fractional signed whole numeric ' +
5362 'values. Int can represent values between -(2^31) and 2^31 - 1. ' ,
54- serialize : coerceInt ,
63+ serialize : serializeInt ,
5564 parseValue : coerceInt ,
5665 parseLiteral ( ast ) {
5766 if ( ast . kind === Kind . INT ) {
@@ -64,24 +73,28 @@ export const GraphQLInt = new GraphQLScalarType({
6473 } ,
6574} ) ;
6675
67- function coerceFloat ( value : mixed ) : number {
76+ function serializeFloat ( value : mixed ) : number {
6877 if ( Array . isArray ( value ) ) {
6978 throw new TypeError (
70- `Float cannot represent an array value: [ ${ String ( value ) } ] ` ,
79+ `Float cannot represent an array value: ${ inspect ( value ) } ` ,
7180 ) ;
7281 }
73- if ( value === '' ) {
82+ const num = Number ( value ) ;
83+ if ( value === '' || ! isFinite ( num ) ) {
7484 throw new TypeError (
75- ' Float cannot represent non numeric value: (empty string)' ,
85+ ` Float cannot represent non numeric value: ${ inspect ( value ) } ` ,
7686 ) ;
7787 }
78- const num = Number ( value ) ;
79- if ( isFinite ( num ) ) {
80- return num ;
88+ return num ;
89+ }
90+
91+ function coerceFloat ( value : mixed ) : number {
92+ if ( ! isFinite ( value ) ) {
93+ throw new TypeError (
94+ `Float cannot represent non numeric value: ${ inspect ( value ) } ` ,
95+ ) ;
8196 }
82- throw new TypeError (
83- 'Float cannot represent non numeric value: ' + inspect ( value ) ,
84- ) ;
97+ return value ;
8598}
8699
87100export const GraphQLFloat = new GraphQLScalarType ( {
@@ -90,7 +103,7 @@ export const GraphQLFloat = new GraphQLScalarType({
90103 'The `Float` scalar type represents signed double-precision fractional ' +
91104 'values as specified by ' +
92105 '[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ' ,
93- serialize : coerceFloat ,
106+ serialize : serializeFloat ,
94107 parseValue : coerceFloat ,
95108 parseLiteral ( ast ) {
96109 return ast . kind === Kind . FLOAT || ast . kind === Kind . INT
@@ -99,7 +112,7 @@ export const GraphQLFloat = new GraphQLScalarType({
99112 } ,
100113} ) ;
101114
102- function coerceString ( value : mixed ) : string {
115+ function serializeString ( value : mixed ) : string {
103116 if ( Array . isArray ( value ) ) {
104117 throw new TypeError (
105118 `String cannot represent an array value: ${ inspect ( value ) } ` ,
@@ -108,38 +121,81 @@ function coerceString(value: mixed): string {
108121 return String ( value ) ;
109122}
110123
124+ function coerceString ( value : mixed ) : string {
125+ if ( typeof value !== 'string' ) {
126+ throw new TypeError (
127+ `String cannot represent a non string value: ${ inspect ( value ) } ` ,
128+ ) ;
129+ }
130+ return value ;
131+ }
132+
111133export const GraphQLString = new GraphQLScalarType ( {
112134 name : 'String' ,
113135 description :
114136 'The `String` scalar type represents textual data, represented as UTF-8 ' +
115137 'character sequences. The String type is most often used by GraphQL to ' +
116138 'represent free-form human-readable text.' ,
117- serialize : coerceString ,
139+ serialize : serializeString ,
118140 parseValue : coerceString ,
119141 parseLiteral ( ast ) {
120142 return ast . kind === Kind . STRING ? ast . value : undefined ;
121143 } ,
122144} ) ;
123145
124- function coerceBoolean ( value : mixed ) : boolean {
146+ function serializeBoolean ( value : mixed ) : boolean {
125147 if ( Array . isArray ( value ) ) {
126148 throw new TypeError (
127- `Boolean cannot represent an array value: [ ${ String ( value ) } ] ` ,
149+ `Boolean cannot represent an array value: ${ inspect ( value ) } ` ,
128150 ) ;
129151 }
130152 return Boolean ( value ) ;
131153}
132154
155+ function coerceBoolean ( value : mixed ) : boolean {
156+ if ( typeof value !== 'boolean' ) {
157+ throw new TypeError (
158+ `Boolean cannot represent a non boolean value: ${ inspect ( value ) } ` ,
159+ ) ;
160+ }
161+ return value ;
162+ }
163+
133164export const GraphQLBoolean = new GraphQLScalarType ( {
134165 name : 'Boolean' ,
135166 description : 'The `Boolean` scalar type represents `true` or `false`.' ,
136- serialize : coerceBoolean ,
167+ serialize : serializeBoolean ,
137168 parseValue : coerceBoolean ,
138169 parseLiteral ( ast ) {
139170 return ast . kind === Kind . BOOLEAN ? ast . value : undefined ;
140171 } ,
141172} ) ;
142173
174+ function serializeID ( value : mixed ) : string {
175+ // Support serializing objects with custom valueOf() functions - a common way
176+ // to represent an object identifier.
177+ const result = value && value . valueOf !== Object . prototype . valueOf
178+ ? value . valueOf ( )
179+ : value ;
180+ if (
181+ typeof result !== 'string' &&
182+ ( typeof result !== 'number' || ! isInteger ( result ) )
183+ ) {
184+ throw new TypeError ( `ID cannot represent value: ${ inspect ( value ) } ` ) ;
185+ }
186+ return String ( result ) ;
187+ }
188+
189+ function coerceID ( value : mixed ) : string {
190+ if (
191+ typeof value !== 'string' &&
192+ ( typeof value !== 'number' || ! isInteger ( value ) )
193+ ) {
194+ throw new TypeError ( `ID cannot represent value: ${ inspect ( value ) } ` ) ;
195+ }
196+ return String ( value ) ;
197+ }
198+
143199export const GraphQLID = new GraphQLScalarType ( {
144200 name : 'ID' ,
145201 description :
@@ -148,8 +204,8 @@ export const GraphQLID = new GraphQLScalarType({
148204 'response as a String; however, it is not intended to be human-readable. ' +
149205 'When expected as an input type, any string (such as `"4"`) or integer ' +
150206 '(such as `4`) input value will be accepted as an ID.' ,
151- serialize : coerceString ,
152- parseValue : coerceString ,
207+ serialize : serializeID ,
208+ parseValue : coerceID ,
153209 parseLiteral ( ast ) {
154210 return ast . kind === Kind . STRING || ast . kind === Kind . INT
155211 ? ast . value
0 commit comments