UNPKG

10.5 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 *
8 * @format
9 */
10'use strict';
11
12var _objectSpread2 = require("@babel/runtime/helpers/interopRequireDefault")(require("@babel/runtime/helpers/objectSpread"));
13
14/**
15 * @public
16 *
17 * Converts a GraphQLIR node into a plain JS object representation that can be
18 * used at runtime.
19 */
20function generate(node) {
21 return require("./GraphQLIRVisitor").visit(node, ReaderCodeGenVisitor);
22}
23
24var ReaderCodeGenVisitor = {
25 leave: {
26 Request: function Request(node) {
27 throw require("./RelayCompilerError").createCompilerError('ReaderCodeGenerator: unexpeted Request node.');
28 },
29 Fragment: function Fragment(node) {
30 var metadata = null;
31
32 if (node.metadata != null) {
33 var _node$metadata = node.metadata,
34 mask = _node$metadata.mask,
35 plural = _node$metadata.plural,
36 connection = _node$metadata.connection,
37 refetch = _node$metadata.refetch;
38
39 if (Array.isArray(connection)) {
40 var _metadata;
41
42 metadata = (_metadata = metadata) !== null && _metadata !== void 0 ? _metadata : {};
43 metadata.connection = connection;
44 }
45
46 if (typeof mask === 'boolean') {
47 var _metadata2;
48
49 metadata = (_metadata2 = metadata) !== null && _metadata2 !== void 0 ? _metadata2 : {};
50 metadata.mask = mask;
51 }
52
53 if (typeof plural === 'boolean') {
54 var _metadata3;
55
56 metadata = (_metadata3 = metadata) !== null && _metadata3 !== void 0 ? _metadata3 : {};
57 metadata.plural = plural;
58 }
59
60 if (typeof refetch === 'object') {
61 var _metadata4;
62
63 metadata = (_metadata4 = metadata) !== null && _metadata4 !== void 0 ? _metadata4 : {};
64 metadata.refetch = {
65 connection: refetch.connection,
66 operation: require("./CodeMarker").moduleDependency(refetch.operation + '.graphql'),
67 fragmentPathInResult: refetch.fragmentPathInResult
68 };
69 }
70 }
71
72 return {
73 kind: 'Fragment',
74 name: node.name,
75 type: node.type.toString(),
76 metadata: metadata,
77 argumentDefinitions: node.argumentDefinitions,
78 selections: node.selections
79 };
80 },
81 LocalArgumentDefinition: function LocalArgumentDefinition(node) {
82 return {
83 kind: 'LocalArgument',
84 name: node.name,
85 type: node.type.toString(),
86 defaultValue: node.defaultValue
87 };
88 },
89 RootArgumentDefinition: function RootArgumentDefinition(node) {
90 return {
91 kind: 'RootArgument',
92 name: node.name,
93 type: node.type ? node.type.toString() : null
94 };
95 },
96 Condition: function Condition(node, key, parent, ancestors) {
97 if (node.condition.kind !== 'Variable') {
98 throw require("./RelayCompilerError").createCompilerError("ReaderCodeGenerator: Expected 'Condition' with static value to be " + 'pruned or inlined', [node.condition.loc]);
99 }
100
101 return {
102 kind: 'Condition',
103 passingValue: node.passingValue,
104 condition: node.condition.variableName,
105 selections: node.selections
106 };
107 },
108 FragmentSpread: function FragmentSpread(node) {
109 return {
110 kind: 'FragmentSpread',
111 name: node.name,
112 args: valuesOrNull(sortByName(node.args))
113 };
114 },
115 InlineFragment: function InlineFragment(node) {
116 return {
117 kind: 'InlineFragment',
118 type: node.typeCondition.toString(),
119 selections: node.selections
120 };
121 },
122 LinkedField: function LinkedField(node) {
123 // Note: it is important that the arguments of this field be sorted to
124 // ensure stable generation of storage keys for equivalent arguments
125 // which may have originally appeared in different orders across an app.
126 // TODO(T37646905) enable this invariant after splitting the
127 // RelayCodeGenerator-test and running the RelayFieldHandleTransform on
128 // Reader ASTs.
129 //
130 // invariant(
131 // node.handles == null,
132 // 'ReaderCodeGenerator: unexpected handles',
133 // );
134 var type = require("./GraphQLSchemaUtils").getRawType(node.type);
135
136 var field = {
137 kind: 'LinkedField',
138 alias: node.alias,
139 name: node.name,
140 storageKey: null,
141 args: valuesOrNull(sortByName(node.args)),
142 concreteType: !require("./GraphQLSchemaUtils").isAbstractType(type) ? type.toString() : null,
143 plural: isPlural(node.type),
144 selections: node.selections
145 }; // Precompute storageKey if possible
146
147 var storageKey = getStaticStorageKey(field, node.metadata);
148
149 if (storageKey) {
150 field = (0, _objectSpread2["default"])({}, field, {
151 storageKey: storageKey
152 });
153 }
154
155 return field;
156 },
157 MatchField: function MatchField(node, key, parent, ancestors) {
158 var matchesByType = {};
159 node.selections.forEach(function (selection) {
160 var _regExpMatch$;
161
162 if (selection.kind === 'ScalarField' && selection.name === '__typename') {
163 // The RelayGenerateTypename transform will add a __typename selection
164 // to the selections of the match field.
165 return;
166 }
167
168 if (selection.kind !== 'MatchBranch') {
169 throw require("./RelayCompilerError").createCompilerError("ReaderCodeGenerator: Expected selection for MatchField '".concat(node.name, "' to be a 'MatchBranch', got '").concat(selection.kind, "'."), [selection.loc]);
170 }
171
172 if (matchesByType.hasOwnProperty(selection.type)) {
173 throw require("./RelayCompilerError").createCompilerError('ReaderCodeGenerator: Each @match type can appear at-most once. ' + "Type '".concat(String(selection.type), "' was duplicated."), selection.type, [selection.loc]);
174 }
175
176 var fragmentName = selection.name;
177 var regExpMatch = fragmentName.match(/^([a-zA-Z][a-zA-Z0-9]*)(?:_([a-zA-Z][_a-zA-Z0-9]*))?$/);
178
179 if (!regExpMatch) {
180 throw require("./RelayCompilerError").createCompilerError('ReaderCodeGenerator: @match fragments should be named ' + "'FragmentName_propName', got '".concat(fragmentName, "'."), [selection.loc]);
181 }
182
183 var fragmentPropName = (_regExpMatch$ = regExpMatch[2]) !== null && _regExpMatch$ !== void 0 ? _regExpMatch$ : 'matchData';
184 matchesByType[selection.type] = {
185 fragmentPropName: fragmentPropName,
186 fragmentName: fragmentName
187 };
188 });
189 var field = {
190 kind: 'MatchField',
191 alias: node.alias,
192 name: node.name,
193 storageKey: null,
194 args: valuesOrNull(sortByName(node.args)),
195 matchesByType: matchesByType
196 }; // Precompute storageKey if possible
197
198 var storageKey = getStaticStorageKey(field, node.metadata);
199
200 if (storageKey) {
201 field = (0, _objectSpread2["default"])({}, field, {
202 storageKey: storageKey
203 });
204 }
205
206 return field;
207 },
208 ScalarField: function ScalarField(node) {
209 // Note: it is important that the arguments of this field be sorted to
210 // ensure stable generation of storage keys for equivalent arguments
211 // which may have originally appeared in different orders across an app.
212 // TODO(T37646905) enable this invariant after splitting the
213 // RelayCodeGenerator-test and running the RelayFieldHandleTransform on
214 // Reader ASTs.
215 //
216 // invariant(
217 // node.handles == null,
218 // 'ReaderCodeGenerator: unexpected handles',
219 var field = {
220 kind: 'ScalarField',
221 alias: node.alias,
222 name: node.name,
223 args: valuesOrNull(sortByName(node.args)),
224 storageKey: null
225 }; // Precompute storageKey if possible
226
227 var storageKey = getStaticStorageKey(field, node.metadata);
228
229 if (storageKey) {
230 field = (0, _objectSpread2["default"])({}, field, {
231 storageKey: storageKey
232 });
233 }
234
235 return field;
236 },
237 SplitOperation: function SplitOperation(node, key, parent) {
238 return {
239 kind: 'SplitOperation',
240 name: node.name,
241 metadata: null,
242 selections: node.selections
243 };
244 },
245 Variable: function Variable(node, key, parent) {
246 return {
247 kind: 'Variable',
248 name: parent.name,
249 variableName: node.variableName,
250 type: parent.type ? parent.type.toString() : null
251 };
252 },
253 Literal: function Literal(node, key, parent) {
254 return {
255 kind: 'Literal',
256 name: parent.name,
257 value: require("relay-runtime").stableCopy(node.value),
258 type: parent.type ? parent.type.toString() : null
259 };
260 },
261 Argument: function Argument(node, key, parent, ancestors) {
262 if (!['Variable', 'Literal'].includes(node.value.kind)) {
263 var valueString = JSON.stringify(node.value, null, 2);
264 throw require("./RelayCompilerError").createUserError('ReaderCodeGenerator: Complex argument values (Lists or ' + 'InputObjects with nested variables) are not supported.', [node.value.loc]);
265 }
266
267 return node.value.value !== null ? node.value : null;
268 }
269 }
270};
271
272function isPlural(type) {
273 return require("./GraphQLSchemaUtils").getNullableType(type) instanceof require("graphql").GraphQLList;
274}
275
276function valuesOrNull(array) {
277 return !array || array.length === 0 ? null : array;
278}
279
280function sortByName(array) {
281 return array instanceof Array ? array.slice().sort(function (a, b) {
282 return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
283 }) : array;
284}
285/**
286 * Pre-computes storage key if possible and advantageous. Storage keys are
287 * generated for fields with supplied arguments that are all statically known
288 * (ie. literals, no variables) at build time.
289 */
290
291
292function getStaticStorageKey(field, metadata) {
293 var metadataStorageKey = metadata === null || metadata === void 0 ? void 0 : metadata.storageKey;
294
295 if (typeof metadataStorageKey === 'string') {
296 return metadataStorageKey;
297 }
298
299 if (!field.args || field.args.length === 0 || field.args.some(function (arg) {
300 return arg.kind !== 'Literal';
301 })) {
302 return null;
303 }
304
305 return require("relay-runtime").getStorageKey(field, {});
306}
307
308module.exports = {
309 generate: generate
310};
\No newline at end of file