UNPKG

3.9 kBJavaScriptView Raw
1import { inspect } from 'cross-inspect';
2import { isEnumType, isInputObjectType, isLeafType, isListType, isNonNullType, Kind, } from 'graphql';
3import { astFromValueUntyped } from './astFromValueUntyped.js';
4import { isIterableObject, isObjectLike } from './jsutils.js';
5/**
6 * Produces a GraphQL Value AST given a JavaScript object.
7 * Function will match JavaScript/JSON values to GraphQL AST schema format
8 * by using suggested GraphQLInputType. For example:
9 *
10 * astFromValue("value", GraphQLString)
11 *
12 * A GraphQL type must be provided, which will be used to interpret different
13 * JavaScript values.
14 *
15 * | JSON Value | GraphQL Value |
16 * | ------------- | -------------------- |
17 * | Object | Input Object |
18 * | Array | List |
19 * | Boolean | Boolean |
20 * | String | String / Enum Value |
21 * | Number | Int / Float |
22 * | BigInt | Int |
23 * | Unknown | Enum Value |
24 * | null | NullValue |
25 *
26 */
27export function astFromValue(value, type) {
28 if (isNonNullType(type)) {
29 const astValue = astFromValue(value, type.ofType);
30 if (astValue?.kind === Kind.NULL) {
31 return null;
32 }
33 return astValue;
34 }
35 // only explicit null, not undefined, NaN
36 if (value === null) {
37 return { kind: Kind.NULL };
38 }
39 // undefined
40 if (value === undefined) {
41 return null;
42 }
43 // Convert JavaScript array to GraphQL list. If the GraphQLType is a list, but
44 // the value is not an array, convert the value using the list's item type.
45 if (isListType(type)) {
46 const itemType = type.ofType;
47 if (isIterableObject(value)) {
48 const valuesNodes = [];
49 for (const item of value) {
50 const itemNode = astFromValue(item, itemType);
51 if (itemNode != null) {
52 valuesNodes.push(itemNode);
53 }
54 }
55 return { kind: Kind.LIST, values: valuesNodes };
56 }
57 return astFromValue(value, itemType);
58 }
59 // Populate the fields of the input object by creating ASTs from each value
60 // in the JavaScript object according to the fields in the input type.
61 if (isInputObjectType(type)) {
62 if (!isObjectLike(value)) {
63 return null;
64 }
65 const fieldNodes = [];
66 for (const field of Object.values(type.getFields())) {
67 const fieldValue = astFromValue(value[field.name], field.type);
68 if (fieldValue) {
69 fieldNodes.push({
70 kind: Kind.OBJECT_FIELD,
71 name: { kind: Kind.NAME, value: field.name },
72 value: fieldValue,
73 });
74 }
75 }
76 return { kind: Kind.OBJECT, fields: fieldNodes };
77 }
78 if (isLeafType(type)) {
79 // Since value is an internally represented value, it must be serialized
80 // to an externally represented value before converting into an AST.
81 const serialized = type.serialize(value);
82 if (serialized == null) {
83 return null;
84 }
85 if (isEnumType(type)) {
86 return { kind: Kind.ENUM, value: serialized };
87 }
88 // ID types can use Int literals.
89 if (type.name === 'ID' &&
90 typeof serialized === 'string' &&
91 integerStringRegExp.test(serialized)) {
92 return { kind: Kind.INT, value: serialized };
93 }
94 return astFromValueUntyped(serialized);
95 }
96 /* c8 ignore next 3 */
97 // Not reachable, all possible types have been considered.
98 console.assert(false, 'Unexpected input type: ' + inspect(type));
99}
100/**
101 * IntValue:
102 * - NegativeSign? 0
103 * - NegativeSign? NonZeroDigit ( Digit+ )?
104 */
105const integerStringRegExp = /^-?(?:0|[1-9][0-9]*)$/;