UNPKG

19.9 kBJavaScriptView Raw
1import { print, Kind, isSpecifiedScalarType, isIntrospectionType, isSpecifiedDirective, astFromValue, GraphQLDeprecatedDirective, isObjectType, isInterfaceType, isUnionType, isInputObjectType, isEnumType, isScalarType, } from 'graphql';
2import { astFromType } from './astFromType.js';
3import { getDirectivesInExtensions } from './get-directives.js';
4import { astFromValueUntyped } from './astFromValueUntyped.js';
5import { isSome } from './helpers.js';
6import { getRootTypeMap } from './rootTypes.js';
7export function getDocumentNodeFromSchema(schema, options = {}) {
8 const pathToDirectivesInExtensions = options.pathToDirectivesInExtensions;
9 const typesMap = schema.getTypeMap();
10 const schemaNode = astFromSchema(schema, pathToDirectivesInExtensions);
11 const definitions = schemaNode != null ? [schemaNode] : [];
12 const directives = schema.getDirectives();
13 for (const directive of directives) {
14 if (isSpecifiedDirective(directive)) {
15 continue;
16 }
17 definitions.push(astFromDirective(directive, schema, pathToDirectivesInExtensions));
18 }
19 for (const typeName in typesMap) {
20 const type = typesMap[typeName];
21 const isPredefinedScalar = isSpecifiedScalarType(type);
22 const isIntrospection = isIntrospectionType(type);
23 if (isPredefinedScalar || isIntrospection) {
24 continue;
25 }
26 if (isObjectType(type)) {
27 definitions.push(astFromObjectType(type, schema, pathToDirectivesInExtensions));
28 }
29 else if (isInterfaceType(type)) {
30 definitions.push(astFromInterfaceType(type, schema, pathToDirectivesInExtensions));
31 }
32 else if (isUnionType(type)) {
33 definitions.push(astFromUnionType(type, schema, pathToDirectivesInExtensions));
34 }
35 else if (isInputObjectType(type)) {
36 definitions.push(astFromInputObjectType(type, schema, pathToDirectivesInExtensions));
37 }
38 else if (isEnumType(type)) {
39 definitions.push(astFromEnumType(type, schema, pathToDirectivesInExtensions));
40 }
41 else if (isScalarType(type)) {
42 definitions.push(astFromScalarType(type, schema, pathToDirectivesInExtensions));
43 }
44 else {
45 throw new Error(`Unknown type ${type}.`);
46 }
47 }
48 return {
49 kind: Kind.DOCUMENT,
50 definitions,
51 };
52}
53// this approach uses the default schema printer rather than a custom solution, so may be more backwards compatible
54// currently does not allow customization of printSchema options having to do with comments.
55export function printSchemaWithDirectives(schema, options = {}) {
56 const documentNode = getDocumentNodeFromSchema(schema, options);
57 return print(documentNode);
58}
59export function astFromSchema(schema, pathToDirectivesInExtensions) {
60 var _a, _b;
61 const operationTypeMap = new Map([
62 ['query', undefined],
63 ['mutation', undefined],
64 ['subscription', undefined],
65 ]);
66 const nodes = [];
67 if (schema.astNode != null) {
68 nodes.push(schema.astNode);
69 }
70 if (schema.extensionASTNodes != null) {
71 for (const extensionASTNode of schema.extensionASTNodes) {
72 nodes.push(extensionASTNode);
73 }
74 }
75 for (const node of nodes) {
76 if (node.operationTypes) {
77 for (const operationTypeDefinitionNode of node.operationTypes) {
78 operationTypeMap.set(operationTypeDefinitionNode.operation, operationTypeDefinitionNode);
79 }
80 }
81 }
82 const rootTypeMap = getRootTypeMap(schema);
83 for (const [operationTypeNode, operationTypeDefinitionNode] of operationTypeMap) {
84 const rootType = rootTypeMap.get(operationTypeNode);
85 if (rootType != null) {
86 const rootTypeAST = astFromType(rootType);
87 if (operationTypeDefinitionNode != null) {
88 operationTypeDefinitionNode.type = rootTypeAST;
89 }
90 else {
91 operationTypeMap.set(operationTypeNode, {
92 kind: Kind.OPERATION_TYPE_DEFINITION,
93 operation: operationTypeNode,
94 type: rootTypeAST,
95 });
96 }
97 }
98 }
99 const operationTypes = [...operationTypeMap.values()].filter(isSome);
100 const directives = getDirectiveNodes(schema, schema, pathToDirectivesInExtensions);
101 if (!operationTypes.length && !directives.length) {
102 return null;
103 }
104 const schemaNode = {
105 kind: operationTypes != null ? Kind.SCHEMA_DEFINITION : Kind.SCHEMA_EXTENSION,
106 operationTypes,
107 // ConstXNode has been introduced in v16 but it is not compatible with XNode so we do `as any` for backwards compatibility
108 directives: directives,
109 };
110 // This code is so weird because it needs to support GraphQL.js 14
111 // In GraphQL.js 14 there is no `description` value on schemaNode
112 schemaNode.description =
113 ((_b = (_a = schema.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : schema.description != null)
114 ? {
115 kind: Kind.STRING,
116 value: schema.description,
117 block: true,
118 }
119 : undefined;
120 return schemaNode;
121}
122export function astFromDirective(directive, schema, pathToDirectivesInExtensions) {
123 var _a, _b, _c, _d;
124 return {
125 kind: Kind.DIRECTIVE_DEFINITION,
126 description: (_b = (_a = directive.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (directive.description
127 ? {
128 kind: Kind.STRING,
129 value: directive.description,
130 }
131 : undefined),
132 name: {
133 kind: Kind.NAME,
134 value: directive.name,
135 },
136 arguments: (_c = directive.args) === null || _c === void 0 ? void 0 : _c.map(arg => astFromArg(arg, schema, pathToDirectivesInExtensions)),
137 repeatable: directive.isRepeatable,
138 locations: ((_d = directive.locations) === null || _d === void 0 ? void 0 : _d.map(location => ({
139 kind: Kind.NAME,
140 value: location,
141 }))) || [],
142 };
143}
144export function getDirectiveNodes(entity, schema, pathToDirectivesInExtensions) {
145 const directivesInExtensions = getDirectivesInExtensions(entity, pathToDirectivesInExtensions);
146 let nodes = [];
147 if (entity.astNode != null) {
148 nodes.push(entity.astNode);
149 }
150 if ('extensionASTNodes' in entity && entity.extensionASTNodes != null) {
151 nodes = nodes.concat(entity.extensionASTNodes);
152 }
153 let directives;
154 if (directivesInExtensions != null) {
155 directives = makeDirectiveNodes(schema, directivesInExtensions);
156 }
157 else {
158 directives = [];
159 for (const node of nodes) {
160 if (node.directives) {
161 directives.push(...node.directives);
162 }
163 }
164 }
165 return directives;
166}
167export function getDeprecatableDirectiveNodes(entity, schema, pathToDirectivesInExtensions) {
168 var _a, _b;
169 let directiveNodesBesidesDeprecated = [];
170 let deprecatedDirectiveNode = null;
171 const directivesInExtensions = getDirectivesInExtensions(entity, pathToDirectivesInExtensions);
172 let directives;
173 if (directivesInExtensions != null) {
174 directives = makeDirectiveNodes(schema, directivesInExtensions);
175 }
176 else {
177 directives = (_a = entity.astNode) === null || _a === void 0 ? void 0 : _a.directives;
178 }
179 if (directives != null) {
180 directiveNodesBesidesDeprecated = directives.filter(directive => directive.name.value !== 'deprecated');
181 if (entity.deprecationReason != null) {
182 deprecatedDirectiveNode = (_b = directives.filter(directive => directive.name.value === 'deprecated')) === null || _b === void 0 ? void 0 : _b[0];
183 }
184 }
185 if (entity.deprecationReason != null &&
186 deprecatedDirectiveNode == null) {
187 deprecatedDirectiveNode = makeDeprecatedDirective(entity.deprecationReason);
188 }
189 return deprecatedDirectiveNode == null
190 ? directiveNodesBesidesDeprecated
191 : [deprecatedDirectiveNode].concat(directiveNodesBesidesDeprecated);
192}
193export function astFromArg(arg, schema, pathToDirectivesInExtensions) {
194 var _a, _b, _c;
195 return {
196 kind: Kind.INPUT_VALUE_DEFINITION,
197 description: (_b = (_a = arg.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (arg.description
198 ? {
199 kind: Kind.STRING,
200 value: arg.description,
201 block: true,
202 }
203 : undefined),
204 name: {
205 kind: Kind.NAME,
206 value: arg.name,
207 },
208 type: astFromType(arg.type),
209 // ConstXNode has been introduced in v16 but it is not compatible with XNode so we do `as any` for backwards compatibility
210 defaultValue: arg.defaultValue !== undefined ? (_c = astFromValue(arg.defaultValue, arg.type)) !== null && _c !== void 0 ? _c : undefined : undefined,
211 directives: getDeprecatableDirectiveNodes(arg, schema, pathToDirectivesInExtensions),
212 };
213}
214export function astFromObjectType(type, schema, pathToDirectivesInExtensions) {
215 var _a, _b;
216 return {
217 kind: Kind.OBJECT_TYPE_DEFINITION,
218 description: (_b = (_a = type.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (type.description
219 ? {
220 kind: Kind.STRING,
221 value: type.description,
222 block: true,
223 }
224 : undefined),
225 name: {
226 kind: Kind.NAME,
227 value: type.name,
228 },
229 fields: Object.values(type.getFields()).map(field => astFromField(field, schema, pathToDirectivesInExtensions)),
230 interfaces: Object.values(type.getInterfaces()).map(iFace => astFromType(iFace)),
231 directives: getDirectiveNodes(type, schema, pathToDirectivesInExtensions),
232 };
233}
234export function astFromInterfaceType(type, schema, pathToDirectivesInExtensions) {
235 var _a, _b;
236 const node = {
237 kind: Kind.INTERFACE_TYPE_DEFINITION,
238 description: (_b = (_a = type.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (type.description
239 ? {
240 kind: Kind.STRING,
241 value: type.description,
242 block: true,
243 }
244 : undefined),
245 name: {
246 kind: Kind.NAME,
247 value: type.name,
248 },
249 fields: Object.values(type.getFields()).map(field => astFromField(field, schema, pathToDirectivesInExtensions)),
250 directives: getDirectiveNodes(type, schema, pathToDirectivesInExtensions),
251 };
252 if ('getInterfaces' in type) {
253 node.interfaces = Object.values(type.getInterfaces()).map(iFace => astFromType(iFace));
254 }
255 return node;
256}
257export function astFromUnionType(type, schema, pathToDirectivesInExtensions) {
258 var _a, _b;
259 return {
260 kind: Kind.UNION_TYPE_DEFINITION,
261 description: (_b = (_a = type.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (type.description
262 ? {
263 kind: Kind.STRING,
264 value: type.description,
265 block: true,
266 }
267 : undefined),
268 name: {
269 kind: Kind.NAME,
270 value: type.name,
271 },
272 // ConstXNode has been introduced in v16 but it is not compatible with XNode so we do `as any` for backwards compatibility
273 directives: getDirectiveNodes(type, schema, pathToDirectivesInExtensions),
274 types: type.getTypes().map(type => astFromType(type)),
275 };
276}
277export function astFromInputObjectType(type, schema, pathToDirectivesInExtensions) {
278 var _a, _b;
279 return {
280 kind: Kind.INPUT_OBJECT_TYPE_DEFINITION,
281 description: (_b = (_a = type.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (type.description
282 ? {
283 kind: Kind.STRING,
284 value: type.description,
285 block: true,
286 }
287 : undefined),
288 name: {
289 kind: Kind.NAME,
290 value: type.name,
291 },
292 fields: Object.values(type.getFields()).map(field => astFromInputField(field, schema, pathToDirectivesInExtensions)),
293 // ConstXNode has been introduced in v16 but it is not compatible with XNode so we do `as any` for backwards compatibility
294 directives: getDirectiveNodes(type, schema, pathToDirectivesInExtensions),
295 };
296}
297export function astFromEnumType(type, schema, pathToDirectivesInExtensions) {
298 var _a, _b;
299 return {
300 kind: Kind.ENUM_TYPE_DEFINITION,
301 description: (_b = (_a = type.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (type.description
302 ? {
303 kind: Kind.STRING,
304 value: type.description,
305 block: true,
306 }
307 : undefined),
308 name: {
309 kind: Kind.NAME,
310 value: type.name,
311 },
312 values: Object.values(type.getValues()).map(value => astFromEnumValue(value, schema, pathToDirectivesInExtensions)),
313 // ConstXNode has been introduced in v16 but it is not compatible with XNode so we do `as any` for backwards compatibility
314 directives: getDirectiveNodes(type, schema, pathToDirectivesInExtensions),
315 };
316}
317export function astFromScalarType(type, schema, pathToDirectivesInExtensions) {
318 var _a, _b, _c;
319 const directivesInExtensions = getDirectivesInExtensions(type, pathToDirectivesInExtensions);
320 const directives = directivesInExtensions
321 ? makeDirectiveNodes(schema, directivesInExtensions)
322 : ((_a = type.astNode) === null || _a === void 0 ? void 0 : _a.directives) || [];
323 const specifiedByValue = (type['specifiedByUrl'] || type['specifiedByURL']);
324 if (specifiedByValue && !directives.some(directiveNode => directiveNode.name.value === 'specifiedBy')) {
325 const specifiedByArgs = {
326 url: specifiedByValue,
327 };
328 directives.push(makeDirectiveNode('specifiedBy', specifiedByArgs));
329 }
330 return {
331 kind: Kind.SCALAR_TYPE_DEFINITION,
332 description: (_c = (_b = type.astNode) === null || _b === void 0 ? void 0 : _b.description) !== null && _c !== void 0 ? _c : (type.description
333 ? {
334 kind: Kind.STRING,
335 value: type.description,
336 block: true,
337 }
338 : undefined),
339 name: {
340 kind: Kind.NAME,
341 value: type.name,
342 },
343 // ConstXNode has been introduced in v16 but it is not compatible with XNode so we do `as any` for backwards compatibility
344 directives: directives,
345 };
346}
347export function astFromField(field, schema, pathToDirectivesInExtensions) {
348 var _a, _b;
349 return {
350 kind: Kind.FIELD_DEFINITION,
351 description: (_b = (_a = field.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (field.description
352 ? {
353 kind: Kind.STRING,
354 value: field.description,
355 block: true,
356 }
357 : undefined),
358 name: {
359 kind: Kind.NAME,
360 value: field.name,
361 },
362 arguments: field.args.map(arg => astFromArg(arg, schema, pathToDirectivesInExtensions)),
363 type: astFromType(field.type),
364 // ConstXNode has been introduced in v16 but it is not compatible with XNode so we do `as any` for backwards compatibility
365 directives: getDeprecatableDirectiveNodes(field, schema, pathToDirectivesInExtensions),
366 };
367}
368export function astFromInputField(field, schema, pathToDirectivesInExtensions) {
369 var _a, _b, _c;
370 return {
371 kind: Kind.INPUT_VALUE_DEFINITION,
372 description: (_b = (_a = field.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (field.description
373 ? {
374 kind: Kind.STRING,
375 value: field.description,
376 block: true,
377 }
378 : undefined),
379 name: {
380 kind: Kind.NAME,
381 value: field.name,
382 },
383 type: astFromType(field.type),
384 // ConstXNode has been introduced in v16 but it is not compatible with XNode so we do `as any` for backwards compatibility
385 directives: getDeprecatableDirectiveNodes(field, schema, pathToDirectivesInExtensions),
386 defaultValue: (_c = astFromValue(field.defaultValue, field.type)) !== null && _c !== void 0 ? _c : undefined,
387 };
388}
389export function astFromEnumValue(value, schema, pathToDirectivesInExtensions) {
390 var _a, _b;
391 return {
392 kind: Kind.ENUM_VALUE_DEFINITION,
393 description: (_b = (_a = value.astNode) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : (value.description
394 ? {
395 kind: Kind.STRING,
396 value: value.description,
397 block: true,
398 }
399 : undefined),
400 name: {
401 kind: Kind.NAME,
402 value: value.name,
403 },
404 // ConstXNode has been introduced in v16 but it is not compatible with XNode so we do `as any` for backwards compatibility
405 directives: getDeprecatableDirectiveNodes(value, schema, pathToDirectivesInExtensions),
406 };
407}
408export function makeDeprecatedDirective(deprecationReason) {
409 return makeDirectiveNode('deprecated', { reason: deprecationReason }, GraphQLDeprecatedDirective);
410}
411export function makeDirectiveNode(name, args, directive) {
412 const directiveArguments = [];
413 if (directive != null) {
414 for (const arg of directive.args) {
415 const argName = arg.name;
416 const argValue = args[argName];
417 if (argValue !== undefined) {
418 const value = astFromValue(argValue, arg.type);
419 if (value) {
420 directiveArguments.push({
421 kind: Kind.ARGUMENT,
422 name: {
423 kind: Kind.NAME,
424 value: argName,
425 },
426 value,
427 });
428 }
429 }
430 }
431 }
432 else {
433 for (const argName in args) {
434 const argValue = args[argName];
435 const value = astFromValueUntyped(argValue);
436 if (value) {
437 directiveArguments.push({
438 kind: Kind.ARGUMENT,
439 name: {
440 kind: Kind.NAME,
441 value: argName,
442 },
443 value,
444 });
445 }
446 }
447 }
448 return {
449 kind: Kind.DIRECTIVE,
450 name: {
451 kind: Kind.NAME,
452 value: name,
453 },
454 arguments: directiveArguments,
455 };
456}
457export function makeDirectiveNodes(schema, directiveValues) {
458 const directiveNodes = [];
459 for (const directiveName in directiveValues) {
460 const arrayOrSingleValue = directiveValues[directiveName];
461 const directive = schema === null || schema === void 0 ? void 0 : schema.getDirective(directiveName);
462 if (Array.isArray(arrayOrSingleValue)) {
463 for (const value of arrayOrSingleValue) {
464 directiveNodes.push(makeDirectiveNode(directiveName, value, directive));
465 }
466 }
467 else {
468 directiveNodes.push(makeDirectiveNode(directiveName, arrayOrSingleValue, directive));
469 }
470 }
471 return directiveNodes;
472}