@@ -20,7 +20,6 @@ import { Kind } from '../language/kinds';
2020import { print } from '../language/printer' ;
2121import type {
2222 FieldNode ,
23- ValueNode ,
2423 ConstValueNode ,
2524 OperationDefinitionNode ,
2625 FragmentDefinitionNode ,
@@ -590,9 +589,39 @@ export interface GraphQLScalarTypeExtensions {
590589 * if (value % 2 === 1) {
591590 * return value;
592591 * }
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+ * }
593602 * }
594603 * });
595604 *
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+ *
596625 */
597626export class GraphQLScalarType extends GraphQLSchemaElement {
598627 name : string ;
@@ -601,6 +630,7 @@ export class GraphQLScalarType extends GraphQLSchemaElement {
601630 serialize : GraphQLScalarSerializer < unknown > ;
602631 parseValue : GraphQLScalarValueParser < unknown > ;
603632 parseLiteral : GraphQLScalarLiteralParser < unknown > ;
633+ valueToLiteral : Maybe < GraphQLScalarValueToLiteral > ;
604634 extensions : Maybe < Readonly < GraphQLScalarTypeExtensions > > ;
605635 astNode : Maybe < ScalarTypeDefinitionNode > ;
606636 extensionASTNodes : ReadonlyArray < ScalarTypeExtensionNode > ;
@@ -614,8 +644,8 @@ export class GraphQLScalarType extends GraphQLSchemaElement {
614644 this . serialize = config . serialize ?? identityFunc ;
615645 this . parseValue = parseValue ;
616646 this . parseLiteral =
617- config . parseLiteral ??
618- ( ( node , variables ) => parseValue ( valueFromASTUntyped ( node , variables ) ) ) ;
647+ config . parseLiteral ?? ( ( node ) => parseValue ( valueFromASTUntyped ( node ) ) ) ;
648+ this . valueToLiteral = config . valueToLiteral ;
619649 this . extensions = config . extensions && toObjMap ( config . extensions ) ;
620650 this . astNode = config . astNode ;
621651 this . extensionASTNodes = config . extensionASTNodes ?? [ ] ;
@@ -641,6 +671,13 @@ export class GraphQLScalarType extends GraphQLSchemaElement {
641671 `${ this . name } must provide both "parseValue" and "parseLiteral" functions.` ,
642672 ) ;
643673 }
674+
675+ if ( config . valueToLiteral ) {
676+ devAssert (
677+ typeof config . valueToLiteral === 'function' ,
678+ `${ this . name } must provide "valueToLiteral" as a function.` ,
679+ ) ;
680+ }
644681 }
645682
646683 toConfig ( ) : GraphQLScalarTypeNormalizedConfig {
@@ -651,6 +688,7 @@ export class GraphQLScalarType extends GraphQLSchemaElement {
651688 serialize : this . serialize ,
652689 parseValue : this . parseValue ,
653690 parseLiteral : this . parseLiteral ,
691+ valueToLiteral : this . valueToLiteral ,
654692 extensions : this . extensions ,
655693 astNode : this . astNode ,
656694 extensionASTNodes : this . extensionASTNodes ,
@@ -671,10 +709,13 @@ export type GraphQLScalarValueParser<TInternal> = (
671709) => Maybe < TInternal > ;
672710
673711export type GraphQLScalarLiteralParser < TInternal > = (
674- valueNode : ValueNode ,
675- variables ?: Maybe < ObjMap < unknown > > ,
712+ valueNode : ConstValueNode ,
676713) => Maybe < TInternal > ;
677714
715+ export type GraphQLScalarValueToLiteral = (
716+ inputValue : unknown ,
717+ ) => ConstValueNode | undefined ;
718+
678719export interface GraphQLScalarTypeConfig < TInternal , TExternal > {
679720 name : string ;
680721 description ?: Maybe < string > ;
@@ -685,6 +726,8 @@ export interface GraphQLScalarTypeConfig<TInternal, TExternal> {
685726 parseValue ?: GraphQLScalarValueParser < TInternal > ;
686727 /** Parses an externally provided literal value to use as an input. */
687728 parseLiteral ?: GraphQLScalarLiteralParser < TInternal > ;
729+ /** Translates an externally provided value to a literal (AST). */
730+ valueToLiteral ?: Maybe < GraphQLScalarValueToLiteral > ;
688731 extensions ?: Maybe < Readonly < GraphQLScalarTypeExtensions > > ;
689732 astNode ?: Maybe < ScalarTypeDefinitionNode > ;
690733 extensionASTNodes ?: Maybe < ReadonlyArray < ScalarTypeExtensionNode > > ;
@@ -1457,10 +1500,7 @@ export class GraphQLEnumType /* <T> */ extends GraphQLSchemaElement {
14571500 return enumValue . value ;
14581501 }
14591502
1460- parseLiteral (
1461- valueNode : ValueNode ,
1462- _variables : Maybe < ObjMap < unknown > > ,
1463- ) : Maybe < any > /* T */ {
1503+ parseLiteral ( valueNode : ConstValueNode ) : Maybe < any > /* T */ {
14641504 // Note: variables will be resolved to a value before calling this function.
14651505 if ( valueNode . kind !== Kind . ENUM ) {
14661506 const valueStr = print ( valueNode ) ;
@@ -1483,6 +1523,12 @@ export class GraphQLEnumType /* <T> */ extends GraphQLSchemaElement {
14831523 return enumValue . value ;
14841524 }
14851525
1526+ valueToLiteral ( value : unknown ) : ConstValueNode | undefined {
1527+ if ( typeof value === 'string' && this . getValue ( value ) ) {
1528+ return { kind : Kind . ENUM , value } ;
1529+ }
1530+ }
1531+
14861532 toConfig ( ) : GraphQLEnumTypeNormalizedConfig {
14871533 return {
14881534 name : this . name ,
0 commit comments