UNPKG

5.06 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true,
5});
6exports.astFromValue = astFromValue;
7
8var _inspect = require('../jsutils/inspect.js');
9
10var _invariant = require('../jsutils/invariant.js');
11
12var _isIterableObject = require('../jsutils/isIterableObject.js');
13
14var _isObjectLike = require('../jsutils/isObjectLike.js');
15
16var _kinds = require('../language/kinds.js');
17
18var _definition = require('../type/definition.js');
19
20var _scalars = require('../type/scalars.js');
21
22/**
23 * Produces a GraphQL Value AST given a JavaScript object.
24 * Function will match JavaScript/JSON values to GraphQL AST schema format
25 * by using suggested GraphQLInputType. For example:
26 *
27 * astFromValue("value", GraphQLString)
28 *
29 * A GraphQL type must be provided, which will be used to interpret different
30 * JavaScript values.
31 *
32 * | JSON Value | GraphQL Value |
33 * | ------------- | -------------------- |
34 * | Object | Input Object |
35 * | Array | List |
36 * | Boolean | Boolean |
37 * | String | String / Enum Value |
38 * | Number | Int / Float |
39 * | Unknown | Enum Value |
40 * | null | NullValue |
41 *
42 */
43function astFromValue(value, type) {
44 if ((0, _definition.isNonNullType)(type)) {
45 const astValue = astFromValue(value, type.ofType);
46
47 if (
48 (astValue === null || astValue === void 0 ? void 0 : astValue.kind) ===
49 _kinds.Kind.NULL
50 ) {
51 return null;
52 }
53
54 return astValue;
55 } // only explicit null, not undefined, NaN
56
57 if (value === null) {
58 return {
59 kind: _kinds.Kind.NULL,
60 };
61 } // undefined
62
63 if (value === undefined) {
64 return null;
65 } // Convert JavaScript array to GraphQL list. If the GraphQLType is a list, but
66 // the value is not an array, convert the value using the list's item type.
67
68 if ((0, _definition.isListType)(type)) {
69 const itemType = type.ofType;
70
71 if ((0, _isIterableObject.isIterableObject)(value)) {
72 const valuesNodes = [];
73
74 for (const item of value) {
75 const itemNode = astFromValue(item, itemType);
76
77 if (itemNode != null) {
78 valuesNodes.push(itemNode);
79 }
80 }
81
82 return {
83 kind: _kinds.Kind.LIST,
84 values: valuesNodes,
85 };
86 }
87
88 return astFromValue(value, itemType);
89 } // Populate the fields of the input object by creating ASTs from each value
90 // in the JavaScript object according to the fields in the input type.
91
92 if ((0, _definition.isInputObjectType)(type)) {
93 if (!(0, _isObjectLike.isObjectLike)(value)) {
94 return null;
95 }
96
97 const fieldNodes = [];
98
99 for (const field of Object.values(type.getFields())) {
100 const fieldValue = astFromValue(value[field.name], field.type);
101
102 if (fieldValue) {
103 fieldNodes.push({
104 kind: _kinds.Kind.OBJECT_FIELD,
105 name: {
106 kind: _kinds.Kind.NAME,
107 value: field.name,
108 },
109 value: fieldValue,
110 });
111 }
112 }
113
114 return {
115 kind: _kinds.Kind.OBJECT,
116 fields: fieldNodes,
117 };
118 }
119
120 if ((0, _definition.isLeafType)(type)) {
121 // Since value is an internally represented value, it must be serialized
122 // to an externally represented value before converting into an AST.
123 const serialized = type.serialize(value);
124
125 if (serialized == null) {
126 return null;
127 } // Others serialize based on their corresponding JavaScript scalar types.
128
129 if (typeof serialized === 'boolean') {
130 return {
131 kind: _kinds.Kind.BOOLEAN,
132 value: serialized,
133 };
134 } // JavaScript numbers can be Int or Float values.
135
136 if (typeof serialized === 'number' && Number.isFinite(serialized)) {
137 const stringNum = String(serialized);
138 return integerStringRegExp.test(stringNum)
139 ? {
140 kind: _kinds.Kind.INT,
141 value: stringNum,
142 }
143 : {
144 kind: _kinds.Kind.FLOAT,
145 value: stringNum,
146 };
147 }
148
149 if (typeof serialized === 'string') {
150 // Enum types use Enum literals.
151 if ((0, _definition.isEnumType)(type)) {
152 return {
153 kind: _kinds.Kind.ENUM,
154 value: serialized,
155 };
156 } // ID types can use Int literals.
157
158 if (type === _scalars.GraphQLID && integerStringRegExp.test(serialized)) {
159 return {
160 kind: _kinds.Kind.INT,
161 value: serialized,
162 };
163 }
164
165 return {
166 kind: _kinds.Kind.STRING,
167 value: serialized,
168 };
169 }
170
171 throw new TypeError(
172 `Cannot convert value to AST: ${(0, _inspect.inspect)(serialized)}.`,
173 );
174 }
175 /* c8 ignore next 3 */
176 // Not reachable, all possible types have been considered.
177
178 false ||
179 (0, _invariant.invariant)(
180 false,
181 'Unexpected input type: ' + (0, _inspect.inspect)(type),
182 );
183}
184/**
185 * IntValue:
186 * - NegativeSign? 0
187 * - NegativeSign? NonZeroDigit ( Digit+ )?
188 */
189
190const integerStringRegExp = /^-?(?:0|[1-9][0-9]*)$/;