UNPKG

5.39 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true,
5});
6exports.valueFromAST = valueFromAST;
7
8var _inspect = require('../jsutils/inspect.js');
9
10var _invariant = require('../jsutils/invariant.js');
11
12var _keyMap = require('../jsutils/keyMap.js');
13
14var _kinds = require('../language/kinds.js');
15
16var _definition = require('../type/definition.js');
17
18/**
19 * Produces a JavaScript value given a GraphQL Value AST.
20 *
21 * A GraphQL type must be provided, which will be used to interpret different
22 * GraphQL Value literals.
23 *
24 * Returns `undefined` when the value could not be validly coerced according to
25 * the provided type.
26 *
27 * | GraphQL Value | JSON Value |
28 * | -------------------- | ------------- |
29 * | Input Object | Object |
30 * | List | Array |
31 * | Boolean | Boolean |
32 * | String | String |
33 * | Int / Float | Number |
34 * | Enum Value | Unknown |
35 * | NullValue | null |
36 *
37 */
38function valueFromAST(valueNode, type, variables) {
39 if (!valueNode) {
40 // When there is no node, then there is also no value.
41 // Importantly, this is different from returning the value null.
42 return;
43 }
44
45 if (valueNode.kind === _kinds.Kind.VARIABLE) {
46 const variableName = valueNode.name.value;
47
48 if (variables == null || variables[variableName] === undefined) {
49 // No valid return value.
50 return;
51 }
52
53 const variableValue = variables[variableName];
54
55 if (variableValue === null && (0, _definition.isNonNullType)(type)) {
56 return; // Invalid: intentionally return no value.
57 } // Note: This does no further checking that this variable is correct.
58 // This assumes that this query has been validated and the variable
59 // usage here is of the correct type.
60
61 return variableValue;
62 }
63
64 if ((0, _definition.isNonNullType)(type)) {
65 if (valueNode.kind === _kinds.Kind.NULL) {
66 return; // Invalid: intentionally return no value.
67 }
68
69 return valueFromAST(valueNode, type.ofType, variables);
70 }
71
72 if (valueNode.kind === _kinds.Kind.NULL) {
73 // This is explicitly returning the value null.
74 return null;
75 }
76
77 if ((0, _definition.isListType)(type)) {
78 const itemType = type.ofType;
79
80 if (valueNode.kind === _kinds.Kind.LIST) {
81 const coercedValues = [];
82
83 for (const itemNode of valueNode.values) {
84 if (isMissingVariable(itemNode, variables)) {
85 // If an array contains a missing variable, it is either coerced to
86 // null or if the item type is non-null, it considered invalid.
87 if ((0, _definition.isNonNullType)(itemType)) {
88 return; // Invalid: intentionally return no value.
89 }
90
91 coercedValues.push(null);
92 } else {
93 const itemValue = valueFromAST(itemNode, itemType, variables);
94
95 if (itemValue === undefined) {
96 return; // Invalid: intentionally return no value.
97 }
98
99 coercedValues.push(itemValue);
100 }
101 }
102
103 return coercedValues;
104 }
105
106 const coercedValue = valueFromAST(valueNode, itemType, variables);
107
108 if (coercedValue === undefined) {
109 return; // Invalid: intentionally return no value.
110 }
111
112 return [coercedValue];
113 }
114
115 if ((0, _definition.isInputObjectType)(type)) {
116 if (valueNode.kind !== _kinds.Kind.OBJECT) {
117 return; // Invalid: intentionally return no value.
118 }
119
120 const coercedObj = Object.create(null);
121 const fieldNodes = (0, _keyMap.keyMap)(
122 valueNode.fields,
123 (field) => field.name.value,
124 );
125
126 for (const field of Object.values(type.getFields())) {
127 const fieldNode = fieldNodes[field.name];
128
129 if (!fieldNode || isMissingVariable(fieldNode.value, variables)) {
130 if (field.defaultValue !== undefined) {
131 coercedObj[field.name] = field.defaultValue;
132 } else if ((0, _definition.isNonNullType)(field.type)) {
133 return; // Invalid: intentionally return no value.
134 }
135
136 continue;
137 }
138
139 const fieldValue = valueFromAST(fieldNode.value, field.type, variables);
140
141 if (fieldValue === undefined) {
142 return; // Invalid: intentionally return no value.
143 }
144
145 coercedObj[field.name] = fieldValue;
146 }
147
148 return coercedObj;
149 }
150
151 if ((0, _definition.isLeafType)(type)) {
152 // Scalars and Enums fulfill parsing a literal value via parseLiteral().
153 // Invalid values represent a failure to parse correctly, in which case
154 // no value is returned.
155 let result;
156
157 try {
158 result = type.parseLiteral(valueNode, variables);
159 } catch (_error) {
160 return; // Invalid: intentionally return no value.
161 }
162
163 if (result === undefined) {
164 return; // Invalid: intentionally return no value.
165 }
166
167 return result;
168 }
169 /* c8 ignore next 3 */
170 // Not reachable, all possible input types have been considered.
171
172 false ||
173 (0, _invariant.invariant)(
174 false,
175 'Unexpected input type: ' + (0, _inspect.inspect)(type),
176 );
177} // Returns true if the provided valueNode is a variable which is not defined
178// in the set of variables.
179
180function isMissingVariable(valueNode, variables) {
181 return (
182 valueNode.kind === _kinds.Kind.VARIABLE &&
183 (variables == null || variables[valueNode.name.value] === undefined)
184 );
185}