UNPKG

6.78 kBJavaScriptView Raw
1import { visit, isListType, isObjectType, Kind, isNonNullType, } from 'graphql';
2import { getBaseType } from './utils.js';
3export function isOutputConfigArray(type) {
4 return Array.isArray(type);
5}
6export function isConfiguredOutput(type) {
7 return (typeof type === 'object' && type.plugins) || type.preset;
8}
9export function normalizeOutputParam(config) {
10 // In case of direct array with a list of plugins
11 if (isOutputConfigArray(config)) {
12 return {
13 documents: [],
14 schema: [],
15 plugins: isConfiguredOutput(config) ? config.plugins : config,
16 };
17 }
18 if (isConfiguredOutput(config)) {
19 return config;
20 }
21 throw new Error(`Invalid "generates" config!`);
22}
23export function normalizeInstanceOrArray(type) {
24 if (Array.isArray(type)) {
25 return type;
26 }
27 if (!type) {
28 return [];
29 }
30 return [type];
31}
32export function normalizeConfig(config) {
33 if (typeof config === 'string') {
34 return [{ [config]: {} }];
35 }
36 if (Array.isArray(config)) {
37 return config.map(plugin => (typeof plugin === 'string' ? { [plugin]: {} } : plugin));
38 }
39 if (typeof config === 'object') {
40 return Object.keys(config).reduce((prev, pluginName) => [...prev, { [pluginName]: config[pluginName] }], []);
41 }
42 return [];
43}
44export function hasNullableTypeRecursively(type) {
45 if (!isNonNullType(type)) {
46 return true;
47 }
48 if (isListType(type) || isNonNullType(type)) {
49 return hasNullableTypeRecursively(type.ofType);
50 }
51 return false;
52}
53export function isUsingTypes(document, externalFragments, schema) {
54 let foundFields = 0;
55 const typesStack = [];
56 visit(document, {
57 SelectionSet: {
58 enter(node, key, parent, anscestors) {
59 const insideIgnoredFragment = anscestors.find((f) => f.kind && f.kind === 'FragmentDefinition' && externalFragments.includes(f.name.value));
60 if (insideIgnoredFragment) {
61 return;
62 }
63 const selections = node.selections || [];
64 if (schema && selections.length > 0) {
65 const nextTypeName = (() => {
66 if (parent.kind === Kind.FRAGMENT_DEFINITION) {
67 return parent.typeCondition.name.value;
68 }
69 if (parent.kind === Kind.FIELD) {
70 const lastType = typesStack[typesStack.length - 1];
71 if (!lastType) {
72 throw new Error(`Unable to find parent type! Please make sure you operation passes validation`);
73 }
74 const field = lastType.getFields()[parent.name.value];
75 if (!field) {
76 throw new Error(`Unable to find field "${parent.name.value}" on type "${lastType}"!`);
77 }
78 return getBaseType(field.type).name;
79 }
80 if (parent.kind === Kind.OPERATION_DEFINITION) {
81 if (parent.operation === 'query') {
82 return schema.getQueryType().name;
83 }
84 if (parent.operation === 'mutation') {
85 return schema.getMutationType().name;
86 }
87 if (parent.operation === 'subscription') {
88 return schema.getSubscriptionType().name;
89 }
90 }
91 else if (parent.kind === Kind.INLINE_FRAGMENT) {
92 if (parent.typeCondition) {
93 return parent.typeCondition.name.value;
94 }
95 return typesStack[typesStack.length - 1].name;
96 }
97 return null;
98 })();
99 typesStack.push(schema.getType(nextTypeName));
100 }
101 },
102 leave(node) {
103 const selections = node.selections || [];
104 if (schema && selections.length > 0) {
105 typesStack.pop();
106 }
107 },
108 },
109 Field: {
110 enter: (node, key, parent, path, anscestors) => {
111 if (node.name.value.startsWith('__')) {
112 return;
113 }
114 const insideIgnoredFragment = anscestors.find((f) => f.kind && f.kind === 'FragmentDefinition' && externalFragments.includes(f.name.value));
115 if (insideIgnoredFragment) {
116 return;
117 }
118 const selections = node.selectionSet ? node.selectionSet.selections || [] : [];
119 const relevantFragmentSpreads = selections.filter(s => s.kind === Kind.FRAGMENT_SPREAD && !externalFragments.includes(s.name.value));
120 if (selections.length === 0 || relevantFragmentSpreads.length > 0) {
121 foundFields++;
122 }
123 if (schema) {
124 const lastType = typesStack[typesStack.length - 1];
125 if (lastType && isObjectType(lastType)) {
126 const field = lastType.getFields()[node.name.value];
127 if (!field) {
128 throw new Error(`Unable to find field "${node.name.value}" on type "${lastType}"!`);
129 }
130 const currentType = field.type;
131 // To handle `Maybe` usage
132 if (hasNullableTypeRecursively(currentType)) {
133 foundFields++;
134 }
135 }
136 }
137 },
138 },
139 VariableDefinition: {
140 enter: (node, key, parent, path, anscestors) => {
141 const insideIgnoredFragment = anscestors.find((f) => f.kind && f.kind === 'FragmentDefinition' && externalFragments.includes(f.name.value));
142 if (insideIgnoredFragment) {
143 return;
144 }
145 foundFields++;
146 },
147 },
148 InputValueDefinition: {
149 enter: (node, key, parent, path, anscestors) => {
150 const insideIgnoredFragment = anscestors.find((f) => f.kind && f.kind === 'FragmentDefinition' && externalFragments.includes(f.name.value));
151 if (insideIgnoredFragment) {
152 return;
153 }
154 foundFields++;
155 },
156 },
157 });
158 return foundFields > 0;
159}