UNPKG

11 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.visitResult = exports.visitErrors = exports.visitData = void 0;
4const graphql_1 = require("graphql");
5const collectFields_js_1 = require("./collectFields.js");
6const getOperationASTFromRequest_js_1 = require("./getOperationASTFromRequest.js");
7function visitData(data, enter, leave) {
8 if (Array.isArray(data)) {
9 return data.map(value => visitData(value, enter, leave));
10 }
11 else if (typeof data === 'object') {
12 const newData = enter != null ? enter(data) : data;
13 if (newData != null) {
14 for (const key in newData) {
15 const value = newData[key];
16 Object.defineProperty(newData, key, {
17 value: visitData(value, enter, leave),
18 });
19 }
20 }
21 return leave != null ? leave(newData) : newData;
22 }
23 return data;
24}
25exports.visitData = visitData;
26function visitErrors(errors, visitor) {
27 return errors.map(error => visitor(error));
28}
29exports.visitErrors = visitErrors;
30function visitResult(result, request, schema, resultVisitorMap, errorVisitorMap) {
31 const fragments = request.document.definitions.reduce((acc, def) => {
32 if (def.kind === graphql_1.Kind.FRAGMENT_DEFINITION) {
33 acc[def.name.value] = def;
34 }
35 return acc;
36 }, {});
37 const variableValues = request.variables || {};
38 const errorInfo = {
39 segmentInfoMap: new Map(),
40 unpathedErrors: new Set(),
41 };
42 const data = result.data;
43 const errors = result.errors;
44 const visitingErrors = errors != null && errorVisitorMap != null;
45 const operationDocumentNode = (0, getOperationASTFromRequest_js_1.getOperationASTFromRequest)(request);
46 if (data != null && operationDocumentNode != null) {
47 result.data = visitRoot(data, operationDocumentNode, schema, fragments, variableValues, resultVisitorMap, visitingErrors ? errors : undefined, errorInfo);
48 }
49 if (errors != null && errorVisitorMap) {
50 result.errors = visitErrorsByType(errors, errorVisitorMap, errorInfo);
51 }
52 return result;
53}
54exports.visitResult = visitResult;
55function visitErrorsByType(errors, errorVisitorMap, errorInfo) {
56 const segmentInfoMap = errorInfo.segmentInfoMap;
57 const unpathedErrors = errorInfo.unpathedErrors;
58 const unpathedErrorVisitor = errorVisitorMap['__unpathed'];
59 return errors.map(originalError => {
60 const pathSegmentsInfo = segmentInfoMap.get(originalError);
61 const newError = pathSegmentsInfo == null
62 ? originalError
63 : pathSegmentsInfo.reduceRight((acc, segmentInfo) => {
64 const typeName = segmentInfo.type.name;
65 const typeVisitorMap = errorVisitorMap[typeName];
66 if (typeVisitorMap == null) {
67 return acc;
68 }
69 const errorVisitor = typeVisitorMap[segmentInfo.fieldName];
70 return errorVisitor == null ? acc : errorVisitor(acc, segmentInfo.pathIndex);
71 }, originalError);
72 if (unpathedErrorVisitor && unpathedErrors.has(originalError)) {
73 return unpathedErrorVisitor(newError);
74 }
75 return newError;
76 });
77}
78function getOperationRootType(schema, operationDef) {
79 switch (operationDef.operation) {
80 case 'query':
81 return schema.getQueryType();
82 case 'mutation':
83 return schema.getMutationType();
84 case 'subscription':
85 return schema.getSubscriptionType();
86 }
87}
88function visitRoot(root, operation, schema, fragments, variableValues, resultVisitorMap, errors, errorInfo) {
89 const operationRootType = getOperationRootType(schema, operation);
90 const { fields: collectedFields } = (0, collectFields_js_1.collectFields)(schema, fragments, variableValues, operationRootType, operation.selectionSet);
91 return visitObjectValue(root, operationRootType, collectedFields, schema, fragments, variableValues, resultVisitorMap, 0, errors, errorInfo);
92}
93function visitObjectValue(object, type, fieldNodeMap, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo) {
94 const fieldMap = type.getFields();
95 const typeVisitorMap = resultVisitorMap?.[type.name];
96 const enterObject = typeVisitorMap?.__enter;
97 const newObject = enterObject != null ? enterObject(object) : object;
98 let sortedErrors;
99 let errorMap = null;
100 if (errors != null) {
101 sortedErrors = sortErrorsByPathSegment(errors, pathIndex);
102 errorMap = sortedErrors.errorMap;
103 for (const error of sortedErrors.unpathedErrors) {
104 errorInfo.unpathedErrors.add(error);
105 }
106 }
107 for (const [responseKey, subFieldNodes] of fieldNodeMap) {
108 const fieldName = subFieldNodes[0].name.value;
109 let fieldType = fieldMap[fieldName]?.type;
110 if (fieldType == null) {
111 switch (fieldName) {
112 case '__typename':
113 fieldType = graphql_1.TypeNameMetaFieldDef.type;
114 break;
115 case '__schema':
116 fieldType = graphql_1.SchemaMetaFieldDef.type;
117 break;
118 case '__type':
119 fieldType = graphql_1.TypeMetaFieldDef.type;
120 break;
121 }
122 }
123 const newPathIndex = pathIndex + 1;
124 let fieldErrors;
125 if (errorMap) {
126 fieldErrors = errorMap[responseKey];
127 if (fieldErrors != null) {
128 delete errorMap[responseKey];
129 }
130 addPathSegmentInfo(type, fieldName, newPathIndex, fieldErrors, errorInfo);
131 }
132 const newValue = visitFieldValue(object[responseKey], fieldType, subFieldNodes, schema, fragments, variableValues, resultVisitorMap, newPathIndex, fieldErrors, errorInfo);
133 updateObject(newObject, responseKey, newValue, typeVisitorMap, fieldName);
134 }
135 const oldTypename = newObject.__typename;
136 if (oldTypename != null) {
137 updateObject(newObject, '__typename', oldTypename, typeVisitorMap, '__typename');
138 }
139 if (errorMap) {
140 for (const errorsKey in errorMap) {
141 const errors = errorMap[errorsKey];
142 for (const error of errors) {
143 errorInfo.unpathedErrors.add(error);
144 }
145 }
146 }
147 const leaveObject = typeVisitorMap?.__leave;
148 return leaveObject != null ? leaveObject(newObject) : newObject;
149}
150function updateObject(object, responseKey, newValue, typeVisitorMap, fieldName) {
151 if (typeVisitorMap == null) {
152 object[responseKey] = newValue;
153 return;
154 }
155 const fieldVisitor = typeVisitorMap[fieldName];
156 if (fieldVisitor == null) {
157 object[responseKey] = newValue;
158 return;
159 }
160 const visitedValue = fieldVisitor(newValue);
161 if (visitedValue === undefined) {
162 delete object[responseKey];
163 return;
164 }
165 object[responseKey] = visitedValue;
166}
167function visitListValue(list, returnType, fieldNodes, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo) {
168 return list.map(listMember => visitFieldValue(listMember, returnType, fieldNodes, schema, fragments, variableValues, resultVisitorMap, pathIndex + 1, errors, errorInfo));
169}
170function visitFieldValue(value, returnType, fieldNodes, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors = [], errorInfo) {
171 if (value == null) {
172 return value;
173 }
174 const nullableType = (0, graphql_1.getNullableType)(returnType);
175 if ((0, graphql_1.isListType)(nullableType)) {
176 return visitListValue(value, nullableType.ofType, fieldNodes, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo);
177 }
178 else if ((0, graphql_1.isAbstractType)(nullableType)) {
179 const finalType = schema.getType(value.__typename);
180 let { fields: collectedFields, patches } = (0, collectFields_js_1.collectSubFields)(schema, fragments, variableValues, finalType, fieldNodes);
181 if (patches.length) {
182 collectedFields = new Map(collectedFields);
183 for (const patch of patches) {
184 for (const [responseKey, fields] of patch.fields) {
185 const existingFields = collectedFields.get(responseKey);
186 if (existingFields) {
187 existingFields.push(...fields);
188 }
189 else {
190 collectedFields.set(responseKey, fields);
191 }
192 }
193 }
194 }
195 return visitObjectValue(value, finalType, collectedFields, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo);
196 }
197 else if ((0, graphql_1.isObjectType)(nullableType)) {
198 let { fields: collectedFields, patches } = (0, collectFields_js_1.collectSubFields)(schema, fragments, variableValues, nullableType, fieldNodes);
199 if (patches.length) {
200 collectedFields = new Map(collectedFields);
201 for (const patch of patches) {
202 for (const [responseKey, fields] of patch.fields) {
203 const existingFields = collectedFields.get(responseKey);
204 if (existingFields) {
205 existingFields.push(...fields);
206 }
207 else {
208 collectedFields.set(responseKey, fields);
209 }
210 }
211 }
212 }
213 return visitObjectValue(value, nullableType, collectedFields, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo);
214 }
215 const typeVisitorMap = resultVisitorMap?.[nullableType.name];
216 if (typeVisitorMap == null) {
217 return value;
218 }
219 const visitedValue = typeVisitorMap(value);
220 return visitedValue === undefined ? value : visitedValue;
221}
222function sortErrorsByPathSegment(errors, pathIndex) {
223 const errorMap = Object.create(null);
224 const unpathedErrors = new Set();
225 for (const error of errors) {
226 const pathSegment = error.path?.[pathIndex];
227 if (pathSegment == null) {
228 unpathedErrors.add(error);
229 continue;
230 }
231 if (pathSegment in errorMap) {
232 errorMap[pathSegment].push(error);
233 }
234 else {
235 errorMap[pathSegment] = [error];
236 }
237 }
238 return {
239 errorMap,
240 unpathedErrors,
241 };
242}
243function addPathSegmentInfo(type, fieldName, pathIndex, errors = [], errorInfo) {
244 for (const error of errors) {
245 const segmentInfo = {
246 type,
247 fieldName,
248 pathIndex,
249 };
250 const pathSegmentsInfo = errorInfo.segmentInfoMap.get(error);
251 if (pathSegmentsInfo == null) {
252 errorInfo.segmentInfoMap.set(error, [segmentInfo]);
253 }
254 else {
255 pathSegmentsInfo.push(segmentInfo);
256 }
257 }
258}