@@ -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' ;
@@ -813,7 +814,10 @@ function defineFieldMap<TSource, TContext>(
813
814
name : argName ,
814
815
description : argConfig . description ,
815
816
type : argConfig . type ,
816
- defaultValue : argConfig . defaultValue ,
817
+ defaultValue : uncoerceDefaultValue (
818
+ argConfig . defaultValue ,
819
+ argConfig . type ,
820
+ ) ,
817
821
deprecationReason : argConfig . deprecationReason ,
818
822
extensions : argConfig . extensions && toObjMap ( argConfig . extensions ) ,
819
823
astNode : argConfig . astNode ,
@@ -1479,7 +1483,10 @@ export class GraphQLInputObjectType {
1479
1483
1480
1484
getFields ( ) : GraphQLInputFieldMap {
1481
1485
if ( typeof this . _fields === 'function' ) {
1482
- this . _fields = this . _fields ( ) ;
1486
+ const _fields = this . _fields ;
1487
+ // Assign before call to avoid potential infinite recursion.
1488
+ this . _fields = { } ;
1489
+ this . _fields = _fields ( ) ;
1483
1490
}
1484
1491
return this . _fields ;
1485
1492
}
@@ -1535,7 +1542,10 @@ function defineInputFieldMap(
1535
1542
name : fieldName ,
1536
1543
description : fieldConfig . description ,
1537
1544
type : fieldConfig . type ,
1538
- defaultValue : fieldConfig . defaultValue ,
1545
+ defaultValue : uncoerceDefaultValue (
1546
+ fieldConfig . defaultValue ,
1547
+ fieldConfig . type ,
1548
+ ) ,
1539
1549
deprecationReason : fieldConfig . deprecationReason ,
1540
1550
extensions : fieldConfig . extensions && toObjMap ( fieldConfig . extensions ) ,
1541
1551
astNode : fieldConfig . astNode ,
@@ -1587,3 +1597,61 @@ export function isRequiredInputField(
1587
1597
}
1588
1598
1589
1599
export type GraphQLInputFieldMap = ObjMap < GraphQLInputField > ;
1600
+
1601
+ /**
1602
+ * Historically GraphQL.js allowed default values to be provided as
1603
+ * assumed-coerced "internal" values, however default values should be provided
1604
+ * as "external" pre-coerced values. `uncoerceDefaultValue()` will convert such
1605
+ * "internal" values to "external" values to avoid breaking existing clients.
1606
+ *
1607
+ * This performs the opposite of `coerceInputValue()`. Given an "internal"
1608
+ * coerced value, reverse the process to provide an "external" uncoerced value.
1609
+ *
1610
+ * This function should not throw Errors on incorrectly shaped input. Instead
1611
+ * it will simply pass through such values directly.
1612
+ *
1613
+ */
1614
+ function uncoerceDefaultValue ( value : mixed , type : GraphQLInputType ) : mixed {
1615
+ // Explicitly return the value null.
1616
+ if ( value === null ) {
1617
+ return null ;
1618
+ }
1619
+
1620
+ // Unwrap type
1621
+ const namedType = getNamedType ( type ) ;
1622
+
1623
+ if ( isIterableObject ( value ) ) {
1624
+ return Array . from ( value , ( itemValue ) =>
1625
+ uncoerceDefaultValue ( itemValue , namedType ) ,
1626
+ ) ;
1627
+ }
1628
+
1629
+ if ( isInputObjectType ( namedType ) ) {
1630
+ if ( ! isObjectLike ( value ) ) {
1631
+ return value ;
1632
+ }
1633
+
1634
+ const fieldDefs = namedType . getFields ( ) ;
1635
+ return mapValue ( value , ( fieldValue , fieldName ) =>
1636
+ fieldName in fieldDefs
1637
+ ? uncoerceDefaultValue ( fieldValue , fieldDefs [ fieldName ] . type )
1638
+ : fieldValue ,
1639
+ ) ;
1640
+ }
1641
+
1642
+ if ( isLeafType ( namedType ) ) {
1643
+ try {
1644
+ // For leaf types (Scalars, Enums), serialize is the oppose of coercion
1645
+ // (parseValue) and will produce an "external" value.
1646
+ return namedType . serialize ( value ) ;
1647
+ } catch ( error ) {
1648
+ // Ingore any invalid data errors.
1649
+ // istanbul ignore next - serialize should only throw GraphQLError
1650
+ if ( ! ( error instanceof GraphQLError ) ) {
1651
+ throw error ;
1652
+ }
1653
+ }
1654
+ }
1655
+
1656
+ return value ;
1657
+ }
0 commit comments