@@ -13,6 +13,7 @@ import { devAssert } from '../jsutils/devAssert';
13
13
import { keyValMap } from '../jsutils/keyValMap' ;
14
14
import { instanceOf } from '../jsutils/instanceOf' ;
15
15
import { didYouMean } from '../jsutils/didYouMean' ;
16
+ import { isIterableObject } from '../jsutils/isIterableObject' ;
16
17
import { isObjectLike } from '../jsutils/isObjectLike' ;
17
18
import { identityFunc } from '../jsutils/identityFunc' ;
18
19
import { suggestionList } from '../jsutils/suggestionList' ;
@@ -830,7 +831,10 @@ export function defineArguments(
830
831
name : argName ,
831
832
description : argConfig . description ,
832
833
type : argConfig . type ,
833
- defaultValue : argConfig . defaultValue ,
834
+ defaultValue : uncoerceDefaultValue (
835
+ argConfig . defaultValue ,
836
+ argConfig . type ,
837
+ ) ,
834
838
deprecationReason : argConfig . deprecationReason ,
835
839
extensions : argConfig . extensions && toObjMap ( argConfig . extensions ) ,
836
840
astNode : argConfig . astNode ,
@@ -1483,7 +1487,10 @@ export class GraphQLInputObjectType {
1483
1487
1484
1488
getFields ( ) : GraphQLInputFieldMap {
1485
1489
if ( typeof this . _fields === 'function' ) {
1486
- this . _fields = this . _fields ( ) ;
1490
+ const _fields = this . _fields ;
1491
+ // Assign before call to avoid potential infinite recursion.
1492
+ this . _fields = { } ;
1493
+ this . _fields = _fields ( ) ;
1487
1494
}
1488
1495
return this . _fields ;
1489
1496
}
@@ -1539,7 +1546,10 @@ function defineInputFieldMap(
1539
1546
name : fieldName ,
1540
1547
description : fieldConfig . description ,
1541
1548
type : fieldConfig . type ,
1542
- defaultValue : fieldConfig . defaultValue ,
1549
+ defaultValue : uncoerceDefaultValue (
1550
+ fieldConfig . defaultValue ,
1551
+ fieldConfig . type ,
1552
+ ) ,
1543
1553
deprecationReason : fieldConfig . deprecationReason ,
1544
1554
extensions : fieldConfig . extensions && toObjMap ( fieldConfig . extensions ) ,
1545
1555
astNode : fieldConfig . astNode ,
@@ -1591,3 +1601,61 @@ export function isRequiredInputField(
1591
1601
}
1592
1602
1593
1603
export type GraphQLInputFieldMap = ObjMap < GraphQLInputField > ;
1604
+
1605
+ /**
1606
+ * Historically GraphQL.js allowed default values to be provided as
1607
+ * assumed-coerced "internal" values, however default values should be provided
1608
+ * as "external" pre-coerced values. `uncoerceDefaultValue()` will convert such
1609
+ * "internal" values to "external" values to avoid breaking existing clients.
1610
+ *
1611
+ * This performs the opposite of `coerceInputValue()`. Given an "internal"
1612
+ * coerced value, reverse the process to provide an "external" uncoerced value.
1613
+ *
1614
+ * This function should not throw Errors on incorrectly shaped input. Instead
1615
+ * it will simply pass through such values directly.
1616
+ *
1617
+ */
1618
+ function uncoerceDefaultValue ( value : mixed , type : GraphQLInputType ) : mixed {
1619
+ // Explicitly return the value null.
1620
+ if ( value === null ) {
1621
+ return null ;
1622
+ }
1623
+
1624
+ // Unwrap type
1625
+ const namedType = getNamedType ( type ) ;
1626
+
1627
+ if ( isIterableObject ( value ) ) {
1628
+ return Array . from ( value , ( itemValue ) =>
1629
+ uncoerceDefaultValue ( itemValue , namedType ) ,
1630
+ ) ;
1631
+ }
1632
+
1633
+ if ( isInputObjectType ( namedType ) ) {
1634
+ if ( ! isObjectLike ( value ) ) {
1635
+ return value ;
1636
+ }
1637
+
1638
+ const fieldDefs = namedType . getFields ( ) ;
1639
+ return mapValue ( value , ( fieldValue , fieldName ) =>
1640
+ fieldName in fieldDefs
1641
+ ? uncoerceDefaultValue ( fieldValue , fieldDefs [ fieldName ] . type )
1642
+ : fieldValue ,
1643
+ ) ;
1644
+ }
1645
+
1646
+ if ( isLeafType ( namedType ) ) {
1647
+ try {
1648
+ // For leaf types (Scalars, Enums), serialize is the oppose of coercion
1649
+ // (parseValue) and will produce an "external" value.
1650
+ return namedType . serialize ( value ) ;
1651
+ } catch ( error ) {
1652
+ // Ingore any invalid data errors.
1653
+ // istanbul ignore next - serialize should only throw GraphQLError
1654
+ if ( ! ( error instanceof GraphQLError ) ) {
1655
+ throw error ;
1656
+ }
1657
+ }
1658
+ }
1659
+
1660
+ return value ;
1661
+ }
0 commit comments