UNPKG

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