@@ -35,7 +35,6 @@ import type {
35
35
ScalarTypeExtensionNode ,
36
36
UnionTypeDefinitionNode ,
37
37
UnionTypeExtensionNode ,
38
- ValueNode ,
39
38
} from '../language/ast.js' ;
40
39
import { Kind } from '../language/kinds.js' ;
41
40
import { print } from '../language/printer.js' ;
@@ -526,22 +525,52 @@ export interface GraphQLScalarTypeExtensions {
526
525
* Example:
527
526
*
528
527
* ```ts
528
+ * function ensureOdd(value) {
529
+ * if (!Number.isFinite(value)) {
530
+ * throw new Error(
531
+ * `Scalar "Odd" cannot represent "${value}" since it is not a finite number.`,
532
+ * );
533
+ * }
534
+ *
535
+ * if (value % 2 === 0) {
536
+ * throw new Error(`Scalar "Odd" cannot represent "${value}" since it is even.`);
537
+ * }
538
+ * }
539
+ *
529
540
* const OddType = new GraphQLScalarType({
530
541
* name: 'Odd',
531
542
* serialize(value) {
532
- * if (!Number.isFinite(value)) {
533
- * throw new Error(
534
- * `Scalar "Odd" cannot represent "${value}" since it is not a finite number.`,
535
- * );
536
- * }
537
- *
538
- * if (value % 2 === 0) {
539
- * throw new Error(`Scalar "Odd" cannot represent "${value}" since it is even.`);
540
- * }
541
- * return value;
543
+ * return ensureOdd(value);
544
+ * },
545
+ * parseValue(value) {
546
+ * return ensureOdd(value);
547
+ * }
548
+ * valueToLiteral(value) {
549
+ * return parse(`${ensureOdd(value)`);
542
550
* }
543
551
* });
544
552
* ```
553
+ *
554
+ * Custom scalars behavior is defined via the following functions:
555
+ *
556
+ * - serialize(value): Implements "Result Coercion". Given an internal value,
557
+ * produces an external value valid for this type. Returns undefined or
558
+ * throws an error to indicate invalid values.
559
+ *
560
+ * - parseValue(value): Implements "Input Coercion" for values. Given an
561
+ * external value (for example, variable values), produces an internal value
562
+ * valid for this type. Returns undefined or throws an error to indicate
563
+ * invalid values.
564
+ *
565
+ * - parseLiteral(ast): Implements "Input Coercion" for literals. Given an
566
+ * GraphQL literal (AST) (for example, an argument value), produces an
567
+ * internal value valid for this type. Returns undefined or throws an error
568
+ * to indicate invalid values.
569
+ *
570
+ * - valueToLiteral(value): Converts an external value to a GraphQL
571
+ * literal (AST). Returns undefined or throws an error to indicate
572
+ * invalid values.
573
+ *
545
574
*/
546
575
export class GraphQLScalarType < TInternal = unknown , TExternal = TInternal > {
547
576
name : string ;
@@ -550,6 +579,7 @@ export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
550
579
serialize : GraphQLScalarSerializer < TExternal > ;
551
580
parseValue : GraphQLScalarValueParser < TInternal > ;
552
581
parseLiteral : GraphQLScalarLiteralParser < TInternal > ;
582
+ valueToLiteral : GraphQLScalarValueToLiteral | undefined ;
553
583
extensions : Readonly < GraphQLScalarTypeExtensions > ;
554
584
astNode : Maybe < ScalarTypeDefinitionNode > ;
555
585
extensionASTNodes : ReadonlyArray < ScalarTypeExtensionNode > ;
@@ -566,8 +596,8 @@ export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
566
596
config . serialize ?? ( identityFunc as GraphQLScalarSerializer < TExternal > ) ;
567
597
this . parseValue = parseValue ;
568
598
this . parseLiteral =
569
- config . parseLiteral ??
570
- ( ( node , variables ) => parseValue ( valueFromASTUntyped ( node , variables ) ) ) ;
599
+ config . parseLiteral ?? ( ( node ) => parseValue ( valueFromASTUntyped ( node ) ) ) ;
600
+ this . valueToLiteral = config . valueToLiteral ;
571
601
this . extensions = toObjMap ( config . extensions ) ;
572
602
this . astNode = config . astNode ;
573
603
this . extensionASTNodes = config . extensionASTNodes ?? [ ] ;
@@ -593,6 +623,7 @@ export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
593
623
serialize : this . serialize ,
594
624
parseValue : this . parseValue ,
595
625
parseLiteral : this . parseLiteral ,
626
+ valueToLiteral : this . valueToLiteral ,
596
627
extensions : this . extensions ,
597
628
astNode : this . astNode ,
598
629
extensionASTNodes : this . extensionASTNodes ,
@@ -617,9 +648,12 @@ export type GraphQLScalarValueParser<TInternal> = (
617
648
) => TInternal ;
618
649
619
650
export type GraphQLScalarLiteralParser < TInternal > = (
620
- valueNode : ValueNode ,
621
- variables ?: Maybe < ObjMap < unknown > > ,
622
- ) => TInternal ;
651
+ valueNode : ConstValueNode ,
652
+ ) => Maybe < TInternal > ;
653
+
654
+ export type GraphQLScalarValueToLiteral = (
655
+ inputValue : unknown ,
656
+ ) => ConstValueNode | undefined ;
623
657
624
658
export interface GraphQLScalarTypeConfig < TInternal , TExternal > {
625
659
name : string ;
@@ -631,6 +665,8 @@ export interface GraphQLScalarTypeConfig<TInternal, TExternal> {
631
665
parseValue ?: GraphQLScalarValueParser < TInternal > | undefined ;
632
666
/** Parses an externally provided literal value to use as an input. */
633
667
parseLiteral ?: GraphQLScalarLiteralParser < TInternal > | undefined ;
668
+ /** Translates an externally provided value to a literal (AST). */
669
+ valueToLiteral ?: GraphQLScalarValueToLiteral | undefined ;
634
670
extensions ?: Maybe < Readonly < GraphQLScalarTypeExtensions > > ;
635
671
astNode ?: Maybe < ScalarTypeDefinitionNode > ;
636
672
extensionASTNodes ?: Maybe < ReadonlyArray < ScalarTypeExtensionNode > > ;
@@ -1374,10 +1410,7 @@ export class GraphQLEnumType /* <T> */ {
1374
1410
return enumValue . value ;
1375
1411
}
1376
1412
1377
- parseLiteral (
1378
- valueNode : ValueNode ,
1379
- _variables : Maybe < ObjMap < unknown > > ,
1380
- ) : Maybe < any > /* T */ {
1413
+ parseLiteral ( valueNode : ConstValueNode ) : Maybe < any > /* T */ {
1381
1414
// Note: variables will be resolved to a value before calling this function.
1382
1415
if ( valueNode . kind !== Kind . ENUM ) {
1383
1416
const valueStr = print ( valueNode ) ;
@@ -1400,6 +1433,12 @@ export class GraphQLEnumType /* <T> */ {
1400
1433
return enumValue . value ;
1401
1434
}
1402
1435
1436
+ valueToLiteral ( value : unknown ) : ConstValueNode | undefined {
1437
+ if ( typeof value === 'string' && this . getValue ( value ) ) {
1438
+ return { kind : Kind . ENUM , value } ;
1439
+ }
1440
+ }
1441
+
1403
1442
toConfig ( ) : GraphQLEnumTypeNormalizedConfig {
1404
1443
const values = keyValMap (
1405
1444
this . getValues ( ) ,
0 commit comments