1import type {
2 FieldNode,
3 DirectiveNode,
4 OperationDefinitionNode,
5} from '@0no-co/graphql.web';
6import { valueFromASTUntyped } from '@0no-co/graphql.web';
7
8import { getName } from './node';
9
10import type { Variables } from '../types';
11
12/** Evaluates a fields arguments taking vars into account */
13export const getFieldArguments = (
14 node: FieldNode | DirectiveNode,
15 vars: Variables
16): null | Variables => {
17 let args: null | Variables = null;
18 if (node.arguments) {
19 for (let i = 0, l = node.arguments.length; i < l; i++) {
20 const arg = node.arguments[i];
21 const value = valueFromASTUntyped(arg.value, vars);
22 if (value !== undefined && value !== null) {
23 if (!args) args = {};
24 args[getName(arg)] = value as any;
25 }
26 }
27 }
28 return args;
29};
30
31/** Returns a filtered form of variables with values missing that the query doesn't require */
32export const filterVariables = (
33 node: OperationDefinitionNode,
34 input: void | object
35) => {
36 if (!input || !node.variableDefinitions) {
37 return undefined;
38 }
39
40 const vars = {};
41 for (let i = 0, l = node.variableDefinitions.length; i < l; i++) {
42 const name = getName(node.variableDefinitions[i].variable);
43 vars[name] = input[name];
44 }
45
46 return vars;
47};
48
49/** Returns a normalized form of variables with defaulted values */
50export const normalizeVariables = (
51 node: OperationDefinitionNode,
52 input: void | Record<string, unknown>
53): Variables => {
54 const vars = {};
55 if (!input) return vars;
56
57 if (node.variableDefinitions) {
58 for (let i = 0, l = node.variableDefinitions.length; i < l; i++) {
59 const def = node.variableDefinitions[i];
60 const name = getName(def.variable);
61 vars[name] =
62 input[name] === undefined && def.defaultValue
63 ? valueFromASTUntyped(def.defaultValue, input)
64 : input[name];
65 }
66 }
67
68 for (const key in input) {
69 if (!(key in vars)) vars[key] = input[key];
70 }
71
72 return vars;
73};