UNPKG

12.9 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 => { var _a, _b; return ((_b = (_a = fragmentNode === null || fragmentNode === void 0 ? void 0 : fragmentNode.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) === null || _b === void 0 ? void 0 : _b.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 => { var _a, _b; return ((_b = (_a = fragmentNode === null || fragmentNode === void 0 ? void 0 : fragmentNode.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) === null || _b === void 0 ? void 0 : _b.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 var _a, _b;
212 if (f == null) {
213 return false;
214 }
215 else if ('selectionSet' in f) {
216 return !!((_b = (_a = f.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) === null || _b === void 0 ? void 0 : _b.length);
217 }
218 return true;
219 }),
220 };
221 }
222}
223function resolveVariable(arg, name) {
224 function resolveVariableType(type) {
225 if ((0, graphql_1.isListType)(type)) {
226 return {
227 kind: graphql_1.Kind.LIST_TYPE,
228 type: resolveVariableType(type.ofType),
229 };
230 }
231 if ((0, graphql_1.isNonNullType)(type)) {
232 return {
233 kind: graphql_1.Kind.NON_NULL_TYPE,
234 // for v16 compatibility
235 type: resolveVariableType(type.ofType),
236 };
237 }
238 return {
239 kind: graphql_1.Kind.NAMED_TYPE,
240 name: {
241 kind: graphql_1.Kind.NAME,
242 value: type.name,
243 },
244 };
245 }
246 return {
247 kind: graphql_1.Kind.VARIABLE_DEFINITION,
248 variable: {
249 kind: graphql_1.Kind.VARIABLE,
250 name: {
251 kind: graphql_1.Kind.NAME,
252 value: name || arg.name,
253 },
254 },
255 type: resolveVariableType(arg.type),
256 };
257}
258function getArgumentName(name, path) {
259 return [...path, name].join('_');
260}
261function resolveField({ type, field, models, firstCall, path, ancestors, ignore, depthLimit, circularReferenceDepth, schema, depth, argNames, selectedFields, rootTypeNames, }) {
262 const namedType = (0, graphql_1.getNamedType)(field.type);
263 let args = [];
264 let removeField = false;
265 if (field.args && field.args.length) {
266 args = field.args
267 .map(arg => {
268 const argumentName = getArgumentName(arg.name, path);
269 if (argNames && !argNames.includes(argumentName)) {
270 if ((0, graphql_1.isNonNullType)(arg.type)) {
271 removeField = true;
272 }
273 return null;
274 }
275 if (!firstCall) {
276 addOperationVariable(resolveVariable(arg, argumentName));
277 }
278 return {
279 kind: graphql_1.Kind.ARGUMENT,
280 name: {
281 kind: graphql_1.Kind.NAME,
282 value: arg.name,
283 },
284 value: {
285 kind: graphql_1.Kind.VARIABLE,
286 name: {
287 kind: graphql_1.Kind.NAME,
288 value: getArgumentName(arg.name, path),
289 },
290 },
291 };
292 })
293 .filter(Boolean);
294 }
295 if (removeField) {
296 return null;
297 }
298 const fieldPath = [...path, field.name];
299 const fieldPathStr = fieldPath.join('.');
300 let fieldName = field.name;
301 if (fieldTypeMap.has(fieldPathStr) && fieldTypeMap.get(fieldPathStr) !== field.type.toString()) {
302 fieldName += field.type.toString().replace('!', 'NonNull');
303 }
304 fieldTypeMap.set(fieldPathStr, field.type.toString());
305 if (!(0, graphql_1.isScalarType)(namedType) && !(0, graphql_1.isEnumType)(namedType)) {
306 return {
307 kind: graphql_1.Kind.FIELD,
308 name: {
309 kind: graphql_1.Kind.NAME,
310 value: field.name,
311 },
312 ...(fieldName !== field.name && { alias: { kind: graphql_1.Kind.NAME, value: fieldName } }),
313 selectionSet: resolveSelectionSet({
314 parent: type,
315 type: namedType,
316 models,
317 firstCall,
318 path: fieldPath,
319 ancestors: [...ancestors, type],
320 ignore,
321 depthLimit,
322 circularReferenceDepth,
323 schema,
324 depth: depth + 1,
325 argNames,
326 selectedFields,
327 rootTypeNames,
328 }) || undefined,
329 arguments: args,
330 };
331 }
332 return {
333 kind: graphql_1.Kind.FIELD,
334 name: {
335 kind: graphql_1.Kind.NAME,
336 value: field.name,
337 },
338 ...(fieldName !== field.name && { alias: { kind: graphql_1.Kind.NAME, value: fieldName } }),
339 arguments: args,
340 };
341}
342function hasCircularRef(types, config = {
343 depth: 1,
344}) {
345 const type = types[types.length - 1];
346 if ((0, graphql_1.isScalarType)(type)) {
347 return false;
348 }
349 const size = types.filter(t => t.name === type.name).length;
350 return size > config.depth;
351}