UNPKG

32.9 kBJavaScriptView Raw
1import { __awaiter, __generator, __assign, __spread } from 'tslib';
2import { printSchemaWithDirectives, createSchemaDefinition, compareNodes, isNotEqual, isValidPath, parseGraphQLSDL } from '@graphql-tools/utils/es5';
3import { isAbsolute, resolve } from 'path';
4import { pathExists, pathExistsSync, readFile, readFileSync } from 'fs-extra';
5import { cwd } from 'process';
6import { Kind, visit, isSchema, parse, Source, getDescription, print, isExecutableDefinitionNode } from 'graphql';
7import { processImport } from '@graphql-tools/import/es5';
8
9function mergeArguments(args1, args2, config) {
10 const result = deduplicateArguments([].concat(args2, args1).filter(a => a));
11 if (config && config.sort) {
12 result.sort(compareNodes);
13 }
14 return result;
15}
16function deduplicateArguments(args) {
17 return args.reduce((acc, current) => {
18 const dup = acc.find(arg => arg.name.value === current.name.value);
19 if (!dup) {
20 return acc.concat([current]);
21 }
22 return acc;
23 }, []);
24}
25
26let commentsRegistry = {};
27function resetComments() {
28 commentsRegistry = {};
29}
30function collectComment(node) {
31 const entityName = node.name.value;
32 pushComment(node, entityName);
33 switch (node.kind) {
34 case 'EnumTypeDefinition':
35 node.values.forEach(value => {
36 pushComment(value, entityName, value.name.value);
37 });
38 break;
39 case 'ObjectTypeDefinition':
40 case 'InputObjectTypeDefinition':
41 case 'InterfaceTypeDefinition':
42 if (node.fields) {
43 node.fields.forEach((field) => {
44 pushComment(field, entityName, field.name.value);
45 if (isFieldDefinitionNode(field) && field.arguments) {
46 field.arguments.forEach(arg => {
47 pushComment(arg, entityName, field.name.value, arg.name.value);
48 });
49 }
50 });
51 }
52 break;
53 }
54}
55function pushComment(node, entity, field, argument) {
56 const comment = getDescription(node, { commentDescriptions: true });
57 if (typeof comment !== 'string' || comment.length === 0) {
58 return;
59 }
60 const keys = [entity];
61 if (field) {
62 keys.push(field);
63 if (argument) {
64 keys.push(argument);
65 }
66 }
67 const path = keys.join('.');
68 if (!commentsRegistry[path]) {
69 commentsRegistry[path] = [];
70 }
71 commentsRegistry[path].push(comment);
72}
73function printComment(comment) {
74 return '\n# ' + comment.replace(/\n/g, '\n# ');
75}
76/**
77 * Copyright (c) 2015-present, Facebook, Inc.
78 *
79 * This source code is licensed under the MIT license found in the
80 * LICENSE file in the root directory of this source tree.
81 */
82/**
83 * NOTE: ==> This file has been modified just to add comments to the printed AST
84 * This is a temp measure, we will move to using the original non modified printer.js ASAP.
85 */
86// import { visit, VisitFn } from 'graphql/language/visitor';
87/**
88 * Given maybeArray, print an empty string if it is null or empty, otherwise
89 * print all items together separated by separator if provided
90 */
91function join(maybeArray, separator) {
92 return maybeArray ? maybeArray.filter(x => x).join(separator || '') : '';
93}
94function addDescription(cb) {
95 return (node, _key, _parent, path, ancestors) => {
96 const keys = [];
97 const parent = path.reduce((prev, key) => {
98 if (['fields', 'arguments', 'values'].includes(key)) {
99 keys.push(prev.name.value);
100 }
101 return prev[key];
102 }, ancestors[0]);
103 const key = [...keys, parent.name.value].join('.');
104 const items = [];
105 if (commentsRegistry[key]) {
106 items.push(...commentsRegistry[key]);
107 }
108 return join([...items.map(printComment), node.description, cb(node)], '\n');
109 };
110}
111function indent(maybeString) {
112 return maybeString && ` ${maybeString.replace(/\n/g, '\n ')}`;
113}
114/**
115 * Given array, print each item on its own line, wrapped in an
116 * indented "{ }" block.
117 */
118function block(array) {
119 return array && array.length !== 0 ? `{\n${indent(join(array, '\n'))}\n}` : '';
120}
121/**
122 * If maybeString is not null or empty, then wrap with start and end, otherwise
123 * print an empty string.
124 */
125function wrap(start, maybeString, end) {
126 return maybeString ? start + maybeString + (end || '') : '';
127}
128/**
129 * Print a block string in the indented block form by adding a leading and
130 * trailing blank line. However, if a block string starts with whitespace and is
131 * a single-line, adding a leading blank line would strip that whitespace.
132 */
133function printBlockString(value, isDescription) {
134 const escaped = value.replace(/"""/g, '\\"""');
135 return (value[0] === ' ' || value[0] === '\t') && value.indexOf('\n') === -1
136 ? `"""${escaped.replace(/"$/, '"\n')}"""`
137 : `"""\n${isDescription ? escaped : indent(escaped)}\n"""`;
138}
139/**
140 * Converts an AST into a string, using one set of reasonable
141 * formatting rules.
142 */
143function printWithComments(ast) {
144 return visit(ast, {
145 leave: {
146 Name: node => node.value,
147 Variable: node => `$${node.name}`,
148 // Document
149 Document: node => `${node.definitions
150 .map(defNode => `${defNode}\n${defNode[0] === '#' ? '' : '\n'}`)
151 .join('')
152 .trim()}\n`,
153 OperationTypeDefinition: node => `${node.operation}: ${node.type}`,
154 VariableDefinition: ({ variable, type, defaultValue }) => `${variable}: ${type}${wrap(' = ', defaultValue)}`,
155 SelectionSet: ({ selections }) => block(selections),
156 Field: ({ alias, name, arguments: args, directives, selectionSet }) => join([wrap('', alias, ': ') + name + wrap('(', join(args, ', '), ')'), join(directives, ' '), selectionSet], ' '),
157 Argument: addDescription(({ name, value }) => `${name}: ${value}`),
158 // Value
159 IntValue: ({ value }) => value,
160 FloatValue: ({ value }) => value,
161 StringValue: ({ value, block: isBlockString }, key) => isBlockString ? printBlockString(value, key === 'description') : JSON.stringify(value),
162 BooleanValue: ({ value }) => (value ? 'true' : 'false'),
163 NullValue: () => 'null',
164 EnumValue: ({ value }) => value,
165 ListValue: ({ values }) => `[${join(values, ', ')}]`,
166 ObjectValue: ({ fields }) => `{${join(fields, ', ')}}`,
167 ObjectField: ({ name, value }) => `${name}: ${value}`,
168 // Directive
169 Directive: ({ name, arguments: args }) => `@${name}${wrap('(', join(args, ', '), ')')}`,
170 // Type
171 NamedType: ({ name }) => name,
172 ListType: ({ type }) => `[${type}]`,
173 NonNullType: ({ type }) => `${type}!`,
174 // Type System Definitions
175 SchemaDefinition: ({ directives, operationTypes }) => join(['schema', join(directives, ' '), block(operationTypes)], ' '),
176 ScalarTypeDefinition: addDescription(({ name, directives }) => join(['scalar', name, join(directives, ' ')], ' ')),
177 ObjectTypeDefinition: addDescription(({ name, interfaces, directives, fields }) => join(['type', name, wrap('implements ', join(interfaces, ' & ')), join(directives, ' '), block(fields)], ' ')),
178 FieldDefinition: addDescription(({ name, arguments: args, type, directives }) => `${name + wrap('(', join(args, ', '), ')')}: ${type}${wrap(' ', join(directives, ' '))}`),
179 InputValueDefinition: addDescription(({ name, type, defaultValue, directives }) => join([`${name}: ${type}`, wrap('= ', defaultValue), join(directives, ' ')], ' ')),
180 InterfaceTypeDefinition: addDescription(({ name, directives, fields }) => join(['interface', name, join(directives, ' '), block(fields)], ' ')),
181 UnionTypeDefinition: addDescription(({ name, directives, types }) => join(['union', name, join(directives, ' '), types && types.length !== 0 ? `= ${join(types, ' | ')}` : ''], ' ')),
182 EnumTypeDefinition: addDescription(({ name, directives, values }) => join(['enum', name, join(directives, ' '), block(values)], ' ')),
183 EnumValueDefinition: addDescription(({ name, directives }) => join([name, join(directives, ' ')], ' ')),
184 InputObjectTypeDefinition: addDescription(({ name, directives, fields }) => join(['input', name, join(directives, ' '), block(fields)], ' ')),
185 ScalarTypeExtension: ({ name, directives }) => join(['extend scalar', name, join(directives, ' ')], ' '),
186 ObjectTypeExtension: ({ name, interfaces, directives, fields }) => join(['extend type', name, wrap('implements ', join(interfaces, ' & ')), join(directives, ' '), block(fields)], ' '),
187 InterfaceTypeExtension: ({ name, directives, fields }) => join(['extend interface', name, join(directives, ' '), block(fields)], ' '),
188 UnionTypeExtension: ({ name, directives, types }) => join(['extend union', name, join(directives, ' '), types && types.length !== 0 ? `= ${join(types, ' | ')}` : ''], ' '),
189 EnumTypeExtension: ({ name, directives, values }) => join(['extend enum', name, join(directives, ' '), block(values)], ' '),
190 InputObjectTypeExtension: ({ name, directives, fields }) => join(['extend input', name, join(directives, ' '), block(fields)], ' '),
191 DirectiveDefinition: addDescription(({ name, arguments: args, locations }) => `directive @${name}${wrap('(', join(args, ', '), ')')} on ${join(locations, ' | ')}`),
192 },
193 });
194}
195function isFieldDefinitionNode(node) {
196 return node.kind === 'FieldDefinition';
197}
198
199function directiveAlreadyExists(directivesArr, otherDirective) {
200 return !!directivesArr.find(directive => directive.name.value === otherDirective.name.value);
201}
202function nameAlreadyExists(name, namesArr) {
203 return namesArr.some(({ value }) => value === name.value);
204}
205function mergeArguments$1(a1, a2) {
206 const result = [...a2];
207 for (const argument of a1) {
208 const existingIndex = result.findIndex(a => a.name.value === argument.name.value);
209 if (existingIndex > -1) {
210 const existingArg = result[existingIndex];
211 if (existingArg.value.kind === 'ListValue') {
212 const source = existingArg.value.values;
213 const target = argument.value.values;
214 // merge values of two lists
215 existingArg.value.values = deduplicateLists(source, target, (targetVal, source) => {
216 const value = targetVal.value;
217 return !value || !source.some((sourceVal) => sourceVal.value === value);
218 });
219 }
220 else {
221 existingArg.value = argument.value;
222 }
223 }
224 else {
225 result.push(argument);
226 }
227 }
228 return result;
229}
230function deduplicateDirectives(directives) {
231 return directives
232 .map((directive, i, all) => {
233 const firstAt = all.findIndex(d => d.name.value === directive.name.value);
234 if (firstAt !== i) {
235 const dup = all[firstAt];
236 directive.arguments = mergeArguments$1(directive.arguments, dup.arguments);
237 return null;
238 }
239 return directive;
240 })
241 .filter(d => d);
242}
243function mergeDirectives(d1 = [], d2 = [], config) {
244 const reverseOrder = config && config.reverseDirectives;
245 const asNext = reverseOrder ? d1 : d2;
246 const asFirst = reverseOrder ? d2 : d1;
247 const result = deduplicateDirectives([...asNext]);
248 for (const directive of asFirst) {
249 if (directiveAlreadyExists(result, directive)) {
250 const existingDirectiveIndex = result.findIndex(d => d.name.value === directive.name.value);
251 const existingDirective = result[existingDirectiveIndex];
252 result[existingDirectiveIndex].arguments = mergeArguments$1(directive.arguments || [], existingDirective.arguments || []);
253 }
254 else {
255 result.push(directive);
256 }
257 }
258 return result;
259}
260function validateInputs(node, existingNode) {
261 const printedNode = print(node);
262 const printedExistingNode = print(existingNode);
263 const leaveInputs = new RegExp('(directive @w*d*)|( on .*$)', 'g');
264 const sameArguments = printedNode.replace(leaveInputs, '') === printedExistingNode.replace(leaveInputs, '');
265 if (!sameArguments) {
266 throw new Error(`Unable to merge GraphQL directive "${node.name.value}". \nExisting directive: \n\t${printedExistingNode} \nReceived directive: \n\t${printedNode}`);
267 }
268}
269function mergeDirective(node, existingNode) {
270 if (existingNode) {
271 validateInputs(node, existingNode);
272 return {
273 ...node,
274 locations: [
275 ...existingNode.locations,
276 ...node.locations.filter(name => !nameAlreadyExists(name, existingNode.locations)),
277 ],
278 };
279 }
280 return node;
281}
282function deduplicateLists(source, target, filterFn) {
283 return source.concat(target.filter(val => filterFn(val, source)));
284}
285
286function mergeEnumValues(first, second, config) {
287 const enumValueMap = new Map();
288 for (const firstValue of first) {
289 enumValueMap.set(firstValue.name.value, firstValue);
290 }
291 for (const secondValue of second) {
292 const enumValue = secondValue.name.value;
293 if (enumValueMap.has(enumValue)) {
294 const firstValue = enumValueMap.get(enumValue);
295 firstValue.description = secondValue.description || firstValue.description;
296 firstValue.directives = mergeDirectives(secondValue.directives, firstValue.directives);
297 }
298 else {
299 enumValueMap.set(enumValue, secondValue);
300 }
301 }
302 const result = [...enumValueMap.values()];
303 if (config && config.sort) {
304 result.sort(compareNodes);
305 }
306 return result;
307}
308
309function mergeEnum(e1, e2, config) {
310 if (e2) {
311 return {
312 name: e1.name,
313 description: e1['description'] || e2['description'],
314 kind: (config && config.convertExtensions) || e1.kind === 'EnumTypeDefinition' || e2.kind === 'EnumTypeDefinition'
315 ? 'EnumTypeDefinition'
316 : 'EnumTypeExtension',
317 loc: e1.loc,
318 directives: mergeDirectives(e1.directives, e2.directives, config),
319 values: mergeEnumValues(e1.values, e2.values, config),
320 };
321 }
322 return config && config.convertExtensions
323 ? {
324 ...e1,
325 kind: 'EnumTypeDefinition',
326 }
327 : e1;
328}
329
330function isStringTypes(types) {
331 return typeof types === 'string';
332}
333function isSourceTypes(types) {
334 return types instanceof Source;
335}
336function isGraphQLType(definition) {
337 return definition.kind === 'ObjectTypeDefinition';
338}
339function isGraphQLTypeExtension(definition) {
340 return definition.kind === 'ObjectTypeExtension';
341}
342function isGraphQLEnum(definition) {
343 return definition.kind === 'EnumTypeDefinition';
344}
345function isGraphQLEnumExtension(definition) {
346 return definition.kind === 'EnumTypeExtension';
347}
348function isGraphQLUnion(definition) {
349 return definition.kind === 'UnionTypeDefinition';
350}
351function isGraphQLUnionExtension(definition) {
352 return definition.kind === 'UnionTypeExtension';
353}
354function isGraphQLScalar(definition) {
355 return definition.kind === 'ScalarTypeDefinition';
356}
357function isGraphQLScalarExtension(definition) {
358 return definition.kind === 'ScalarTypeExtension';
359}
360function isGraphQLInputType(definition) {
361 return definition.kind === 'InputObjectTypeDefinition';
362}
363function isGraphQLInputTypeExtension(definition) {
364 return definition.kind === 'InputObjectTypeExtension';
365}
366function isGraphQLInterface(definition) {
367 return definition.kind === 'InterfaceTypeDefinition';
368}
369function isGraphQLInterfaceExtension(definition) {
370 return definition.kind === 'InterfaceTypeExtension';
371}
372function isGraphQLDirective(definition) {
373 return definition.kind === 'DirectiveDefinition';
374}
375function extractType(type) {
376 let visitedType = type;
377 while (visitedType.kind === 'ListType' || visitedType.kind === 'NonNullType') {
378 visitedType = visitedType.type;
379 }
380 return visitedType;
381}
382function isSchemaDefinition(node) {
383 return node.kind === 'SchemaDefinition';
384}
385function isWrappingTypeNode(type) {
386 return type.kind !== Kind.NAMED_TYPE;
387}
388function isListTypeNode(type) {
389 return type.kind === Kind.LIST_TYPE;
390}
391function isNonNullTypeNode(type) {
392 return type.kind === Kind.NON_NULL_TYPE;
393}
394function printTypeNode(type) {
395 if (isListTypeNode(type)) {
396 return `[${printTypeNode(type.type)}]`;
397 }
398 if (isNonNullTypeNode(type)) {
399 return `${printTypeNode(type.type)}!`;
400 }
401 return type.name.value;
402}
403
404function fieldAlreadyExists(fieldsArr, otherField) {
405 const result = fieldsArr.find(field => field.name.value === otherField.name.value);
406 if (result) {
407 const t1 = extractType(result.type);
408 const t2 = extractType(otherField.type);
409 if (t1.name.value !== t2.name.value) {
410 throw new Error(`Field "${otherField.name.value}" already defined with a different type. Declared as "${t1.name.value}", but you tried to override with "${t2.name.value}"`);
411 }
412 }
413 return !!result;
414}
415function mergeFields(type, f1, f2, config) {
416 const result = [...f2];
417 for (const field of f1) {
418 if (fieldAlreadyExists(result, field)) {
419 const existing = result.find((f) => f.name.value === field.name.value);
420 if (config && config.throwOnConflict) {
421 preventConflicts(type, existing, field, false);
422 }
423 else {
424 preventConflicts(type, existing, field, true);
425 }
426 if (isNonNullTypeNode(field.type) && !isNonNullTypeNode(existing.type)) {
427 existing.type = field.type;
428 }
429 existing.arguments = mergeArguments(field['arguments'] || [], existing.arguments || [], config);
430 existing.directives = mergeDirectives(field.directives, existing.directives, config);
431 existing.description = field.description || existing.description;
432 }
433 else {
434 result.push(field);
435 }
436 }
437 if (config && config.sort) {
438 result.sort(compareNodes);
439 }
440 if (config && config.exclusions) {
441 return result.filter(field => !config.exclusions.includes(`${type.name.value}.${field.name.value}`));
442 }
443 return result;
444}
445function preventConflicts(type, a, b, ignoreNullability = false) {
446 const aType = printTypeNode(a.type);
447 const bType = printTypeNode(b.type);
448 if (isNotEqual(aType, bType)) {
449 if (safeChangeForFieldType(a.type, b.type, ignoreNullability) === false) {
450 throw new Error(`Field '${type.name.value}.${a.name.value}' changed type from '${aType}' to '${bType}'`);
451 }
452 }
453}
454function safeChangeForFieldType(oldType, newType, ignoreNullability = false) {
455 // both are named
456 if (!isWrappingTypeNode(oldType) && !isWrappingTypeNode(newType)) {
457 return oldType.toString() === newType.toString();
458 }
459 // new is non-null
460 if (isNonNullTypeNode(newType)) {
461 const ofType = isNonNullTypeNode(oldType) ? oldType.type : oldType;
462 return safeChangeForFieldType(ofType, newType.type);
463 }
464 // old is non-null
465 if (isNonNullTypeNode(oldType)) {
466 return safeChangeForFieldType(newType, oldType, ignoreNullability);
467 }
468 // old is list
469 if (isListTypeNode(oldType)) {
470 return ((isListTypeNode(newType) && safeChangeForFieldType(oldType.type, newType.type)) ||
471 (isNonNullTypeNode(newType) && safeChangeForFieldType(oldType, newType['type'])));
472 }
473 return false;
474}
475
476function mergeInputType(node, existingNode, config) {
477 if (existingNode) {
478 try {
479 return {
480 name: node.name,
481 description: node['description'] || existingNode['description'],
482 kind: (config && config.convertExtensions) ||
483 node.kind === 'InputObjectTypeDefinition' ||
484 existingNode.kind === 'InputObjectTypeDefinition'
485 ? 'InputObjectTypeDefinition'
486 : 'InputObjectTypeExtension',
487 loc: node.loc,
488 fields: mergeFields(node, node.fields, existingNode.fields, config),
489 directives: mergeDirectives(node.directives, existingNode.directives, config),
490 };
491 }
492 catch (e) {
493 throw new Error(`Unable to merge GraphQL input type "${node.name.value}": ${e.message}`);
494 }
495 }
496 return config && config.convertExtensions
497 ? {
498 ...node,
499 kind: 'InputObjectTypeDefinition',
500 }
501 : node;
502}
503
504function mergeInterface(node, existingNode, config) {
505 if (existingNode) {
506 try {
507 return {
508 name: node.name,
509 description: node['description'] || existingNode['description'],
510 kind: (config && config.convertExtensions) ||
511 node.kind === 'InterfaceTypeDefinition' ||
512 existingNode.kind === 'InterfaceTypeDefinition'
513 ? 'InterfaceTypeDefinition'
514 : 'InterfaceTypeExtension',
515 loc: node.loc,
516 fields: mergeFields(node, node.fields, existingNode.fields, config),
517 directives: mergeDirectives(node.directives, existingNode.directives, config),
518 };
519 }
520 catch (e) {
521 throw new Error(`Unable to merge GraphQL interface "${node.name.value}": ${e.message}`);
522 }
523 }
524 return config && config.convertExtensions
525 ? {
526 ...node,
527 kind: 'InterfaceTypeDefinition',
528 }
529 : node;
530}
531
532function alreadyExists(arr, other) {
533 return !!arr.find(i => i.name.value === other.name.value);
534}
535function mergeNamedTypeArray(first, second, config) {
536 const result = [...second, ...first.filter(d => !alreadyExists(second, d))];
537 if (config && config.sort) {
538 result.sort(compareNodes);
539 }
540 return result;
541}
542
543function mergeType(node, existingNode, config) {
544 if (existingNode) {
545 try {
546 return {
547 name: node.name,
548 description: node['description'] || existingNode['description'],
549 kind: (config && config.convertExtensions) ||
550 node.kind === 'ObjectTypeDefinition' ||
551 existingNode.kind === 'ObjectTypeDefinition'
552 ? 'ObjectTypeDefinition'
553 : 'ObjectTypeExtension',
554 loc: node.loc,
555 fields: mergeFields(node, node.fields, existingNode.fields, config),
556 directives: mergeDirectives(node.directives, existingNode.directives, config),
557 interfaces: mergeNamedTypeArray(node.interfaces, existingNode.interfaces, config),
558 };
559 }
560 catch (e) {
561 throw new Error(`Unable to merge GraphQL type "${node.name.value}": ${e.message}`);
562 }
563 }
564 return config && config.convertExtensions
565 ? {
566 ...node,
567 kind: 'ObjectTypeDefinition',
568 }
569 : node;
570}
571
572function mergeUnion(first, second, config) {
573 if (second) {
574 return {
575 name: first.name,
576 description: first['description'] || second['description'],
577 directives: mergeDirectives(first.directives, second.directives, config),
578 kind: (config && config.convertExtensions) ||
579 first.kind === 'UnionTypeDefinition' ||
580 second.kind === 'UnionTypeDefinition'
581 ? 'UnionTypeDefinition'
582 : 'UnionTypeExtension',
583 loc: first.loc,
584 types: mergeNamedTypeArray(first.types, second.types, config),
585 };
586 }
587 return config && config.convertExtensions
588 ? {
589 ...first,
590 kind: 'UnionTypeDefinition',
591 }
592 : first;
593}
594
595function mergeGraphQLNodes(nodes, config) {
596 return nodes.reduce((prev, nodeDefinition) => {
597 const node = nodeDefinition;
598 if (node && node.name && node.name.value) {
599 const name = node.name.value;
600 if (config && config.commentDescriptions) {
601 collectComment(node);
602 }
603 if (config &&
604 config.exclusions &&
605 (config.exclusions.includes(name + '.*') || config.exclusions.includes(name))) {
606 delete prev[name];
607 }
608 else if (isGraphQLType(nodeDefinition) || isGraphQLTypeExtension(nodeDefinition)) {
609 prev[name] = mergeType(nodeDefinition, prev[name], config);
610 }
611 else if (isGraphQLEnum(nodeDefinition) || isGraphQLEnumExtension(nodeDefinition)) {
612 prev[name] = mergeEnum(nodeDefinition, prev[name], config);
613 }
614 else if (isGraphQLUnion(nodeDefinition) || isGraphQLUnionExtension(nodeDefinition)) {
615 prev[name] = mergeUnion(nodeDefinition, prev[name], config);
616 }
617 else if (isGraphQLScalar(nodeDefinition) || isGraphQLScalarExtension(nodeDefinition)) {
618 prev[name] = nodeDefinition;
619 }
620 else if (isGraphQLInputType(nodeDefinition) || isGraphQLInputTypeExtension(nodeDefinition)) {
621 prev[name] = mergeInputType(nodeDefinition, prev[name], config);
622 }
623 else if (isGraphQLInterface(nodeDefinition) || isGraphQLInterfaceExtension(nodeDefinition)) {
624 prev[name] = mergeInterface(nodeDefinition, prev[name], config);
625 }
626 else if (isGraphQLDirective(nodeDefinition)) {
627 prev[name] = mergeDirective(nodeDefinition, prev[name]);
628 }
629 }
630 return prev;
631 }, {});
632}
633
634function mergeTypeDefs(types, config) {
635 resetComments();
636 const doc = {
637 kind: Kind.DOCUMENT,
638 definitions: mergeGraphQLTypes(types, {
639 useSchemaDefinition: true,
640 forceSchemaDefinition: false,
641 throwOnConflict: false,
642 commentDescriptions: false,
643 ...config,
644 }),
645 };
646 let result;
647 if (config && config.commentDescriptions) {
648 result = printWithComments(doc);
649 }
650 else {
651 result = doc;
652 }
653 resetComments();
654 return result;
655}
656function mergeGraphQLTypes(types, config) {
657 resetComments();
658 const allNodes = types
659 .map(type => {
660 if (Array.isArray(type)) {
661 type = mergeTypeDefs(type);
662 }
663 if (isSchema(type)) {
664 return parse(printSchemaWithDirectives(type));
665 }
666 else if (isStringTypes(type) || isSourceTypes(type)) {
667 return parse(type);
668 }
669 return type;
670 })
671 .map(ast => ast.definitions)
672 .reduce((defs, newDef = []) => [...defs, ...newDef], []);
673 // XXX: right now we don't handle multiple schema definitions
674 let schemaDef = allNodes.filter(isSchemaDefinition).reduce((def, node) => {
675 node.operationTypes
676 .filter(op => op.type.name.value)
677 .forEach(op => {
678 def[op.operation] = op.type.name.value;
679 });
680 return def;
681 }, {
682 query: null,
683 mutation: null,
684 subscription: null,
685 });
686 const mergedNodes = mergeGraphQLNodes(allNodes, config);
687 const allTypes = Object.keys(mergedNodes);
688 if (config && config.sort) {
689 allTypes.sort(typeof config.sort === 'function' ? config.sort : undefined);
690 }
691 if (config && config.useSchemaDefinition) {
692 const queryType = schemaDef.query ? schemaDef.query : allTypes.find(t => t === 'Query');
693 const mutationType = schemaDef.mutation ? schemaDef.mutation : allTypes.find(t => t === 'Mutation');
694 const subscriptionType = schemaDef.subscription ? schemaDef.subscription : allTypes.find(t => t === 'Subscription');
695 schemaDef = {
696 query: queryType,
697 mutation: mutationType,
698 subscription: subscriptionType,
699 };
700 }
701 const schemaDefinition = createSchemaDefinition(schemaDef, {
702 force: config.forceSchemaDefinition,
703 });
704 if (!schemaDefinition) {
705 return Object.values(mergedNodes);
706 }
707 return [...Object.values(mergedNodes), parse(schemaDefinition).definitions[0]];
708}
709
710var FILE_EXTENSIONS = ['.gql', '.gqls', '.graphql', '.graphqls'];
711function isGraphQLImportFile(rawSDL) {
712 var trimmedRawSDL = rawSDL.trim();
713 return trimmedRawSDL.startsWith('# import') || trimmedRawSDL.startsWith('#import');
714}
715/**
716 * This loader loads documents and type definitions from `.graphql` files.
717 *
718 * You can load a single source:
719 *
720 * ```js
721 * const schema = await loadSchema('schema.graphql', {
722 * loaders: [
723 * new GraphQLFileLoader()
724 * ]
725 * });
726 * ```
727 *
728 * Or provide a glob pattern to load multiple sources:
729 *
730 * ```js
731 * const schema = await loadSchema('graphql/*.graphql', {
732 * loaders: [
733 * new GraphQLFileLoader()
734 * ]
735 * });
736 * ```
737 */
738var GraphQLFileLoader = /** @class */ (function () {
739 function GraphQLFileLoader() {
740 }
741 GraphQLFileLoader.prototype.loaderId = function () {
742 return 'graphql-file';
743 };
744 GraphQLFileLoader.prototype.canLoad = function (pointer, options) {
745 return __awaiter(this, void 0, void 0, function () {
746 var normalizedFilePath;
747 return __generator(this, function (_a) {
748 if (isValidPath(pointer)) {
749 if (FILE_EXTENSIONS.find(function (extension) { return pointer.endsWith(extension); })) {
750 normalizedFilePath = isAbsolute(pointer) ? pointer : resolve(options.cwd || cwd(), pointer);
751 return [2 /*return*/, pathExists(normalizedFilePath)];
752 }
753 }
754 return [2 /*return*/, false];
755 });
756 });
757 };
758 GraphQLFileLoader.prototype.canLoadSync = function (pointer, options) {
759 if (isValidPath(pointer)) {
760 if (FILE_EXTENSIONS.find(function (extension) { return pointer.endsWith(extension); })) {
761 var normalizedFilePath = isAbsolute(pointer) ? pointer : resolve(options.cwd || cwd(), pointer);
762 return pathExistsSync(normalizedFilePath);
763 }
764 }
765 return false;
766 };
767 GraphQLFileLoader.prototype.load = function (pointer, options) {
768 return __awaiter(this, void 0, void 0, function () {
769 var normalizedFilePath, rawSDL;
770 return __generator(this, function (_a) {
771 switch (_a.label) {
772 case 0:
773 normalizedFilePath = isAbsolute(pointer) ? pointer : resolve(options.cwd || cwd(), pointer);
774 return [4 /*yield*/, readFile(normalizedFilePath, { encoding: 'utf8' })];
775 case 1:
776 rawSDL = _a.sent();
777 return [2 /*return*/, this.handleFileContent(rawSDL, pointer, options)];
778 }
779 });
780 });
781 };
782 GraphQLFileLoader.prototype.loadSync = function (pointer, options) {
783 var normalizedFilePath = isAbsolute(pointer) ? pointer : resolve(options.cwd || cwd(), pointer);
784 var rawSDL = readFileSync(normalizedFilePath, { encoding: 'utf8' });
785 return this.handleFileContent(rawSDL, pointer, options);
786 };
787 GraphQLFileLoader.prototype.handleFileContent = function (rawSDL, pointer, options) {
788 if (!options.skipGraphQLImport && isGraphQLImportFile(rawSDL)) {
789 var document_1 = processImport(pointer, options.cwd);
790 var typeSystemDefinitions = document_1.definitions
791 .filter(function (d) { return !isExecutableDefinitionNode(d); })
792 .map(function (definition) { return ({
793 kind: Kind.DOCUMENT,
794 definitions: [definition],
795 }); });
796 var mergedTypeDefs = mergeTypeDefs(typeSystemDefinitions, { useSchemaDefinition: false });
797 var executableDefinitions = document_1.definitions.filter(isExecutableDefinitionNode);
798 return {
799 location: pointer,
800 document: __assign(__assign({}, mergedTypeDefs), { definitions: __spread(mergedTypeDefs.definitions, executableDefinitions) }),
801 };
802 }
803 return parseGraphQLSDL(pointer, rawSDL, options);
804 };
805 return GraphQLFileLoader;
806}());
807
808export { GraphQLFileLoader };
809//# sourceMappingURL=index.esm.js.map