UNPKG

4.35 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 * strict-local
8 * @format
9 */
10'use strict';
11
12/**
13 * A transform that removes any selections that are not valid relative to the
14 * server schema. The primary use case is for fields added via client
15 * `extend type ...` definitions and for inline fragments / fragment spreads
16 * whose types are added with client `type ...` type extensions.
17 *
18 * Given a base schema:
19 *
20 * ```
21 * # Note: full schema definition elided for clarity
22 * interface Viewer {
23 * name: String
24 * }
25 * type User implements Viewer {
26 * name: String
27 * }
28 * ```
29 *
30 * And a fragment:
31 *
32 * ```
33 * fragment on Viewer {
34 * name
35 * ... on User {
36 * clientField # (1)
37 * }
38 * ... on ClientType { # (2)
39 * clientField
40 * }
41 * }
42 * extend type User {
43 * clientField: String
44 * }
45 * type ClientType implements Viewer {
46 * name: String
47 * clientField: String
48 * }
49 * ```
50 *
51 * This transform will output:
52 *
53 * ```
54 * fragment on Viewer {
55 * name
56 * }
57 * ```
58 *
59 * Note that (1) is removed because this field does not exist on the base `User`
60 * type, and (2) is removed because the `ClientType` type does not exist in the
61 * base schema.
62 */
63function skipClientFieldTransform(context) {
64 return require("./GraphQLIRTransformer").transform(context, {
65 FragmentSpread: visitFragmentSpread,
66 InlineFragment: visitInlineFragment,
67 LinkedField: visitField,
68 MatchField: visitField,
69 ScalarField: visitField
70 }, function (node) {
71 return buildState(context, node);
72 });
73}
74/**
75 * @internal
76 *
77 * Build the initial state, returning null for fragments whose type is not
78 * defined in the server schema.
79 */
80
81
82function buildState(context, node) {
83 var schema = context.serverSchema;
84
85 switch (node.kind) {
86 case 'Fragment':
87 return schema.getType(node.type.name);
88
89 case 'Root':
90 switch (node.operation) {
91 case 'query':
92 return schema.getQueryType();
93
94 case 'mutation':
95 return schema.getMutationType();
96
97 case 'subscription':
98 return schema.getSubscriptionType();
99
100 default:
101 node.operation;
102 }
103
104 break;
105
106 case 'SplitOperation':
107 return schema.getType(node.type.name);
108
109 default:
110 node;
111 }
112
113 return null;
114}
115/**
116 * @internal
117 *
118 * Skip fields that were added via `extend type ...`.
119 */
120
121
122function visitField(field, parentType) {
123 if ( // Field is defined in the original parent type definition:
124 require("./GraphQLSchemaUtils").canHaveSelections(parentType) && require("./GraphQLSchemaUtils").assertTypeWithFields(parentType).getFields()[field.name] || // Allow metadata fields and fields defined on classic "fat" interfaces
125 field.name === require("graphql").SchemaMetaFieldDef.name || field.name === require("graphql").TypeMetaFieldDef.name || field.name === require("graphql").TypeNameMetaFieldDef.name || field.directives.some(function (_ref) {
126 var name = _ref.name;
127 return name === 'fixme_fat_interface';
128 })) {
129 var rawType = require("./GraphQLSchemaUtils").getRawType(field.type);
130
131 var type = this.getContext().serverSchema.getType(rawType.name);
132 !type ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'SkipClientFieldTransform: Expected type `%s` to be defined in ' + 'the server schema.', rawType.name) : require("fbjs/lib/invariant")(false) : void 0;
133 return this.traverse(field, type);
134 }
135
136 return null;
137}
138/**
139 * @internal
140 *
141 * Skip fragment spreads where the referenced fragment is not defined in the
142 * original schema.
143 */
144
145
146function visitFragmentSpread(spread, parentType) {
147 var context = this.getContext();
148 var fragment = context.getFragment(spread.name);
149
150 if (context.serverSchema.getType(fragment.type.name)) {
151 return this.traverse(spread, parentType);
152 }
153
154 return null;
155}
156/**
157 * @internal
158 *
159 * Skip inline fragments where the type is not in the schema.
160 */
161
162
163function visitInlineFragment(fragment, parentType) {
164 var schema = this.getContext().serverSchema;
165 var type = schema.getType(fragment.typeCondition.name);
166
167 if (type) {
168 return this.traverse(fragment, type);
169 }
170
171 return null;
172}
173
174module.exports = {
175 transform: skipClientFieldTransform
176};
\No newline at end of file