1 | import { print, Kind, isSpecifiedScalarType, isIntrospectionType, isSpecifiedDirective, astFromValue, GraphQLDeprecatedDirective, isObjectType, isInterfaceType, isUnionType, isInputObjectType, isEnumType, isScalarType, } from 'graphql';
|
2 | import { astFromType } from './astFromType.js';
|
3 | import { getDirectivesInExtensions } from './get-directives.js';
|
4 | import { astFromValueUntyped } from './astFromValueUntyped.js';
|
5 | import { isSome } from './helpers.js';
|
6 | import { getRootTypeMap } from './rootTypes.js';
|
7 | export 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 |
|
54 |
|
55 | export function printSchemaWithDirectives(schema, options = {}) {
|
56 | const documentNode = getDocumentNodeFromSchema(schema, options);
|
57 | return print(documentNode);
|
58 | }
|
59 | export 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 |
|
108 | directives: directives,
|
109 | };
|
110 |
|
111 |
|
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 | }
|
122 | export 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 | }
|
144 | export 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 | }
|
167 | export 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 | }
|
193 | export 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 |
|
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 | }
|
214 | export 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 | }
|
234 | export 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 | }
|
257 | export 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 |
|
273 | directives: getDirectiveNodes(type, schema, pathToDirectivesInExtensions),
|
274 | types: type.getTypes().map(type => astFromType(type)),
|
275 | };
|
276 | }
|
277 | export 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 |
|
294 | directives: getDirectiveNodes(type, schema, pathToDirectivesInExtensions),
|
295 | };
|
296 | }
|
297 | export 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 |
|
314 | directives: getDirectiveNodes(type, schema, pathToDirectivesInExtensions),
|
315 | };
|
316 | }
|
317 | export 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 |
|
344 | directives: directives,
|
345 | };
|
346 | }
|
347 | export 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 |
|
365 | directives: getDeprecatableDirectiveNodes(field, schema, pathToDirectivesInExtensions),
|
366 | };
|
367 | }
|
368 | export 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 |
|
385 | directives: getDeprecatableDirectiveNodes(field, schema, pathToDirectivesInExtensions),
|
386 | defaultValue: (_c = astFromValue(field.defaultValue, field.type)) !== null && _c !== void 0 ? _c : undefined,
|
387 | };
|
388 | }
|
389 | export 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 |
|
405 | directives: getDeprecatableDirectiveNodes(value, schema, pathToDirectivesInExtensions),
|
406 | };
|
407 | }
|
408 | export function makeDeprecatedDirective(deprecationReason) {
|
409 | return makeDirectiveNode('deprecated', { reason: deprecationReason }, GraphQLDeprecatedDirective);
|
410 | }
|
411 | export 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 | }
|
457 | export 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 | }
|