8
8
*/
9
9
10
10
import inspect from '../jsutils/inspect' ;
11
+ import isFinite from '../jsutils/isFinite' ;
11
12
import isInteger from '../jsutils/isInteger' ;
12
13
import { GraphQLScalarType , isNamedType } from './definition' ;
13
14
import { Kind } from '../language/kinds' ;
@@ -20,38 +21,46 @@ import { Kind } from '../language/kinds';
20
21
const MAX_INT = 2147483647 ;
21
22
const MIN_INT = - 2147483648 ;
22
23
23
- function coerceInt ( value : mixed ) : number {
24
+ function serializeInt ( value : mixed ) : number {
24
25
if ( Array . isArray ( value ) ) {
25
26
throw new TypeError (
26
- `Int cannot represent an array value: [ ${ String ( value ) } ] ` ,
27
+ `Int cannot represent an array value: ${ inspect ( value ) } ` ,
27
28
) ;
28
29
}
29
- if ( value === '' ) {
30
+ const num = Number ( value ) ;
31
+ if ( value === '' || ! isInteger ( num ) ) {
30
32
throw new TypeError (
31
- ' Int cannot represent non-integer value: (empty string)' ,
33
+ ` Int cannot represent non-integer value: ${ inspect ( value ) } ` ,
32
34
) ;
33
35
}
34
- const num = Number ( value ) ;
35
- if ( ! isInteger ( num ) ) {
36
+ if ( num > MAX_INT || num < MIN_INT ) {
36
37
throw new TypeError (
37
- ' Int cannot represent non- integer value: ' + inspect ( value ) ,
38
+ ` Int cannot represent non 32-bit signed integer value: ${ inspect ( value ) } ` ,
38
39
) ;
39
40
}
41
+ return num ;
42
+ }
40
43
41
- if ( num > MAX_INT || num < MIN_INT ) {
44
+ function coerceInt ( value : mixed ) : number {
45
+ if ( ! isInteger ( value ) ) {
42
46
throw new TypeError (
43
- ' Int cannot represent non 32-bit signed integer value: ' + inspect ( value ) ,
47
+ ` Int cannot represent non- integer value: ${ inspect ( value ) } ` ,
44
48
) ;
45
49
}
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 ;
47
56
}
48
57
49
58
export const GraphQLInt = new GraphQLScalarType ( {
50
59
name : 'Int' ,
51
60
description :
52
61
'The `Int` scalar type represents non-fractional signed whole numeric ' +
53
62
'values. Int can represent values between -(2^31) and 2^31 - 1. ' ,
54
- serialize : coerceInt ,
63
+ serialize : serializeInt ,
55
64
parseValue : coerceInt ,
56
65
parseLiteral ( ast ) {
57
66
if ( ast . kind === Kind . INT ) {
@@ -64,24 +73,28 @@ export const GraphQLInt = new GraphQLScalarType({
64
73
} ,
65
74
} ) ;
66
75
67
- function coerceFloat ( value : mixed ) : number {
76
+ function serializeFloat ( value : mixed ) : number {
68
77
if ( Array . isArray ( value ) ) {
69
78
throw new TypeError (
70
- `Float cannot represent an array value: [ ${ String ( value ) } ] ` ,
79
+ `Float cannot represent an array value: ${ inspect ( value ) } ` ,
71
80
) ;
72
81
}
73
- if ( value === '' ) {
82
+ const num = Number ( value ) ;
83
+ if ( value === '' || ! isFinite ( num ) ) {
74
84
throw new TypeError (
75
- ' Float cannot represent non numeric value: (empty string)' ,
85
+ ` Float cannot represent non numeric value: ${ inspect ( value ) } ` ,
76
86
) ;
77
87
}
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
+ ) ;
81
96
}
82
- throw new TypeError (
83
- 'Float cannot represent non numeric value: ' + inspect ( value ) ,
84
- ) ;
97
+ return value ;
85
98
}
86
99
87
100
export const GraphQLFloat = new GraphQLScalarType ( {
@@ -90,7 +103,7 @@ export const GraphQLFloat = new GraphQLScalarType({
90
103
'The `Float` scalar type represents signed double-precision fractional ' +
91
104
'values as specified by ' +
92
105
'[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ' ,
93
- serialize : coerceFloat ,
106
+ serialize : serializeFloat ,
94
107
parseValue : coerceFloat ,
95
108
parseLiteral ( ast ) {
96
109
return ast . kind === Kind . FLOAT || ast . kind === Kind . INT
@@ -99,13 +112,31 @@ export const GraphQLFloat = new GraphQLScalarType({
99
112
} ,
100
113
} ) ;
101
114
115
+ function serializeString ( value : mixed ) : string {
116
+ // Support serializing objects with custom valueOf() functions - a common way
117
+ // to represent an complex value which can be represented as a string
118
+ // (ex: MongoDB id objects).
119
+ const result =
120
+ value && typeof value . valueOf === 'function' ? value . valueOf ( ) : value ;
121
+ // Serialize string, number, and boolean values to a string, but do not
122
+ // attempt to coerce object, function, symbol, or other types as strings.
123
+ if (
124
+ typeof result !== 'string' &&
125
+ typeof result !== 'number' &&
126
+ typeof result !== 'boolean'
127
+ ) {
128
+ throw new TypeError ( `String cannot represent value: ${ inspect ( result ) } ` ) ;
129
+ }
130
+ return String ( result ) ;
131
+ }
132
+
102
133
function coerceString ( value : mixed ) : string {
103
- if ( Array . isArray ( value ) ) {
134
+ if ( typeof value !== 'string' ) {
104
135
throw new TypeError (
105
- `String cannot represent an array value: ${ inspect ( value ) } ` ,
136
+ `String cannot represent a non string value: ${ inspect ( value ) } ` ,
106
137
) ;
107
138
}
108
- return String ( value ) ;
139
+ return value ;
109
140
}
110
141
111
142
export const GraphQLString = new GraphQLScalarType ( {
@@ -114,32 +145,65 @@ export const GraphQLString = new GraphQLScalarType({
114
145
'The `String` scalar type represents textual data, represented as UTF-8 ' +
115
146
'character sequences. The String type is most often used by GraphQL to ' +
116
147
'represent free-form human-readable text.' ,
117
- serialize : coerceString ,
148
+ serialize : serializeString ,
118
149
parseValue : coerceString ,
119
150
parseLiteral ( ast ) {
120
151
return ast . kind === Kind . STRING ? ast . value : undefined ;
121
152
} ,
122
153
} ) ;
123
154
124
- function coerceBoolean ( value : mixed ) : boolean {
155
+ function serializeBoolean ( value : mixed ) : boolean {
125
156
if ( Array . isArray ( value ) ) {
126
157
throw new TypeError (
127
- `Boolean cannot represent an array value: [ ${ String ( value ) } ] ` ,
158
+ `Boolean cannot represent an array value: ${ inspect ( value ) } ` ,
128
159
) ;
129
160
}
130
161
return Boolean ( value ) ;
131
162
}
132
163
164
+ function coerceBoolean ( value : mixed ) : boolean {
165
+ if ( typeof value !== 'boolean' ) {
166
+ throw new TypeError (
167
+ `Boolean cannot represent a non boolean value: ${ inspect ( value ) } ` ,
168
+ ) ;
169
+ }
170
+ return value ;
171
+ }
172
+
133
173
export const GraphQLBoolean = new GraphQLScalarType ( {
134
174
name : 'Boolean' ,
135
175
description : 'The `Boolean` scalar type represents `true` or `false`.' ,
136
- serialize : coerceBoolean ,
176
+ serialize : serializeBoolean ,
137
177
parseValue : coerceBoolean ,
138
178
parseLiteral ( ast ) {
139
179
return ast . kind === Kind . BOOLEAN ? ast . value : undefined ;
140
180
} ,
141
181
} ) ;
142
182
183
+ function serializeID ( value : mixed ) : string {
184
+ // Support serializing objects with custom valueOf() functions - a common way
185
+ // to represent an object identifier (ex. MongoDB).
186
+ const result =
187
+ value && typeof value . valueOf === 'function' ? value . valueOf ( ) : value ;
188
+ if (
189
+ typeof result !== 'string' &&
190
+ ( typeof result !== 'number' || ! isInteger ( result ) )
191
+ ) {
192
+ throw new TypeError ( `ID cannot represent value: ${ inspect ( value ) } ` ) ;
193
+ }
194
+ return String ( result ) ;
195
+ }
196
+
197
+ function coerceID ( value : mixed ) : string {
198
+ if (
199
+ typeof value !== 'string' &&
200
+ ( typeof value !== 'number' || ! isInteger ( value ) )
201
+ ) {
202
+ throw new TypeError ( `ID cannot represent value: ${ inspect ( value ) } ` ) ;
203
+ }
204
+ return String ( value ) ;
205
+ }
206
+
143
207
export const GraphQLID = new GraphQLScalarType ( {
144
208
name : 'ID' ,
145
209
description :
@@ -148,8 +212,8 @@ export const GraphQLID = new GraphQLScalarType({
148
212
'response as a String; however, it is not intended to be human-readable. ' +
149
213
'When expected as an input type, any string (such as `"4"`) or integer ' +
150
214
'(such as `4`) input value will be accepted as an ID.' ,
151
- serialize : coerceString ,
152
- parseValue : coerceString ,
215
+ serialize : serializeID ,
216
+ parseValue : coerceID ,
153
217
parseLiteral ( ast ) {
154
218
return ast . kind === Kind . STRING || ast . kind === Kind . INT
155
219
? ast . value
0 commit comments