1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | 'use strict';
|
11 |
|
12 | var _objectSpread2 = require("@babel/runtime/helpers/interopRequireDefault")(require("@babel/runtime/helpers/objectSpread"));
|
13 |
|
14 | var _toConsumableArray2 = require("@babel/runtime/helpers/interopRequireDefault")(require("@babel/runtime/helpers/toConsumableArray"));
|
15 |
|
16 | var CONNECTION = 'connection';
|
17 | var HANDLER = 'handler';
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | function relayConnectionTransform(context) {
|
30 | return require("./GraphQLIRTransformer").transform(context, {
|
31 | Fragment: visitFragmentOrRoot,
|
32 | LinkedField: visitLinkedOrMatchField,
|
33 | MatchField: visitLinkedOrMatchField,
|
34 | Root: visitFragmentOrRoot
|
35 | }, function (node) {
|
36 | return {
|
37 | path: [],
|
38 | connectionMetadata: [],
|
39 | definitionName: node.name
|
40 | };
|
41 | });
|
42 | }
|
43 |
|
44 | var SCHEMA_EXTENSION = 'directive @connection(key: String!, filters: [String], handler: String) on FIELD';
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | function visitFragmentOrRoot(node, options) {
|
50 | var transformedNode = this.traverse(node, options);
|
51 | var connectionMetadata = options.connectionMetadata;
|
52 |
|
53 | if (connectionMetadata.length) {
|
54 | return (0, _objectSpread2["default"])({}, transformedNode, {
|
55 | metadata: (0, _objectSpread2["default"])({}, transformedNode.metadata, {
|
56 | connection: connectionMetadata
|
57 | })
|
58 | });
|
59 | }
|
60 |
|
61 | return transformedNode;
|
62 | }
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 | function visitLinkedOrMatchField(field, options) {
|
69 | var _handler;
|
70 |
|
71 | var isPlural = require("./GraphQLSchemaUtils").getNullableType(field.type) instanceof require("graphql").GraphQLList;
|
72 |
|
73 | options.path.push(isPlural ? null : field.alias || field.name);
|
74 | var transformedField = this.traverse(field, options);
|
75 | var connectionDirective = field.directives.find(function (directive) {
|
76 | return directive.name === CONNECTION;
|
77 | });
|
78 |
|
79 | if (!connectionDirective) {
|
80 | options.path.pop();
|
81 | return transformedField;
|
82 | }
|
83 |
|
84 | var definitionName = options.definitionName;
|
85 | validateConnectionSelection(definitionName, transformedField);
|
86 | validateConnectionType(definitionName, transformedField);
|
87 | var pathHasPlural = options.path.includes(null);
|
88 | var firstArg = findArg(transformedField, require("./RelayConnectionConstants").FIRST);
|
89 | var lastArg = findArg(transformedField, require("./RelayConnectionConstants").LAST);
|
90 | var direction = null;
|
91 | var countArg = null;
|
92 | var cursorArg = null;
|
93 |
|
94 | if (firstArg && !lastArg) {
|
95 | direction = 'forward';
|
96 | countArg = firstArg;
|
97 | cursorArg = findArg(transformedField, require("./RelayConnectionConstants").AFTER);
|
98 | } else if (lastArg && !firstArg) {
|
99 | direction = 'backward';
|
100 | countArg = lastArg;
|
101 | cursorArg = findArg(transformedField, require("./RelayConnectionConstants").BEFORE);
|
102 | } else if (lastArg && firstArg) {
|
103 | direction = 'bidirectional';
|
104 | }
|
105 |
|
106 | var countVariable = countArg && countArg.value.kind === 'Variable' ? countArg.value.variableName : null;
|
107 | var cursorVariable = cursorArg && cursorArg.value.kind === 'Variable' ? cursorArg.value.variableName : null;
|
108 | options.connectionMetadata.push({
|
109 | count: countVariable,
|
110 | cursor: cursorVariable,
|
111 | direction: direction,
|
112 | path: pathHasPlural ? null : (0, _toConsumableArray2["default"])(options.path)
|
113 | });
|
114 | options.path.pop();
|
115 |
|
116 | var _getLiteralArgumentVa = require("./getLiteralArgumentValues")(connectionDirective.args),
|
117 | handler = _getLiteralArgumentVa.handler,
|
118 | key = _getLiteralArgumentVa.key,
|
119 | filters = _getLiteralArgumentVa.filters;
|
120 |
|
121 | if (handler != null && typeof handler !== 'string') {
|
122 | var _ref, _handleArg$value;
|
123 |
|
124 | var handleArg = connectionDirective.args.find(function (arg) {
|
125 | return arg.name === 'key';
|
126 | });
|
127 | throw require("./RelayCompilerError").createUserError("Expected the ".concat(HANDLER, " argument to ") + "@".concat(CONNECTION, " to be a string literal for field ").concat(field.name, "."), [(_ref = handleArg === null || handleArg === void 0 ? void 0 : (_handleArg$value = handleArg.value) === null || _handleArg$value === void 0 ? void 0 : _handleArg$value.loc) !== null && _ref !== void 0 ? _ref : connectionDirective.loc]);
|
128 | }
|
129 |
|
130 | if (typeof key !== 'string') {
|
131 | var _ref2, _keyArg$value;
|
132 |
|
133 | var keyArg = connectionDirective.args.find(function (arg) {
|
134 | return arg.name === 'key';
|
135 | });
|
136 | throw require("./RelayCompilerError").createUserError("Expected the ".concat(require("./RelayConnectionConstants").KEY, " argument to ") + "@".concat(CONNECTION, " to be a string literal for field ").concat(field.name, "."), [(_ref2 = keyArg === null || keyArg === void 0 ? void 0 : (_keyArg$value = keyArg.value) === null || _keyArg$value === void 0 ? void 0 : _keyArg$value.loc) !== null && _ref2 !== void 0 ? _ref2 : connectionDirective.loc]);
|
137 | }
|
138 |
|
139 | var postfix = field.alias || field.name;
|
140 |
|
141 | if (!key.endsWith('_' + postfix)) {
|
142 | var _ref3, _keyArg$value2;
|
143 |
|
144 | var _keyArg = connectionDirective.args.find(function (arg) {
|
145 | return arg.name === 'key';
|
146 | });
|
147 |
|
148 | throw require("./RelayCompilerError").createUserError("Expected the ".concat(require("./RelayConnectionConstants").KEY, " argument to ") + "@".concat(CONNECTION, " to be of form <SomeName>_").concat(postfix, ", got '").concat(key, "'. ") + 'For detailed explanation, check out ' + 'https://facebook.github.io/relay/docs/en/pagination-container.html#connection', [(_ref3 = _keyArg === null || _keyArg === void 0 ? void 0 : (_keyArg$value2 = _keyArg.value) === null || _keyArg$value2 === void 0 ? void 0 : _keyArg$value2.loc) !== null && _ref3 !== void 0 ? _ref3 : connectionDirective.loc]);
|
149 | }
|
150 |
|
151 | var generateFilters = function generateFilters() {
|
152 | var filteredVariableArgs = field.args.filter(function (arg) {
|
153 | return !require("relay-runtime").ConnectionInterface.isConnectionCall({
|
154 | name: arg.name,
|
155 | value: null
|
156 | });
|
157 | }).map(function (arg) {
|
158 | return arg.name;
|
159 | });
|
160 | return filteredVariableArgs.length === 0 ? null : filteredVariableArgs;
|
161 | };
|
162 |
|
163 | var handle = {
|
164 | name: (_handler = handler) !== null && _handler !== void 0 ? _handler : CONNECTION,
|
165 | key: key,
|
166 | filters: filters || generateFilters()
|
167 | };
|
168 |
|
169 | if (direction !== null) {
|
170 | var fragment = generateConnectionFragment(this.getContext(), transformedField.loc, transformedField.type, direction);
|
171 | transformedField = (0, _objectSpread2["default"])({}, transformedField, {
|
172 | selections: transformedField.selections.concat(fragment)
|
173 | });
|
174 | }
|
175 |
|
176 | return (0, _objectSpread2["default"])({}, transformedField, {
|
177 | directives: transformedField.directives.filter(function (directive) {
|
178 | return directive.name !== CONNECTION;
|
179 | }),
|
180 | handles: transformedField.handles ? (0, _toConsumableArray2["default"])(transformedField.handles).concat([handle]) : [handle]
|
181 | });
|
182 | }
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 | function generateConnectionFragment(context, loc, type, direction) {
|
192 | var _ConnectionInterface$ = require("relay-runtime").ConnectionInterface.get(),
|
193 | CURSOR = _ConnectionInterface$.CURSOR,
|
194 | EDGES = _ConnectionInterface$.EDGES,
|
195 | END_CURSOR = _ConnectionInterface$.END_CURSOR,
|
196 | HAS_NEXT_PAGE = _ConnectionInterface$.HAS_NEXT_PAGE,
|
197 | HAS_PREV_PAGE = _ConnectionInterface$.HAS_PREV_PAGE,
|
198 | NODE = _ConnectionInterface$.NODE,
|
199 | PAGE_INFO = _ConnectionInterface$.PAGE_INFO,
|
200 | START_CURSOR = _ConnectionInterface$.START_CURSOR;
|
201 |
|
202 | var compositeType = require("graphql").assertCompositeType(require("./GraphQLSchemaUtils").getNullableType(type));
|
203 |
|
204 | var pageInfo = PAGE_INFO;
|
205 |
|
206 | if (direction === 'forward') {
|
207 | pageInfo += "{\n ".concat(END_CURSOR, "\n ").concat(HAS_NEXT_PAGE, "\n }");
|
208 | } else if (direction === 'backward') {
|
209 | pageInfo += "{\n ".concat(HAS_PREV_PAGE, "\n ").concat(START_CURSOR, "\n }");
|
210 | } else {
|
211 | pageInfo += "{\n ".concat(END_CURSOR, "\n ").concat(HAS_NEXT_PAGE, "\n ").concat(HAS_PREV_PAGE, "\n ").concat(START_CURSOR, "\n }");
|
212 | }
|
213 |
|
214 | var fragmentString = "fragment ConnectionFragment on ".concat(String(compositeType), " {\n ").concat(EDGES, " {\n ").concat(CURSOR, "\n ").concat(NODE, " {\n __typename # rely on GenerateRequisiteFieldTransform to add \"id\"\n }\n }\n ").concat(pageInfo, "\n }");
|
215 |
|
216 | var ast = require("graphql").parse(fragmentString);
|
217 |
|
218 | var fragmentAST = ast.definitions[0];
|
219 |
|
220 | if (fragmentAST == null || fragmentAST.kind !== 'FragmentDefinition') {
|
221 | throw require("./RelayCompilerError").createCompilerError('RelayConnectionTransform: Expected a fragment definition AST.', null, [fragmentAST].filter(Boolean));
|
222 | }
|
223 |
|
224 | var fragment = require("./RelayParser").transform(context.clientSchema, [fragmentAST])[0];
|
225 |
|
226 | if (fragment == null || fragment.kind !== 'Fragment') {
|
227 | throw require("./RelayCompilerError").createCompilerError('RelayConnectionTransform: Expected a connection fragment.', [fragment === null || fragment === void 0 ? void 0 : fragment.loc].filter(Boolean));
|
228 | }
|
229 |
|
230 | return {
|
231 | directives: [],
|
232 | kind: 'InlineFragment',
|
233 | loc: {
|
234 | kind: 'Derived',
|
235 | source: loc
|
236 | },
|
237 | metadata: null,
|
238 | selections: fragment.selections,
|
239 | typeCondition: compositeType
|
240 | };
|
241 | }
|
242 |
|
243 | function findArg(field, argName) {
|
244 | return field.args && field.args.find(function (arg) {
|
245 | return arg.name === argName;
|
246 | });
|
247 | }
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 | function validateConnectionSelection(definitionName, field) {
|
264 | var _ConnectionInterface$2 = require("relay-runtime").ConnectionInterface.get(),
|
265 | EDGES = _ConnectionInterface$2.EDGES;
|
266 |
|
267 | if (!findArg(field, require("./RelayConnectionConstants").FIRST) && !findArg(field, require("./RelayConnectionConstants").LAST)) {
|
268 | throw require("./RelayCompilerError").createUserError("Expected field `".concat(field.name, ": ") + "".concat(String(field.type), "` to have a ").concat(require("./RelayConnectionConstants").FIRST, " or ").concat(require("./RelayConnectionConstants").LAST, " argument in ") + "document `".concat(definitionName, "`."), [field.loc]);
|
269 | }
|
270 |
|
271 | if (!field.selections.some(function (selection) {
|
272 | return selection.kind === 'LinkedField' && selection.name === EDGES;
|
273 | })) {
|
274 | throw require("./RelayCompilerError").createUserError("Expected field `".concat(field.name, ": ") + "".concat(String(field.type), "` to have a ").concat(EDGES, " selection in document ") + "`".concat(definitionName, "`."), [field.loc]);
|
275 | }
|
276 | }
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 | function validateConnectionType(definitionName, field) {
|
289 | var type = field.type;
|
290 |
|
291 | var _ConnectionInterface$3 = require("relay-runtime").ConnectionInterface.get(),
|
292 | CURSOR = _ConnectionInterface$3.CURSOR,
|
293 | EDGES = _ConnectionInterface$3.EDGES,
|
294 | END_CURSOR = _ConnectionInterface$3.END_CURSOR,
|
295 | HAS_NEXT_PAGE = _ConnectionInterface$3.HAS_NEXT_PAGE,
|
296 | HAS_PREV_PAGE = _ConnectionInterface$3.HAS_PREV_PAGE,
|
297 | NODE = _ConnectionInterface$3.NODE,
|
298 | PAGE_INFO = _ConnectionInterface$3.PAGE_INFO,
|
299 | START_CURSOR = _ConnectionInterface$3.START_CURSOR;
|
300 |
|
301 | var typeWithFields = require("./GraphQLSchemaUtils").assertTypeWithFields(require("./GraphQLSchemaUtils").getNullableType(type));
|
302 |
|
303 | var typeFields = typeWithFields.getFields();
|
304 | var edges = typeFields[EDGES];
|
305 |
|
306 | if (edges == null) {
|
307 | throw require("./RelayCompilerError").createUserError("Expected type '".concat(String(type), "' to have an '").concat(EDGES, "' field in document '").concat(definitionName, "'."), [field.loc]);
|
308 | }
|
309 |
|
310 | var edgesType = require("./GraphQLSchemaUtils").getNullableType(edges.type);
|
311 |
|
312 | if (!(edgesType instanceof require("graphql").GraphQLList)) {
|
313 | throw require("./RelayCompilerError").createUserError("Expected '".concat(EDGES, "' field on type '").concat(String(type), "' to be a list type in document '").concat(definitionName, "'."), [field.loc]);
|
314 | }
|
315 |
|
316 | var edgeType = require("./GraphQLSchemaUtils").getNullableType(edgesType.ofType);
|
317 |
|
318 | if (!(edgeType instanceof require("graphql").GraphQLObjectType)) {
|
319 | throw require("./RelayCompilerError").createUserError("Expected '".concat(EDGES, "' field on type '").concat(String(type), "' to be a list of objects in document '").concat(definitionName, "'."), [field.loc]);
|
320 | }
|
321 |
|
322 | var node = edgeType.getFields()[NODE];
|
323 |
|
324 | if (node == null) {
|
325 | throw require("./RelayCompilerError").createUserError("Expected type '".concat(String(type), "' to have have a '").concat(EDGES, " { ").concat(NODE, " }' field in in document '").concat(definitionName, "'."), [field.loc]);
|
326 | }
|
327 |
|
328 | var nodeType = require("./GraphQLSchemaUtils").getNullableType(node.type);
|
329 |
|
330 | if (!(nodeType instanceof require("graphql").GraphQLInterfaceType || nodeType instanceof require("graphql").GraphQLUnionType || nodeType instanceof require("graphql").GraphQLObjectType)) {
|
331 | throw require("./RelayCompilerError").createUserError("Expected type '".concat(String(type), "' to have a '").concat(EDGES, " { ").concat(NODE, " }' field for which the type is an interface, object, or union in document '").concat(definitionName, "'."), [field.loc]);
|
332 | }
|
333 |
|
334 | var cursor = edgeType.getFields()[CURSOR];
|
335 |
|
336 | if (cursor == null || !(require("./GraphQLSchemaUtils").getNullableType(cursor.type) instanceof require("graphql").GraphQLScalarType)) {
|
337 | throw require("./RelayCompilerError").createUserError("Expected type '".concat(String(type), "' to have a '").concat(EDGES, " { ").concat(CURSOR, " }' scalar field in document '").concat(definitionName, "'."), [field.loc]);
|
338 | }
|
339 |
|
340 | var pageInfo = typeFields[PAGE_INFO];
|
341 |
|
342 | if (pageInfo == null) {
|
343 | throw require("./RelayCompilerError").createUserError("Expected type '".concat(String(type), "' to have a '").concat(EDGES, " { ").concat(PAGE_INFO, " }' field in document '").concat(definitionName, "'."), [field.loc]);
|
344 | }
|
345 |
|
346 | var pageInfoType = require("./GraphQLSchemaUtils").getNullableType(pageInfo.type);
|
347 |
|
348 | if (!(pageInfoType instanceof require("graphql").GraphQLObjectType)) {
|
349 | throw require("./RelayCompilerError").createUserError("Expected type '".concat(String(type), "' to have a '").concat(EDGES, " { ").concat(PAGE_INFO, " }' field with object type in document '").concat(definitionName, "'."), [field.loc]);
|
350 | }
|
351 |
|
352 | [END_CURSOR, HAS_NEXT_PAGE, HAS_PREV_PAGE, START_CURSOR].forEach(function (fieldName) {
|
353 | var pageInfoField = pageInfoType.getFields()[fieldName];
|
354 |
|
355 | if (pageInfoField == null || !(require("./GraphQLSchemaUtils").getNullableType(pageInfoField.type) instanceof require("graphql").GraphQLScalarType)) {
|
356 | throw require("./RelayCompilerError").createUserError("Expected type '".concat(String(pageInfo.type), "' to have a '").concat(fieldName, "' scalar field in document '").concat(definitionName, "'."), [field.loc]);
|
357 | }
|
358 | });
|
359 | }
|
360 |
|
361 | module.exports = {
|
362 | CONNECTION: CONNECTION,
|
363 | SCHEMA_EXTENSION: SCHEMA_EXTENSION,
|
364 | transform: relayConnectionTransform
|
365 | }; |
\ | No newline at end of file |