visitResult.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.visitResult = exports.visitErrors = exports.visitData = void 0;
  4. const getOperationASTFromRequest_js_1 = require("./getOperationASTFromRequest.js");
  5. const graphql_1 = require("graphql");
  6. const collectFields_js_1 = require("./collectFields.js");
  7. function 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. }
  25. exports.visitData = visitData;
  26. function visitErrors(errors, visitor) {
  27. return errors.map(error => visitor(error));
  28. }
  29. exports.visitErrors = visitErrors;
  30. function 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. }
  54. exports.visitResult = visitResult;
  55. function 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. }
  78. function 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. }
  88. function visitRoot(root, operation, schema, fragments, variableValues, resultVisitorMap, errors, errorInfo) {
  89. const operationRootType = getOperationRootType(schema, operation);
  90. const collectedFields = (0, collectFields_js_1.collectFields)(schema, fragments, variableValues, operationRootType, operation.selectionSet, new Map(), new Set());
  91. return visitObjectValue(root, operationRootType, collectedFields, schema, fragments, variableValues, resultVisitorMap, 0, errors, errorInfo);
  92. }
  93. function visitObjectValue(object, type, fieldNodeMap, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo) {
  94. var _a;
  95. const fieldMap = type.getFields();
  96. const typeVisitorMap = resultVisitorMap === null || resultVisitorMap === void 0 ? void 0 : resultVisitorMap[type.name];
  97. const enterObject = typeVisitorMap === null || typeVisitorMap === void 0 ? void 0 : typeVisitorMap.__enter;
  98. const newObject = enterObject != null ? enterObject(object) : object;
  99. let sortedErrors;
  100. let errorMap = null;
  101. if (errors != null) {
  102. sortedErrors = sortErrorsByPathSegment(errors, pathIndex);
  103. errorMap = sortedErrors.errorMap;
  104. for (const error of sortedErrors.unpathedErrors) {
  105. errorInfo.unpathedErrors.add(error);
  106. }
  107. }
  108. for (const [responseKey, subFieldNodes] of fieldNodeMap) {
  109. const fieldName = subFieldNodes[0].name.value;
  110. let fieldType = (_a = fieldMap[fieldName]) === null || _a === void 0 ? void 0 : _a.type;
  111. if (fieldType == null) {
  112. switch (fieldName) {
  113. case '__typename':
  114. fieldType = graphql_1.TypeNameMetaFieldDef.type;
  115. break;
  116. case '__schema':
  117. fieldType = graphql_1.SchemaMetaFieldDef.type;
  118. break;
  119. }
  120. }
  121. const newPathIndex = pathIndex + 1;
  122. let fieldErrors;
  123. if (errorMap) {
  124. fieldErrors = errorMap[responseKey];
  125. if (fieldErrors != null) {
  126. delete errorMap[responseKey];
  127. }
  128. addPathSegmentInfo(type, fieldName, newPathIndex, fieldErrors, errorInfo);
  129. }
  130. const newValue = visitFieldValue(object[responseKey], fieldType, subFieldNodes, schema, fragments, variableValues, resultVisitorMap, newPathIndex, fieldErrors, errorInfo);
  131. updateObject(newObject, responseKey, newValue, typeVisitorMap, fieldName);
  132. }
  133. const oldTypename = newObject.__typename;
  134. if (oldTypename != null) {
  135. updateObject(newObject, '__typename', oldTypename, typeVisitorMap, '__typename');
  136. }
  137. if (errorMap) {
  138. for (const errorsKey in errorMap) {
  139. const errors = errorMap[errorsKey];
  140. for (const error of errors) {
  141. errorInfo.unpathedErrors.add(error);
  142. }
  143. }
  144. }
  145. const leaveObject = typeVisitorMap === null || typeVisitorMap === void 0 ? void 0 : typeVisitorMap.__leave;
  146. return leaveObject != null ? leaveObject(newObject) : newObject;
  147. }
  148. function updateObject(object, responseKey, newValue, typeVisitorMap, fieldName) {
  149. if (typeVisitorMap == null) {
  150. object[responseKey] = newValue;
  151. return;
  152. }
  153. const fieldVisitor = typeVisitorMap[fieldName];
  154. if (fieldVisitor == null) {
  155. object[responseKey] = newValue;
  156. return;
  157. }
  158. const visitedValue = fieldVisitor(newValue);
  159. if (visitedValue === undefined) {
  160. delete object[responseKey];
  161. return;
  162. }
  163. object[responseKey] = visitedValue;
  164. }
  165. function visitListValue(list, returnType, fieldNodes, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo) {
  166. return list.map(listMember => visitFieldValue(listMember, returnType, fieldNodes, schema, fragments, variableValues, resultVisitorMap, pathIndex + 1, errors, errorInfo));
  167. }
  168. function visitFieldValue(value, returnType, fieldNodes, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors = [], errorInfo) {
  169. if (value == null) {
  170. return value;
  171. }
  172. const nullableType = (0, graphql_1.getNullableType)(returnType);
  173. if ((0, graphql_1.isListType)(nullableType)) {
  174. return visitListValue(value, nullableType.ofType, fieldNodes, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo);
  175. }
  176. else if ((0, graphql_1.isAbstractType)(nullableType)) {
  177. const finalType = schema.getType(value.__typename);
  178. const collectedFields = (0, collectFields_js_1.collectSubFields)(schema, fragments, variableValues, finalType, fieldNodes);
  179. return visitObjectValue(value, finalType, collectedFields, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo);
  180. }
  181. else if ((0, graphql_1.isObjectType)(nullableType)) {
  182. const collectedFields = (0, collectFields_js_1.collectSubFields)(schema, fragments, variableValues, nullableType, fieldNodes);
  183. return visitObjectValue(value, nullableType, collectedFields, schema, fragments, variableValues, resultVisitorMap, pathIndex, errors, errorInfo);
  184. }
  185. const typeVisitorMap = resultVisitorMap === null || resultVisitorMap === void 0 ? void 0 : resultVisitorMap[nullableType.name];
  186. if (typeVisitorMap == null) {
  187. return value;
  188. }
  189. const visitedValue = typeVisitorMap(value);
  190. return visitedValue === undefined ? value : visitedValue;
  191. }
  192. function sortErrorsByPathSegment(errors, pathIndex) {
  193. var _a;
  194. const errorMap = Object.create(null);
  195. const unpathedErrors = new Set();
  196. for (const error of errors) {
  197. const pathSegment = (_a = error.path) === null || _a === void 0 ? void 0 : _a[pathIndex];
  198. if (pathSegment == null) {
  199. unpathedErrors.add(error);
  200. continue;
  201. }
  202. if (pathSegment in errorMap) {
  203. errorMap[pathSegment].push(error);
  204. }
  205. else {
  206. errorMap[pathSegment] = [error];
  207. }
  208. }
  209. return {
  210. errorMap,
  211. unpathedErrors,
  212. };
  213. }
  214. function addPathSegmentInfo(type, fieldName, pathIndex, errors = [], errorInfo) {
  215. for (const error of errors) {
  216. const segmentInfo = {
  217. type,
  218. fieldName,
  219. pathIndex,
  220. };
  221. const pathSegmentsInfo = errorInfo.segmentInfoMap.get(error);
  222. if (pathSegmentsInfo == null) {
  223. errorInfo.segmentInfoMap.set(error, [segmentInfo]);
  224. }
  225. else {
  226. pathSegmentsInfo.push(segmentInfo);
  227. }
  228. }
  229. }