UNPKG

7 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.collectSubFields = exports.getDeferValues = exports.getFieldEntryKey = exports.doesFragmentConditionMatch = exports.shouldIncludeNode = exports.collectFields = void 0;
4const graphql_1 = require("graphql");
5const AccumulatorMap_js_1 = require("./AccumulatorMap.js");
6const directives_js_1 = require("./directives.js");
7const memoize_js_1 = require("./memoize.js");
8function collectFieldsImpl(schema, fragments, variableValues, runtimeType, selectionSet, fields, patches, visitedFragmentNames) {
9 for (const selection of selectionSet.selections) {
10 switch (selection.kind) {
11 case graphql_1.Kind.FIELD: {
12 if (!shouldIncludeNode(variableValues, selection)) {
13 continue;
14 }
15 fields.add(getFieldEntryKey(selection), selection);
16 break;
17 }
18 case graphql_1.Kind.INLINE_FRAGMENT: {
19 if (!shouldIncludeNode(variableValues, selection) ||
20 !doesFragmentConditionMatch(schema, selection, runtimeType)) {
21 continue;
22 }
23 const defer = getDeferValues(variableValues, selection);
24 if (defer) {
25 const patchFields = new AccumulatorMap_js_1.AccumulatorMap();
26 collectFieldsImpl(schema, fragments, variableValues, runtimeType, selection.selectionSet, patchFields, patches, visitedFragmentNames);
27 patches.push({
28 label: defer.label,
29 fields: patchFields,
30 });
31 }
32 else {
33 collectFieldsImpl(schema, fragments, variableValues, runtimeType, selection.selectionSet, fields, patches, visitedFragmentNames);
34 }
35 break;
36 }
37 case graphql_1.Kind.FRAGMENT_SPREAD: {
38 const fragName = selection.name.value;
39 if (!shouldIncludeNode(variableValues, selection)) {
40 continue;
41 }
42 const defer = getDeferValues(variableValues, selection);
43 if (visitedFragmentNames.has(fragName) && !defer) {
44 continue;
45 }
46 const fragment = fragments[fragName];
47 if (!fragment || !doesFragmentConditionMatch(schema, fragment, runtimeType)) {
48 continue;
49 }
50 if (!defer) {
51 visitedFragmentNames.add(fragName);
52 }
53 if (defer) {
54 const patchFields = new AccumulatorMap_js_1.AccumulatorMap();
55 collectFieldsImpl(schema, fragments, variableValues, runtimeType, fragment.selectionSet, patchFields, patches, visitedFragmentNames);
56 patches.push({
57 label: defer.label,
58 fields: patchFields,
59 });
60 }
61 else {
62 collectFieldsImpl(schema, fragments, variableValues, runtimeType, fragment.selectionSet, fields, patches, visitedFragmentNames);
63 }
64 break;
65 }
66 }
67 }
68}
69/**
70 * Given a selectionSet, collects all of the fields and returns them.
71 *
72 * CollectFields requires the "runtime type" of an object. For a field that
73 * returns an Interface or Union type, the "runtime type" will be the actual
74 * object type returned by that field.
75 *
76 */
77function collectFields(schema, fragments, variableValues, runtimeType, selectionSet) {
78 const fields = new AccumulatorMap_js_1.AccumulatorMap();
79 const patches = [];
80 collectFieldsImpl(schema, fragments, variableValues, runtimeType, selectionSet, fields, patches, new Set());
81 return { fields, patches };
82}
83exports.collectFields = collectFields;
84/**
85 * Determines if a field should be included based on the `@include` and `@skip`
86 * directives, where `@skip` has higher precedence than `@include`.
87 */
88function shouldIncludeNode(variableValues, node) {
89 const skip = (0, graphql_1.getDirectiveValues)(graphql_1.GraphQLSkipDirective, node, variableValues);
90 if (skip?.['if'] === true) {
91 return false;
92 }
93 const include = (0, graphql_1.getDirectiveValues)(graphql_1.GraphQLIncludeDirective, node, variableValues);
94 if (include?.['if'] === false) {
95 return false;
96 }
97 return true;
98}
99exports.shouldIncludeNode = shouldIncludeNode;
100/**
101 * Determines if a fragment is applicable to the given type.
102 */
103function doesFragmentConditionMatch(schema, fragment, type) {
104 const typeConditionNode = fragment.typeCondition;
105 if (!typeConditionNode) {
106 return true;
107 }
108 const conditionalType = (0, graphql_1.typeFromAST)(schema, typeConditionNode);
109 if (conditionalType === type) {
110 return true;
111 }
112 if ((0, graphql_1.isAbstractType)(conditionalType)) {
113 const possibleTypes = schema.getPossibleTypes(conditionalType);
114 return possibleTypes.includes(type);
115 }
116 return false;
117}
118exports.doesFragmentConditionMatch = doesFragmentConditionMatch;
119/**
120 * Implements the logic to compute the key of a given field's entry
121 */
122function getFieldEntryKey(node) {
123 return node.alias ? node.alias.value : node.name.value;
124}
125exports.getFieldEntryKey = getFieldEntryKey;
126/**
127 * Returns an object containing the `@defer` arguments if a field should be
128 * deferred based on the experimental flag, defer directive present and
129 * not disabled by the "if" argument.
130 */
131function getDeferValues(variableValues, node) {
132 const defer = (0, graphql_1.getDirectiveValues)(directives_js_1.GraphQLDeferDirective, node, variableValues);
133 if (!defer) {
134 return;
135 }
136 if (defer['if'] === false) {
137 return;
138 }
139 return {
140 label: typeof defer['label'] === 'string' ? defer['label'] : undefined,
141 };
142}
143exports.getDeferValues = getDeferValues;
144/**
145 * Given an array of field nodes, collects all of the subfields of the passed
146 * in fields, and returns them at the end.
147 *
148 * CollectSubFields requires the "return type" of an object. For a field that
149 * returns an Interface or Union type, the "return type" will be the actual
150 * object type returned by that field.
151 *
152 */
153exports.collectSubFields = (0, memoize_js_1.memoize5)(function collectSubfields(schema, fragments, variableValues, returnType, fieldNodes) {
154 const subFieldNodes = new AccumulatorMap_js_1.AccumulatorMap();
155 const visitedFragmentNames = new Set();
156 const subPatches = [];
157 const subFieldsAndPatches = {
158 fields: subFieldNodes,
159 patches: subPatches,
160 };
161 for (const node of fieldNodes) {
162 if (node.selectionSet) {
163 collectFieldsImpl(schema, fragments, variableValues, returnType, node.selectionSet, subFieldNodes, subPatches, visitedFragmentNames);
164 }
165 }
166 return subFieldsAndPatches;
167});