UNPKG

12.5 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.buildOperationNodeForField = void 0;
4const graphql_1 = require("graphql");
5const rootTypes_js_1 = require("./rootTypes.js");
6let operationVariables = [];
7let fieldTypeMap = new Map();
8function addOperationVariable(variable) {
9 operationVariables.push(variable);
10}
11function resetOperationVariables() {
12 operationVariables = [];
13}
14function resetFieldMap() {
15 fieldTypeMap = new Map();
16}
17function buildOperationNodeForField({ schema, kind, field, models, ignore = [], depthLimit, circularReferenceDepth, argNames, selectedFields = true, }) {
18 resetOperationVariables();
19 resetFieldMap();
20 const rootTypeNames = (0, rootTypes_js_1.getRootTypeNames)(schema);
21 const operationNode = buildOperationAndCollectVariables({
22 schema,
23 fieldName: field,
24 kind,
25 models: models || [],
26 ignore,
27 depthLimit: depthLimit || Infinity,
28 circularReferenceDepth: circularReferenceDepth || 1,
29 argNames,
30 selectedFields,
31 rootTypeNames,
32 });
33 // attach variables
34 operationNode.variableDefinitions = [...operationVariables];
35 resetOperationVariables();
36 resetFieldMap();
37 return operationNode;
38}
39exports.buildOperationNodeForField = buildOperationNodeForField;
40function buildOperationAndCollectVariables({ schema, fieldName, kind, models, ignore, depthLimit, circularReferenceDepth, argNames, selectedFields, rootTypeNames, }) {
41 const type = (0, rootTypes_js_1.getDefinedRootType)(schema, kind);
42 const field = type.getFields()[fieldName];
43 const operationName = `${fieldName}_${kind}`;
44 if (field.args) {
45 for (const arg of field.args) {
46 const argName = arg.name;
47 if (!argNames || argNames.includes(argName)) {
48 addOperationVariable(resolveVariable(arg, argName));
49 }
50 }
51 }
52 return {
53 kind: graphql_1.Kind.OPERATION_DEFINITION,
54 operation: kind,
55 name: {
56 kind: graphql_1.Kind.NAME,
57 value: operationName,
58 },
59 variableDefinitions: [],
60 selectionSet: {
61 kind: graphql_1.Kind.SELECTION_SET,
62 selections: [
63 resolveField({
64 type,
65 field,
66 models,
67 firstCall: true,
68 path: [],
69 ancestors: [],
70 ignore,
71 depthLimit,
72 circularReferenceDepth,
73 schema,
74 depth: 0,
75 argNames,
76 selectedFields,
77 rootTypeNames,
78 }),
79 ],
80 },
81 };
82}
83function resolveSelectionSet({ parent, type, models, firstCall, path, ancestors, ignore, depthLimit, circularReferenceDepth, schema, depth, argNames, selectedFields, rootTypeNames, }) {
84 if (typeof selectedFields === 'boolean' && depth > depthLimit) {
85 return;
86 }
87 if ((0, graphql_1.isUnionType)(type)) {
88 const types = type.getTypes();
89 return {
90 kind: graphql_1.Kind.SELECTION_SET,
91 selections: types
92 .filter(t => !hasCircularRef([...ancestors, t], {
93 depth: circularReferenceDepth,
94 }))
95 .map(t => {
96 return {
97 kind: graphql_1.Kind.INLINE_FRAGMENT,
98 typeCondition: {
99 kind: graphql_1.Kind.NAMED_TYPE,
100 name: {
101 kind: graphql_1.Kind.NAME,
102 value: t.name,
103 },
104 },
105 selectionSet: resolveSelectionSet({
106 parent: type,
107 type: t,
108 models,
109 path,
110 ancestors,
111 ignore,
112 depthLimit,
113 circularReferenceDepth,
114 schema,
115 depth,
116 argNames,
117 selectedFields,
118 rootTypeNames,
119 }),
120 };
121 })
122 .filter(fragmentNode => fragmentNode?.selectionSet?.selections?.length > 0),
123 };
124 }
125 if ((0, graphql_1.isInterfaceType)(type)) {
126 const types = Object.values(schema.getTypeMap()).filter((t) => (0, graphql_1.isObjectType)(t) && t.getInterfaces().includes(type));
127 return {
128 kind: graphql_1.Kind.SELECTION_SET,
129 selections: types
130 .filter(t => !hasCircularRef([...ancestors, t], {
131 depth: circularReferenceDepth,
132 }))
133 .map(t => {
134 return {
135 kind: graphql_1.Kind.INLINE_FRAGMENT,
136 typeCondition: {
137 kind: graphql_1.Kind.NAMED_TYPE,
138 name: {
139 kind: graphql_1.Kind.NAME,
140 value: t.name,
141 },
142 },
143 selectionSet: resolveSelectionSet({
144 parent: type,
145 type: t,
146 models,
147 path,
148 ancestors,
149 ignore,
150 depthLimit,
151 circularReferenceDepth,
152 schema,
153 depth,
154 argNames,
155 selectedFields,
156 rootTypeNames,
157 }),
158 };
159 })
160 .filter(fragmentNode => fragmentNode?.selectionSet?.selections?.length > 0),
161 };
162 }
163 if ((0, graphql_1.isObjectType)(type) && !rootTypeNames.has(type.name)) {
164 const isIgnored = ignore.includes(type.name) || ignore.includes(`${parent.name}.${path[path.length - 1]}`);
165 const isModel = models.includes(type.name);
166 if (!firstCall && isModel && !isIgnored) {
167 return {
168 kind: graphql_1.Kind.SELECTION_SET,
169 selections: [
170 {
171 kind: graphql_1.Kind.FIELD,
172 name: {
173 kind: graphql_1.Kind.NAME,
174 value: 'id',
175 },
176 },
177 ],
178 };
179 }
180 const fields = type.getFields();
181 return {
182 kind: graphql_1.Kind.SELECTION_SET,
183 selections: Object.keys(fields)
184 .filter(fieldName => {
185 return !hasCircularRef([...ancestors, (0, graphql_1.getNamedType)(fields[fieldName].type)], {
186 depth: circularReferenceDepth,
187 });
188 })
189 .map(fieldName => {
190 const selectedSubFields = typeof selectedFields === 'object' ? selectedFields[fieldName] : true;
191 if (selectedSubFields) {
192 return resolveField({
193 type,
194 field: fields[fieldName],
195 models,
196 path: [...path, fieldName],
197 ancestors,
198 ignore,
199 depthLimit,
200 circularReferenceDepth,
201 schema,
202 depth,
203 argNames,
204 selectedFields: selectedSubFields,
205 rootTypeNames,
206 });
207 }
208 return null;
209 })
210 .filter((f) => {
211 if (f == null) {
212 return false;
213 }
214 else if ('selectionSet' in f) {
215 return !!f.selectionSet?.selections?.length;
216 }
217 return true;
218 }),
219 };
220 }
221}
222function resolveVariable(arg, name) {
223 function resolveVariableType(type) {
224 if ((0, graphql_1.isListType)(type)) {
225 return {
226 kind: graphql_1.Kind.LIST_TYPE,
227 type: resolveVariableType(type.ofType),
228 };
229 }
230 if ((0, graphql_1.isNonNullType)(type)) {
231 return {
232 kind: graphql_1.Kind.NON_NULL_TYPE,
233 // for v16 compatibility
234 type: resolveVariableType(type.ofType),
235 };
236 }
237 return {
238 kind: graphql_1.Kind.NAMED_TYPE,
239 name: {
240 kind: graphql_1.Kind.NAME,
241 value: type.name,
242 },
243 };
244 }
245 return {
246 kind: graphql_1.Kind.VARIABLE_DEFINITION,
247 variable: {
248 kind: graphql_1.Kind.VARIABLE,
249 name: {
250 kind: graphql_1.Kind.NAME,
251 value: name || arg.name,
252 },
253 },
254 type: resolveVariableType(arg.type),
255 };
256}
257function getArgumentName(name, path) {
258 return [...path, name].join('_');
259}
260function resolveField({ type, field, models, firstCall, path, ancestors, ignore, depthLimit, circularReferenceDepth, schema, depth, argNames, selectedFields, rootTypeNames, }) {
261 const namedType = (0, graphql_1.getNamedType)(field.type);
262 let args = [];
263 let removeField = false;
264 if (field.args && field.args.length) {
265 args = field.args
266 .map(arg => {
267 const argumentName = getArgumentName(arg.name, path);
268 if (argNames && !argNames.includes(argumentName)) {
269 if ((0, graphql_1.isNonNullType)(arg.type)) {
270 removeField = true;
271 }
272 return null;
273 }
274 if (!firstCall) {
275 addOperationVariable(resolveVariable(arg, argumentName));
276 }
277 return {
278 kind: graphql_1.Kind.ARGUMENT,
279 name: {
280 kind: graphql_1.Kind.NAME,
281 value: arg.name,
282 },
283 value: {
284 kind: graphql_1.Kind.VARIABLE,
285 name: {
286 kind: graphql_1.Kind.NAME,
287 value: getArgumentName(arg.name, path),
288 },
289 },
290 };
291 })
292 .filter(Boolean);
293 }
294 if (removeField) {
295 return null;
296 }
297 const fieldPath = [...path, field.name];
298 const fieldPathStr = fieldPath.join('.');
299 let fieldName = field.name;
300 if (fieldTypeMap.has(fieldPathStr) && fieldTypeMap.get(fieldPathStr) !== field.type.toString()) {
301 fieldName += field.type
302 .toString()
303 .replace('!', 'NonNull')
304 .replace('[', 'List')
305 .replace(']', '');
306 }
307 fieldTypeMap.set(fieldPathStr, field.type.toString());
308 if (!(0, graphql_1.isScalarType)(namedType) && !(0, graphql_1.isEnumType)(namedType)) {
309 return {
310 kind: graphql_1.Kind.FIELD,
311 name: {
312 kind: graphql_1.Kind.NAME,
313 value: field.name,
314 },
315 ...(fieldName !== field.name && { alias: { kind: graphql_1.Kind.NAME, value: fieldName } }),
316 selectionSet: resolveSelectionSet({
317 parent: type,
318 type: namedType,
319 models,
320 firstCall,
321 path: fieldPath,
322 ancestors: [...ancestors, type],
323 ignore,
324 depthLimit,
325 circularReferenceDepth,
326 schema,
327 depth: depth + 1,
328 argNames,
329 selectedFields,
330 rootTypeNames,
331 }) || undefined,
332 arguments: args,
333 };
334 }
335 return {
336 kind: graphql_1.Kind.FIELD,
337 name: {
338 kind: graphql_1.Kind.NAME,
339 value: field.name,
340 },
341 ...(fieldName !== field.name && { alias: { kind: graphql_1.Kind.NAME, value: fieldName } }),
342 arguments: args,
343 };
344}
345function hasCircularRef(types, config = {
346 depth: 1,
347}) {
348 const type = types[types.length - 1];
349 if ((0, graphql_1.isScalarType)(type)) {
350 return false;
351 }
352 const size = types.filter(t => t.name === type.name).length;
353 return size > config.depth;
354}