UNPKG

7.89 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true,
5});
6exports.printIntrospectionSchema = printIntrospectionSchema;
7exports.printSchema = printSchema;
8exports.printType = printType;
9
10var _inspect = require('../jsutils/inspect.js');
11
12var _invariant = require('../jsutils/invariant.js');
13
14var _blockString = require('../language/blockString.js');
15
16var _kinds = require('../language/kinds.js');
17
18var _printer = require('../language/printer.js');
19
20var _definition = require('../type/definition.js');
21
22var _directives = require('../type/directives.js');
23
24var _introspection = require('../type/introspection.js');
25
26var _scalars = require('../type/scalars.js');
27
28var _astFromValue = require('./astFromValue.js');
29
30function printSchema(schema) {
31 return printFilteredSchema(
32 schema,
33 (n) => !(0, _directives.isSpecifiedDirective)(n),
34 isDefinedType,
35 );
36}
37
38function printIntrospectionSchema(schema) {
39 return printFilteredSchema(
40 schema,
41 _directives.isSpecifiedDirective,
42 _introspection.isIntrospectionType,
43 );
44}
45
46function isDefinedType(type) {
47 return (
48 !(0, _scalars.isSpecifiedScalarType)(type) &&
49 !(0, _introspection.isIntrospectionType)(type)
50 );
51}
52
53function printFilteredSchema(schema, directiveFilter, typeFilter) {
54 const directives = schema.getDirectives().filter(directiveFilter);
55 const types = Object.values(schema.getTypeMap()).filter(typeFilter);
56 return [
57 printSchemaDefinition(schema),
58 ...directives.map((directive) => printDirective(directive)),
59 ...types.map((type) => printType(type)),
60 ]
61 .filter(Boolean)
62 .join('\n\n');
63}
64
65function printSchemaDefinition(schema) {
66 if (schema.description == null && isSchemaOfCommonNames(schema)) {
67 return;
68 }
69
70 const operationTypes = [];
71 const queryType = schema.getQueryType();
72
73 if (queryType) {
74 operationTypes.push(` query: ${queryType.name}`);
75 }
76
77 const mutationType = schema.getMutationType();
78
79 if (mutationType) {
80 operationTypes.push(` mutation: ${mutationType.name}`);
81 }
82
83 const subscriptionType = schema.getSubscriptionType();
84
85 if (subscriptionType) {
86 operationTypes.push(` subscription: ${subscriptionType.name}`);
87 }
88
89 return printDescription(schema) + `schema {\n${operationTypes.join('\n')}\n}`;
90}
91/**
92 * GraphQL schema define root types for each type of operation. These types are
93 * the same as any other type and can be named in any manner, however there is
94 * a common naming convention:
95 *
96 * ```graphql
97 * schema {
98 * query: Query
99 * mutation: Mutation
100 * subscription: Subscription
101 * }
102 * ```
103 *
104 * When using this naming convention, the schema description can be omitted.
105 */
106
107function isSchemaOfCommonNames(schema) {
108 const queryType = schema.getQueryType();
109
110 if (queryType && queryType.name !== 'Query') {
111 return false;
112 }
113
114 const mutationType = schema.getMutationType();
115
116 if (mutationType && mutationType.name !== 'Mutation') {
117 return false;
118 }
119
120 const subscriptionType = schema.getSubscriptionType();
121
122 if (subscriptionType && subscriptionType.name !== 'Subscription') {
123 return false;
124 }
125
126 return true;
127}
128
129function printType(type) {
130 if ((0, _definition.isScalarType)(type)) {
131 return printScalar(type);
132 }
133
134 if ((0, _definition.isObjectType)(type)) {
135 return printObject(type);
136 }
137
138 if ((0, _definition.isInterfaceType)(type)) {
139 return printInterface(type);
140 }
141
142 if ((0, _definition.isUnionType)(type)) {
143 return printUnion(type);
144 }
145
146 if ((0, _definition.isEnumType)(type)) {
147 return printEnum(type);
148 }
149
150 if ((0, _definition.isInputObjectType)(type)) {
151 return printInputObject(type);
152 }
153 /* c8 ignore next 3 */
154 // Not reachable, all possible types have been considered.
155
156 false ||
157 (0, _invariant.invariant)(
158 false,
159 'Unexpected type: ' + (0, _inspect.inspect)(type),
160 );
161}
162
163function printScalar(type) {
164 return (
165 printDescription(type) + `scalar ${type.name}` + printSpecifiedByURL(type)
166 );
167}
168
169function printImplementedInterfaces(type) {
170 const interfaces = type.getInterfaces();
171 return interfaces.length
172 ? ' implements ' + interfaces.map((i) => i.name).join(' & ')
173 : '';
174}
175
176function printObject(type) {
177 return (
178 printDescription(type) +
179 `type ${type.name}` +
180 printImplementedInterfaces(type) +
181 printFields(type)
182 );
183}
184
185function printInterface(type) {
186 return (
187 printDescription(type) +
188 `interface ${type.name}` +
189 printImplementedInterfaces(type) +
190 printFields(type)
191 );
192}
193
194function printUnion(type) {
195 const types = type.getTypes();
196 const possibleTypes = types.length ? ' = ' + types.join(' | ') : '';
197 return printDescription(type) + 'union ' + type.name + possibleTypes;
198}
199
200function printEnum(type) {
201 const values = type
202 .getValues()
203 .map(
204 (value, i) =>
205 printDescription(value, ' ', !i) +
206 ' ' +
207 value.name +
208 printDeprecated(value.deprecationReason),
209 );
210 return printDescription(type) + `enum ${type.name}` + printBlock(values);
211}
212
213function printInputObject(type) {
214 const fields = Object.values(type.getFields()).map(
215 (f, i) => printDescription(f, ' ', !i) + ' ' + printInputValue(f),
216 );
217 return printDescription(type) + `input ${type.name}` + printBlock(fields);
218}
219
220function printFields(type) {
221 const fields = Object.values(type.getFields()).map(
222 (f, i) =>
223 printDescription(f, ' ', !i) +
224 ' ' +
225 f.name +
226 printArgs(f.args, ' ') +
227 ': ' +
228 String(f.type) +
229 printDeprecated(f.deprecationReason),
230 );
231 return printBlock(fields);
232}
233
234function printBlock(items) {
235 return items.length !== 0 ? ' {\n' + items.join('\n') + '\n}' : '';
236}
237
238function printArgs(args, indentation = '') {
239 if (args.length === 0) {
240 return '';
241 } // If every arg does not have a description, print them on one line.
242
243 if (args.every((arg) => !arg.description)) {
244 return '(' + args.map(printInputValue).join(', ') + ')';
245 }
246
247 return (
248 '(\n' +
249 args
250 .map(
251 (arg, i) =>
252 printDescription(arg, ' ' + indentation, !i) +
253 ' ' +
254 indentation +
255 printInputValue(arg),
256 )
257 .join('\n') +
258 '\n' +
259 indentation +
260 ')'
261 );
262}
263
264function printInputValue(arg) {
265 const defaultAST = (0, _astFromValue.astFromValue)(
266 arg.defaultValue,
267 arg.type,
268 );
269 let argDecl = arg.name + ': ' + String(arg.type);
270
271 if (defaultAST) {
272 argDecl += ` = ${(0, _printer.print)(defaultAST)}`;
273 }
274
275 return argDecl + printDeprecated(arg.deprecationReason);
276}
277
278function printDirective(directive) {
279 return (
280 printDescription(directive) +
281 'directive @' +
282 directive.name +
283 printArgs(directive.args) +
284 (directive.isRepeatable ? ' repeatable' : '') +
285 ' on ' +
286 directive.locations.join(' | ')
287 );
288}
289
290function printDeprecated(reason) {
291 if (reason == null) {
292 return '';
293 }
294
295 if (reason !== _directives.DEFAULT_DEPRECATION_REASON) {
296 const astValue = (0, _printer.print)({
297 kind: _kinds.Kind.STRING,
298 value: reason,
299 });
300 return ` @deprecated(reason: ${astValue})`;
301 }
302
303 return ' @deprecated';
304}
305
306function printSpecifiedByURL(scalar) {
307 if (scalar.specifiedByURL == null) {
308 return '';
309 }
310
311 const astValue = (0, _printer.print)({
312 kind: _kinds.Kind.STRING,
313 value: scalar.specifiedByURL,
314 });
315 return ` @specifiedBy(url: ${astValue})`;
316}
317
318function printDescription(def, indentation = '', firstInBlock = true) {
319 const { description } = def;
320
321 if (description == null) {
322 return '';
323 }
324
325 const blockString = (0, _printer.print)({
326 kind: _kinds.Kind.STRING,
327 value: description,
328 block: (0, _blockString.isPrintableAsBlockString)(description),
329 });
330 const prefix =
331 indentation && !firstInBlock ? '\n' + indentation : indentation;
332 return prefix + blockString.replace(/\n/g, '\n' + indentation) + '\n';
333}