UNPKG

2.83 kBJavaScriptView Raw
1import { Kind } from 'graphql';
2/**
3 * Produces a GraphQL Value AST given a JavaScript object.
4 * Function will match JavaScript/JSON values to GraphQL AST schema format
5 * by using the following mapping.
6 *
7 * | JSON Value | GraphQL Value |
8 * | ------------- | -------------------- |
9 * | Object | Input Object |
10 * | Array | List |
11 * | Boolean | Boolean |
12 * | String | String |
13 * | Number | Int / Float |
14 * | BigInt | Int |
15 * | null | NullValue |
16 *
17 */
18export function astFromValueUntyped(value) {
19 // only explicit null, not undefined, NaN
20 if (value === null) {
21 return { kind: Kind.NULL };
22 }
23 // undefined
24 if (value === undefined) {
25 return null;
26 }
27 // Convert JavaScript array to GraphQL list. If the GraphQLType is a list, but
28 // the value is not an array, convert the value using the list's item type.
29 if (Array.isArray(value)) {
30 const valuesNodes = [];
31 for (const item of value) {
32 const itemNode = astFromValueUntyped(item);
33 if (itemNode != null) {
34 valuesNodes.push(itemNode);
35 }
36 }
37 return { kind: Kind.LIST, values: valuesNodes };
38 }
39 if (typeof value === 'object') {
40 if (value?.toJSON) {
41 return astFromValueUntyped(value.toJSON());
42 }
43 const fieldNodes = [];
44 for (const fieldName in value) {
45 const fieldValue = value[fieldName];
46 const ast = astFromValueUntyped(fieldValue);
47 if (ast) {
48 fieldNodes.push({
49 kind: Kind.OBJECT_FIELD,
50 name: { kind: Kind.NAME, value: fieldName },
51 value: ast,
52 });
53 }
54 }
55 return { kind: Kind.OBJECT, fields: fieldNodes };
56 }
57 // Others serialize based on their corresponding JavaScript scalar types.
58 if (typeof value === 'boolean') {
59 return { kind: Kind.BOOLEAN, value };
60 }
61 if (typeof value === 'bigint') {
62 return { kind: Kind.INT, value: String(value) };
63 }
64 // JavaScript numbers can be Int or Float values.
65 if (typeof value === 'number' && isFinite(value)) {
66 const stringNum = String(value);
67 return integerStringRegExp.test(stringNum)
68 ? { kind: Kind.INT, value: stringNum }
69 : { kind: Kind.FLOAT, value: stringNum };
70 }
71 if (typeof value === 'string') {
72 return { kind: Kind.STRING, value };
73 }
74 throw new TypeError(`Cannot convert value to AST: ${value}.`);
75}
76/**
77 * IntValue:
78 * - NegativeSign? 0
79 * - NegativeSign? NonZeroDigit ( Digit+ )?
80 */
81const integerStringRegExp = /^-?(?:0|[1-9][0-9]*)$/;