@@ -20,7 +20,6 @@ import { Kind } from '../language/kinds';
20
20
import { print } from '../language/printer' ;
21
21
import type {
22
22
FieldNode ,
23
- ValueNode ,
24
23
ConstValueNode ,
25
24
OperationDefinitionNode ,
26
25
FragmentDefinitionNode ,
@@ -590,9 +589,39 @@ export interface GraphQLScalarTypeExtensions {
590
589
* if (value % 2 === 1) {
591
590
* return value;
592
591
* }
592
+ * },
593
+ * parseValue(value) {
594
+ * if (value % 2 === 1) {
595
+ * return value;
596
+ * }
597
+ * }
598
+ * valueToLiteral(value) {
599
+ * if (value % 2 === 1) {
600
+ * return parse(`${value}`);
601
+ * }
593
602
* }
594
603
* });
595
604
*
605
+ * Custom scalars behavior is defined via the following functions:
606
+ *
607
+ * - serialize(value): Implements "Result Coercion". Given an internal value,
608
+ * produces an external value valid for this type. Returns undefined or
609
+ * throws an error to indicate invalid values.
610
+ *
611
+ * - parseValue(value): Implements "Input Coercion" for values. Given an
612
+ * external value (for example, variable values), produces an internal value
613
+ * valid for this type. Returns undefined or throws an error to indicate
614
+ * invalid values.
615
+ *
616
+ * - parseLiteral(ast): Implements "Input Coercion" for literals. Given an
617
+ * GraphQL literal (AST) (for example, an argument value), produces an
618
+ * internal value valid for this type. Returns undefined or throws an error
619
+ * to indicate invalid values.
620
+ *
621
+ * - valueToLiteral(value): Converts an external value to a GraphQL
622
+ * literal (AST). Returns undefined or throws an error to indicate
623
+ * invalid values.
624
+ *
596
625
*/
597
626
export class GraphQLScalarType extends GraphQLSchemaElement {
598
627
name : string ;
@@ -601,6 +630,7 @@ export class GraphQLScalarType extends GraphQLSchemaElement {
601
630
serialize : GraphQLScalarSerializer < unknown > ;
602
631
parseValue : GraphQLScalarValueParser < unknown > ;
603
632
parseLiteral : GraphQLScalarLiteralParser < unknown > ;
633
+ valueToLiteral : Maybe < GraphQLScalarValueToLiteral > ;
604
634
extensions : Maybe < Readonly < GraphQLScalarTypeExtensions > > ;
605
635
astNode : Maybe < ScalarTypeDefinitionNode > ;
606
636
extensionASTNodes : ReadonlyArray < ScalarTypeExtensionNode > ;
@@ -614,8 +644,8 @@ export class GraphQLScalarType extends GraphQLSchemaElement {
614
644
this . serialize = config . serialize ?? identityFunc ;
615
645
this . parseValue = parseValue ;
616
646
this . parseLiteral =
617
- config . parseLiteral ??
618
- ( ( node , variables ) => parseValue ( valueFromASTUntyped ( node , variables ) ) ) ;
647
+ config . parseLiteral ?? ( ( node ) => parseValue ( valueFromASTUntyped ( node ) ) ) ;
648
+ this . valueToLiteral = config . valueToLiteral ;
619
649
this . extensions = config . extensions && toObjMap ( config . extensions ) ;
620
650
this . astNode = config . astNode ;
621
651
this . extensionASTNodes = config . extensionASTNodes ?? [ ] ;
@@ -641,6 +671,13 @@ export class GraphQLScalarType extends GraphQLSchemaElement {
641
671
`${ this . name } must provide both "parseValue" and "parseLiteral" functions.` ,
642
672
) ;
643
673
}
674
+
675
+ if ( config . valueToLiteral ) {
676
+ devAssert (
677
+ typeof config . valueToLiteral === 'function' ,
678
+ `${ this . name } must provide "valueToLiteral" as a function.` ,
679
+ ) ;
680
+ }
644
681
}
645
682
646
683
toConfig ( ) : GraphQLScalarTypeNormalizedConfig {
@@ -651,6 +688,7 @@ export class GraphQLScalarType extends GraphQLSchemaElement {
651
688
serialize : this . serialize ,
652
689
parseValue : this . parseValue ,
653
690
parseLiteral : this . parseLiteral ,
691
+ valueToLiteral : this . valueToLiteral ,
654
692
extensions : this . extensions ,
655
693
astNode : this . astNode ,
656
694
extensionASTNodes : this . extensionASTNodes ,
@@ -671,10 +709,13 @@ export type GraphQLScalarValueParser<TInternal> = (
671
709
) => Maybe < TInternal > ;
672
710
673
711
export type GraphQLScalarLiteralParser < TInternal > = (
674
- valueNode : ValueNode ,
675
- variables ?: Maybe < ObjMap < unknown > > ,
712
+ valueNode : ConstValueNode ,
676
713
) => Maybe < TInternal > ;
677
714
715
+ export type GraphQLScalarValueToLiteral = (
716
+ inputValue : unknown ,
717
+ ) => ConstValueNode | undefined ;
718
+
678
719
export interface GraphQLScalarTypeConfig < TInternal , TExternal > {
679
720
name : string ;
680
721
description ?: Maybe < string > ;
@@ -685,6 +726,8 @@ export interface GraphQLScalarTypeConfig<TInternal, TExternal> {
685
726
parseValue ?: GraphQLScalarValueParser < TInternal > ;
686
727
/** Parses an externally provided literal value to use as an input. */
687
728
parseLiteral ?: GraphQLScalarLiteralParser < TInternal > ;
729
+ /** Translates an externally provided value to a literal (AST). */
730
+ valueToLiteral ?: Maybe < GraphQLScalarValueToLiteral > ;
688
731
extensions ?: Maybe < Readonly < GraphQLScalarTypeExtensions > > ;
689
732
astNode ?: Maybe < ScalarTypeDefinitionNode > ;
690
733
extensionASTNodes ?: Maybe < ReadonlyArray < ScalarTypeExtensionNode > > ;
@@ -1457,10 +1500,7 @@ export class GraphQLEnumType /* <T> */ extends GraphQLSchemaElement {
1457
1500
return enumValue . value ;
1458
1501
}
1459
1502
1460
- parseLiteral (
1461
- valueNode : ValueNode ,
1462
- _variables : Maybe < ObjMap < unknown > > ,
1463
- ) : Maybe < any > /* T */ {
1503
+ parseLiteral ( valueNode : ConstValueNode ) : Maybe < any > /* T */ {
1464
1504
// Note: variables will be resolved to a value before calling this function.
1465
1505
if ( valueNode . kind !== Kind . ENUM ) {
1466
1506
const valueStr = print ( valueNode ) ;
@@ -1483,6 +1523,12 @@ export class GraphQLEnumType /* <T> */ extends GraphQLSchemaElement {
1483
1523
return enumValue . value ;
1484
1524
}
1485
1525
1526
+ valueToLiteral ( value : unknown ) : ConstValueNode | undefined {
1527
+ if ( typeof value === 'string' && this . getValue ( value ) ) {
1528
+ return { kind : Kind . ENUM , value } ;
1529
+ }
1530
+ }
1531
+
1486
1532
toConfig ( ) : GraphQLEnumTypeNormalizedConfig {
1487
1533
return {
1488
1534
name : this . name ,
0 commit comments