UNPKG

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