UNPKG

155 kBJavaScriptView Raw
1import { parse, isNonNullType, GraphQLError, Kind, valueFromAST, print, isObjectType, isScalarType, isSpecifiedScalarType, isIntrospectionType, printType, specifiedRules, validate, buildSchema, buildClientSchema, Source, isListType, getNamedType, isEnumType, isUnionType, isInterfaceType, GraphQLString, GraphQLNonNull, GraphQLList, isInputObjectType, GraphQLID, GraphQLBoolean, GraphQLFloat, GraphQLInt, GraphQLObjectType, GraphQLInterfaceType, GraphQLInputObjectType, isSpecifiedDirective, GraphQLDirective, GraphQLUnionType, GraphQLEnumType, GraphQLScalarType, isNamedType, getNullableType, isLeafType, GraphQLSchema, isSchema, isInputType, valueFromASTUntyped, isDirective, getDirectiveValues as getDirectiveValues$1, GraphQLSkipDirective, GraphQLIncludeDirective, typeFromAST, isAbstractType, isCompositeType, doTypesOverlap, getOperationAST, getOperationRootType } from 'graphql';
2import AggregateError from '@ardatan/aggregate-error';
3import { camelCase } from 'camel-case';
4
5const asArray = (fns) => (Array.isArray(fns) ? fns : fns ? [fns] : []);
6function isEqual(a, b) {
7 if (Array.isArray(a) && Array.isArray(b)) {
8 if (a.length !== b.length) {
9 return false;
10 }
11 for (let index = 0; index < a.length; index++) {
12 if (a[index] !== b[index]) {
13 return false;
14 }
15 }
16 return true;
17 }
18 return a === b || (!a && !b);
19}
20function isNotEqual(a, b) {
21 return !isEqual(a, b);
22}
23function isDocumentString(str) {
24 // XXX: is-valid-path or is-glob treat SDL as a valid path
25 // (`scalar Date` for example)
26 // this why checking the extension is fast enough
27 // and prevent from parsing the string in order to find out
28 // if the string is a SDL
29 if (/\.[a-z0-9]+$/i.test(str)) {
30 return false;
31 }
32 try {
33 parse(str);
34 return true;
35 }
36 catch (e) { }
37 return false;
38}
39const invalidPathRegex = /[‘“!$%&^<=>`]/;
40function isValidPath(str) {
41 return typeof str === 'string' && !invalidPathRegex.test(str);
42}
43function compareStrings(a, b) {
44 if (a.toString() < b.toString()) {
45 return -1;
46 }
47 if (a.toString() > b.toString()) {
48 return 1;
49 }
50 return 0;
51}
52function nodeToString(a) {
53 if ('alias' in a) {
54 return a.alias.value;
55 }
56 if ('name' in a) {
57 return a.name.value;
58 }
59 return a.kind;
60}
61function compareNodes(a, b, customFn) {
62 const aStr = nodeToString(a);
63 const bStr = nodeToString(b);
64 if (typeof customFn === 'function') {
65 return customFn(aStr, bStr);
66 }
67 return compareStrings(aStr, bStr);
68}
69
70function debugLog(...args) {
71 if (process && process.env && process.env.DEBUG && !process.env.GQL_tools_NODEBUG) {
72 // tslint:disable-next-line: no-console
73 console.log(...args);
74 }
75}
76
77const fixWindowsPath = (path) => path.replace(/\\/g, '/');
78
79const flattenArray = (arr) => arr.reduce((acc, next) => acc.concat(Array.isArray(next) ? flattenArray(next) : next), []);
80
81const MAX_ARRAY_LENGTH = 10;
82const MAX_RECURSIVE_DEPTH = 2;
83/**
84 * Used to print values in error messages.
85 */
86function inspect(value) {
87 return formatValue(value, []);
88}
89function formatValue(value, seenValues) {
90 switch (typeof value) {
91 case 'string':
92 return JSON.stringify(value);
93 case 'function':
94 return value.name ? `[function ${value.name}]` : '[function]';
95 case 'object':
96 if (value === null) {
97 return 'null';
98 }
99 return formatObjectValue(value, seenValues);
100 default:
101 return String(value);
102 }
103}
104function formatObjectValue(value, previouslySeenValues) {
105 if (previouslySeenValues.indexOf(value) !== -1) {
106 return '[Circular]';
107 }
108 const seenValues = [...previouslySeenValues, value];
109 const customInspectFn = getCustomFn(value);
110 if (customInspectFn !== undefined) {
111 const customValue = customInspectFn.call(value);
112 // check for infinite recursion
113 if (customValue !== value) {
114 return typeof customValue === 'string' ? customValue : formatValue(customValue, seenValues);
115 }
116 }
117 else if (Array.isArray(value)) {
118 return formatArray(value, seenValues);
119 }
120 return formatObject(value, seenValues);
121}
122function formatObject(object, seenValues) {
123 const keys = Object.keys(object);
124 if (keys.length === 0) {
125 return '{}';
126 }
127 if (seenValues.length > MAX_RECURSIVE_DEPTH) {
128 return '[' + getObjectTag(object) + ']';
129 }
130 const properties = keys.map(key => {
131 const value = formatValue(object[key], seenValues);
132 return key + ': ' + value;
133 });
134 return '{ ' + properties.join(', ') + ' }';
135}
136function formatArray(array, seenValues) {
137 if (array.length === 0) {
138 return '[]';
139 }
140 if (seenValues.length > MAX_RECURSIVE_DEPTH) {
141 return '[Array]';
142 }
143 const len = Math.min(MAX_ARRAY_LENGTH, array.length);
144 const remaining = array.length - len;
145 const items = [];
146 for (let i = 0; i < len; ++i) {
147 items.push(formatValue(array[i], seenValues));
148 }
149 if (remaining === 1) {
150 items.push('... 1 more item');
151 }
152 else if (remaining > 1) {
153 items.push(`... ${remaining.toString(10)} more items`);
154 }
155 return '[' + items.join(', ') + ']';
156}
157function getCustomFn(obj) {
158 if (typeof obj.inspect === 'function') {
159 return obj.inspect;
160 }
161}
162function getObjectTag(obj) {
163 const tag = Object.prototype.toString
164 .call(obj)
165 .replace(/^\[object /, '')
166 .replace(/]$/, '');
167 if (tag === 'Object' && typeof obj.constructor === 'function') {
168 const name = obj.constructor.name;
169 if (typeof name === 'string' && name !== '') {
170 return name;
171 }
172 }
173 return tag;
174}
175
176/**
177 * Prepares an object map of argument values given a list of argument
178 * definitions and list of argument AST nodes.
179 *
180 * Note: The returned value is a plain Object with a prototype, since it is
181 * exposed to user code. Care should be taken to not pull values from the
182 * Object prototype.
183 */
184function getArgumentValues(def, node, variableValues = {}) {
185 var _a;
186 const variableMap = Object.entries(variableValues).reduce((prev, [key, value]) => ({
187 ...prev,
188 [key]: value,
189 }), {});
190 const coercedValues = {};
191 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
192 const argumentNodes = (_a = node.arguments) !== null && _a !== void 0 ? _a : [];
193 const argNodeMap = argumentNodes.reduce((prev, arg) => ({
194 ...prev,
195 [arg.name.value]: arg,
196 }), {});
197 for (const argDef of def.args) {
198 const name = argDef.name;
199 const argType = argDef.type;
200 const argumentNode = argNodeMap[name];
201 if (!argumentNode) {
202 if (argDef.defaultValue !== undefined) {
203 coercedValues[name] = argDef.defaultValue;
204 }
205 else if (isNonNullType(argType)) {
206 throw new GraphQLError(`Argument "${name}" of required type "${inspect(argType)}" ` + 'was not provided.', node);
207 }
208 continue;
209 }
210 const valueNode = argumentNode.value;
211 let isNull = valueNode.kind === Kind.NULL;
212 if (valueNode.kind === Kind.VARIABLE) {
213 const variableName = valueNode.name.value;
214 if (variableValues == null || !(variableName in variableMap)) {
215 if (argDef.defaultValue !== undefined) {
216 coercedValues[name] = argDef.defaultValue;
217 }
218 else if (isNonNullType(argType)) {
219 throw new GraphQLError(`Argument "${name}" of required type "${inspect(argType)}" ` +
220 `was provided the variable "$${variableName}" which was not provided a runtime value.`, valueNode);
221 }
222 continue;
223 }
224 isNull = variableValues[variableName] == null;
225 }
226 if (isNull && isNonNullType(argType)) {
227 throw new GraphQLError(`Argument "${name}" of non-null type "${inspect(argType)}" ` + 'must not be null.', valueNode);
228 }
229 const coercedValue = valueFromAST(valueNode, argType, variableValues);
230 if (coercedValue === undefined) {
231 // Note: ValuesOfCorrectTypeRule validation should catch this before
232 // execution. This is a runtime check to ensure execution does not
233 // continue with an invalid argument value.
234 throw new GraphQLError(`Argument "${name}" has invalid value ${print(valueNode)}.`, valueNode);
235 }
236 coercedValues[name] = coercedValue;
237 }
238 return coercedValues;
239}
240
241function getDirectives(schema, node) {
242 const schemaDirectives = schema && schema.getDirectives ? schema.getDirectives() : [];
243 const schemaDirectiveMap = schemaDirectives.reduce((schemaDirectiveMap, schemaDirective) => {
244 schemaDirectiveMap[schemaDirective.name] = schemaDirective;
245 return schemaDirectiveMap;
246 }, {});
247 let astNodes = [];
248 if (node.astNode) {
249 astNodes.push(node.astNode);
250 }
251 if ('extensionASTNodes' in node && node.extensionASTNodes) {
252 astNodes = [...astNodes, ...node.extensionASTNodes];
253 }
254 const result = {};
255 astNodes.forEach(astNode => {
256 if (astNode.directives) {
257 astNode.directives.forEach(directive => {
258 const schemaDirective = schemaDirectiveMap[directive.name.value];
259 if (schemaDirective) {
260 const directiveValue = getDirectiveValues(schemaDirective, astNode);
261 if (schemaDirective.isRepeatable) {
262 if (result[schemaDirective.name]) {
263 result[schemaDirective.name] = result[schemaDirective.name].concat([directiveValue]);
264 }
265 else {
266 result[schemaDirective.name] = [directiveValue];
267 }
268 }
269 else {
270 result[schemaDirective.name] = directiveValue;
271 }
272 }
273 });
274 }
275 });
276 return result;
277}
278// graphql-js getDirectiveValues does not handle repeatable directives
279function getDirectiveValues(directiveDef, node) {
280 if (node.directives) {
281 if (directiveDef.isRepeatable) {
282 const directiveNodes = node.directives.filter(directive => directive.name.value === directiveDef.name);
283 return directiveNodes.map(directiveNode => getArgumentValues(directiveDef, directiveNode));
284 }
285 const directiveNode = node.directives.find(directive => directive.name.value === directiveDef.name);
286 return getArgumentValues(directiveDef, directiveNode);
287 }
288}
289
290function isObjectTypeDefinitionOrExtension(obj) {
291 return obj && (obj.kind === 'ObjectTypeDefinition' || obj.kind === 'ObjectTypeExtension');
292}
293function parseDirectiveValue(value) {
294 switch (value.kind) {
295 case Kind.INT:
296 return parseInt(value.value);
297 case Kind.FLOAT:
298 return parseFloat(value.value);
299 case Kind.BOOLEAN:
300 return Boolean(value.value);
301 case Kind.STRING:
302 case Kind.ENUM:
303 return value.value;
304 case Kind.LIST:
305 return value.values.map(v => parseDirectiveValue(v));
306 case Kind.OBJECT:
307 return value.fields.reduce((prev, v) => ({ ...prev, [v.name.value]: parseDirectiveValue(v.value) }), {});
308 case Kind.NULL:
309 return null;
310 default:
311 return null;
312 }
313}
314function getFieldsWithDirectives(documentNode) {
315 const result = {};
316 const allTypes = documentNode.definitions.filter(isObjectTypeDefinitionOrExtension);
317 for (const type of allTypes) {
318 const typeName = type.name.value;
319 for (const field of type.fields) {
320 if (field.directives && field.directives.length > 0) {
321 const fieldName = field.name.value;
322 const key = `${typeName}.${fieldName}`;
323 const directives = field.directives.map(d => ({
324 name: d.name.value,
325 args: (d.arguments || []).reduce((prev, arg) => ({ ...prev, [arg.name.value]: parseDirectiveValue(arg.value) }), {}),
326 }));
327 result[key] = directives;
328 }
329 }
330 }
331 return result;
332}
333
334function getImplementingTypes(interfaceName, schema) {
335 const allTypesMap = schema.getTypeMap();
336 const result = [];
337 for (const graphqlTypeName in allTypesMap) {
338 const graphqlType = allTypesMap[graphqlTypeName];
339 if (isObjectType(graphqlType)) {
340 const allInterfaces = graphqlType.getInterfaces();
341 if (allInterfaces.find(int => int.name === interfaceName)) {
342 result.push(graphqlType.name);
343 }
344 }
345 }
346 return result;
347}
348
349function createSchemaDefinition(def, config) {
350 const schemaRoot = {};
351 if (def.query) {
352 schemaRoot.query = def.query.toString();
353 }
354 if (def.mutation) {
355 schemaRoot.mutation = def.mutation.toString();
356 }
357 if (def.subscription) {
358 schemaRoot.subscription = def.subscription.toString();
359 }
360 const fields = Object.keys(schemaRoot)
361 .map(rootType => (schemaRoot[rootType] ? `${rootType}: ${schemaRoot[rootType]}` : null))
362 .filter(a => a);
363 if (fields.length) {
364 return `schema { ${fields.join('\n')} }`;
365 }
366 if (config && config.force) {
367 return ` schema { query: Query } `;
368 }
369 return undefined;
370}
371
372function printSchemaWithDirectives(schema, _options = {}) {
373 var _a;
374 const typesMap = schema.getTypeMap();
375 const result = [getSchemaDefinition(schema)];
376 for (const typeName in typesMap) {
377 const type = typesMap[typeName];
378 const isPredefinedScalar = isScalarType(type) && isSpecifiedScalarType(type);
379 const isIntrospection = isIntrospectionType(type);
380 if (isPredefinedScalar || isIntrospection) {
381 continue;
382 }
383 // KAMIL: we might want to turn on descriptions in future
384 result.push(print((_a = correctType(typeName, typesMap)) === null || _a === void 0 ? void 0 : _a.astNode));
385 }
386 const directives = schema.getDirectives();
387 for (const directive of directives) {
388 if (directive.astNode) {
389 result.push(print(directive.astNode));
390 }
391 }
392 return result.join('\n');
393}
394function extendDefinition(type) {
395 switch (type.astNode.kind) {
396 case Kind.OBJECT_TYPE_DEFINITION:
397 return {
398 ...type.astNode,
399 fields: type.astNode.fields.concat(type.extensionASTNodes.reduce((fields, node) => fields.concat(node.fields), [])),
400 };
401 case Kind.INPUT_OBJECT_TYPE_DEFINITION:
402 return {
403 ...type.astNode,
404 fields: type.astNode.fields.concat(type.extensionASTNodes.reduce((fields, node) => fields.concat(node.fields), [])),
405 };
406 default:
407 return type.astNode;
408 }
409}
410function correctType(typeName, typesMap) {
411 var _a;
412 const type = typesMap[typeName];
413 type.name = typeName.toString();
414 if (type.astNode && type.extensionASTNodes) {
415 type.astNode = type.extensionASTNodes ? extendDefinition(type) : type.astNode;
416 }
417 const doc = parse(printType(type));
418 const fixedAstNode = doc.definitions[0];
419 const originalAstNode = type === null || type === void 0 ? void 0 : type.astNode;
420 if (originalAstNode) {
421 fixedAstNode.directives = originalAstNode === null || originalAstNode === void 0 ? void 0 : originalAstNode.directives;
422 if (fixedAstNode && 'fields' in fixedAstNode && originalAstNode && 'fields' in originalAstNode) {
423 for (const fieldDefinitionNode of fixedAstNode.fields) {
424 const originalFieldDefinitionNode = originalAstNode.fields.find(field => field.name.value === fieldDefinitionNode.name.value);
425 fieldDefinitionNode.directives = originalFieldDefinitionNode === null || originalFieldDefinitionNode === void 0 ? void 0 : originalFieldDefinitionNode.directives;
426 if (fieldDefinitionNode &&
427 'arguments' in fieldDefinitionNode &&
428 originalFieldDefinitionNode &&
429 'arguments' in originalFieldDefinitionNode) {
430 for (const argument of fieldDefinitionNode.arguments) {
431 const originalArgumentNode = (_a = originalFieldDefinitionNode.arguments) === null || _a === void 0 ? void 0 : _a.find(arg => arg.name.value === argument.name.value);
432 argument.directives = originalArgumentNode.directives;
433 }
434 }
435 }
436 }
437 else if (fixedAstNode && 'values' in fixedAstNode && originalAstNode && 'values' in originalAstNode) {
438 for (const valueDefinitionNode of fixedAstNode.values) {
439 const originalValueDefinitionNode = originalAstNode.values.find(valueNode => valueNode.name.value === valueDefinitionNode.name.value);
440 valueDefinitionNode.directives = originalValueDefinitionNode === null || originalValueDefinitionNode === void 0 ? void 0 : originalValueDefinitionNode.directives;
441 }
442 }
443 }
444 type.astNode = fixedAstNode;
445 return type;
446}
447function getSchemaDefinition(schema) {
448 if (!Object.getOwnPropertyDescriptor(schema, 'astNode').get && schema.astNode) {
449 return print(schema.astNode);
450 }
451 else {
452 return createSchemaDefinition({
453 query: schema.getQueryType(),
454 mutation: schema.getMutationType(),
455 subscription: schema.getSubscriptionType(),
456 });
457 }
458}
459
460async function validateGraphQlDocuments(schema, documentFiles, effectiveRules) {
461 effectiveRules = effectiveRules || createDefaultRules();
462 const allFragments = [];
463 documentFiles.forEach(documentFile => {
464 if (documentFile.document) {
465 for (const definitionNode of documentFile.document.definitions) {
466 if (definitionNode.kind === Kind.FRAGMENT_DEFINITION) {
467 allFragments.push(definitionNode);
468 }
469 }
470 }
471 });
472 const allErrors = [];
473 await Promise.all(documentFiles.map(async (documentFile) => {
474 const documentToValidate = {
475 kind: Kind.DOCUMENT,
476 definitions: [...allFragments, ...documentFile.document.definitions].filter((definition, index, list) => {
477 if (definition.kind === Kind.FRAGMENT_DEFINITION) {
478 const firstIndex = list.findIndex(def => def.kind === Kind.FRAGMENT_DEFINITION && def.name.value === definition.name.value);
479 const isDuplicated = firstIndex !== index;
480 if (isDuplicated) {
481 return false;
482 }
483 }
484 return true;
485 }),
486 };
487 const errors = validate(schema, documentToValidate, effectiveRules);
488 if (errors.length > 0) {
489 allErrors.push({
490 filePath: documentFile.location,
491 errors,
492 });
493 }
494 }));
495 return allErrors;
496}
497function checkValidationErrors(loadDocumentErrors) {
498 if (loadDocumentErrors.length > 0) {
499 const errors = [];
500 for (const loadDocumentError of loadDocumentErrors) {
501 for (const graphQLError of loadDocumentError.errors) {
502 const error = new Error();
503 error.name = 'GraphQLDocumentError';
504 error.message = `${error.name}: ${graphQLError.message}`;
505 error.stack = error.message;
506 graphQLError.locations.forEach(location => (error.stack += `\n at ${loadDocumentError.filePath}:${location.line}:${location.column}`));
507 errors.push(error);
508 }
509 }
510 throw new AggregateError(errors);
511 }
512}
513function createDefaultRules() {
514 const ignored = ['NoUnusedFragmentsRule', 'NoUnusedVariablesRule', 'KnownDirectivesRule'];
515 // GraphQL v14 has no Rule suffix in function names
516 // Adding `*Rule` makes validation backwards compatible
517 ignored.forEach(rule => {
518 ignored.push(rule.replace(/Rule$/, ''));
519 });
520 return specifiedRules.filter((f) => !ignored.includes(f.name));
521}
522
523function buildFixedSchema(schema, options) {
524 return buildSchema(printSchemaWithDirectives(schema, options), {
525 noLocation: true,
526 ...(options || {}),
527 });
528}
529function fixSchemaAst(schema, options) {
530 let schemaWithValidAst;
531 if (!schema.astNode) {
532 Object.defineProperty(schema, 'astNode', {
533 get() {
534 if (!schemaWithValidAst) {
535 schemaWithValidAst = buildFixedSchema(schema, options);
536 }
537 return schemaWithValidAst.astNode;
538 },
539 });
540 }
541 if (!schema.extensionASTNodes) {
542 Object.defineProperty(schema, 'extensionASTNodes', {
543 get() {
544 if (!schemaWithValidAst) {
545 schemaWithValidAst = buildFixedSchema(schema, options);
546 }
547 return schemaWithValidAst.extensionASTNodes;
548 },
549 });
550 }
551 return schema;
552}
553
554function stripBOM(content) {
555 content = content.toString();
556 // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
557 // because the buffer-to-string conversion in `fs.readFileSync()`
558 // translates it to FEFF, the UTF-16 BOM.
559 if (content.charCodeAt(0) === 0xfeff) {
560 content = content.slice(1);
561 }
562 return content;
563}
564function parseBOM(content) {
565 return JSON.parse(stripBOM(content));
566}
567function parseGraphQLJSON(location, jsonContent, options) {
568 let parsedJson = parseBOM(jsonContent);
569 if (parsedJson.data) {
570 parsedJson = parsedJson.data;
571 }
572 if (parsedJson.kind === 'Document') {
573 const document = parsedJson;
574 return {
575 location,
576 document,
577 };
578 }
579 else if (parsedJson.__schema) {
580 const schema = buildClientSchema(parsedJson, options);
581 const rawSDL = printSchemaWithDirectives(schema, options);
582 return {
583 location,
584 document: parse(rawSDL, options),
585 rawSDL,
586 schema,
587 };
588 }
589 throw new Error(`Not valid JSON content`);
590}
591
592function parseGraphQLSDL(location, rawSDL, options) {
593 let document;
594 try {
595 document = parse(new Source(rawSDL, location), options);
596 }
597 catch (e) {
598 if (e.message.includes('EOF')) {
599 document = {
600 kind: Kind.DOCUMENT,
601 definitions: [],
602 };
603 }
604 else {
605 throw e;
606 }
607 }
608 return {
609 location,
610 document,
611 rawSDL,
612 };
613}
614
615/**
616 * Get all GraphQL types from schema without:
617 *
618 * - Query, Mutation, Subscription objects
619 * - Internal scalars added by parser
620 *
621 * @param schema
622 */
623function getUserTypesFromSchema(schema) {
624 const allTypesMap = schema.getTypeMap();
625 // tslint:disable-next-line: no-unnecessary-local-variable
626 const modelTypes = Object.values(allTypesMap).filter((graphqlType) => {
627 if (isObjectType(graphqlType)) {
628 // Filter out private types
629 if (graphqlType.name.startsWith('__')) {
630 return false;
631 }
632 if (schema.getMutationType() && graphqlType.name === schema.getMutationType().name) {
633 return false;
634 }
635 if (schema.getQueryType() && graphqlType.name === schema.getQueryType().name) {
636 return false;
637 }
638 if (schema.getSubscriptionType() && graphqlType.name === schema.getSubscriptionType().name) {
639 return false;
640 }
641 return true;
642 }
643 return false;
644 });
645 return modelTypes;
646}
647
648let operationVariables = [];
649let fieldTypeMap = new Map();
650function addOperationVariable(variable) {
651 operationVariables.push(variable);
652}
653function resetOperationVariables() {
654 operationVariables = [];
655}
656function resetFieldMap() {
657 fieldTypeMap = new Map();
658}
659function buildOperationName(name) {
660 return camelCase(name);
661}
662function buildOperationNodeForField({ schema, kind, field, models, ignore, depthLimit, circularReferenceDepth, argNames, selectedFields = true, }) {
663 resetOperationVariables();
664 resetFieldMap();
665 const operationNode = buildOperationAndCollectVariables({
666 schema,
667 fieldName: field,
668 kind,
669 models: models || [],
670 ignore: ignore || [],
671 depthLimit: depthLimit || Infinity,
672 circularReferenceDepth: circularReferenceDepth || 1,
673 argNames,
674 selectedFields,
675 });
676 // attach variables
677 operationNode.variableDefinitions = [...operationVariables];
678 resetOperationVariables();
679 resetFieldMap();
680 return operationNode;
681}
682function buildOperationAndCollectVariables({ schema, fieldName, kind, models, ignore, depthLimit, circularReferenceDepth, argNames, selectedFields, }) {
683 const typeMap = {
684 query: schema.getQueryType(),
685 mutation: schema.getMutationType(),
686 subscription: schema.getSubscriptionType(),
687 };
688 const type = typeMap[kind];
689 const field = type.getFields()[fieldName];
690 const operationName = buildOperationName(`${fieldName}_${kind}`);
691 if (field.args) {
692 field.args.forEach(arg => {
693 const argName = arg.name;
694 if (!argNames || argNames.includes(argName)) {
695 addOperationVariable(resolveVariable(arg, argName));
696 }
697 });
698 }
699 return {
700 kind: Kind.OPERATION_DEFINITION,
701 operation: kind,
702 name: {
703 kind: 'Name',
704 value: operationName,
705 },
706 variableDefinitions: [],
707 selectionSet: {
708 kind: Kind.SELECTION_SET,
709 selections: [
710 resolveField({
711 type,
712 field,
713 models,
714 firstCall: true,
715 path: [],
716 ancestors: [],
717 ignore,
718 depthLimit,
719 circularReferenceDepth,
720 schema,
721 depth: 0,
722 argNames,
723 selectedFields,
724 }),
725 ],
726 },
727 };
728}
729function resolveSelectionSet({ parent, type, models, firstCall, path, ancestors, ignore, depthLimit, circularReferenceDepth, schema, depth, argNames, selectedFields, }) {
730 if (typeof selectedFields === 'boolean' && depth > depthLimit) {
731 return;
732 }
733 if (isUnionType(type)) {
734 const types = type.getTypes();
735 return {
736 kind: Kind.SELECTION_SET,
737 selections: types
738 .filter(t => !hasCircularRef([...ancestors, t], {
739 depth: circularReferenceDepth,
740 }))
741 .map(t => {
742 return {
743 kind: Kind.INLINE_FRAGMENT,
744 typeCondition: {
745 kind: Kind.NAMED_TYPE,
746 name: {
747 kind: Kind.NAME,
748 value: t.name,
749 },
750 },
751 selectionSet: resolveSelectionSet({
752 parent: type,
753 type: t,
754 models,
755 path,
756 ancestors,
757 ignore,
758 depthLimit,
759 circularReferenceDepth,
760 schema,
761 depth,
762 argNames,
763 selectedFields,
764 }),
765 };
766 })
767 .filter(fragmentNode => { var _a, _b; return ((_b = (_a = fragmentNode === null || fragmentNode === void 0 ? void 0 : fragmentNode.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) === null || _b === void 0 ? void 0 : _b.length) > 0; }),
768 };
769 }
770 if (isInterfaceType(type)) {
771 const types = Object.values(schema.getTypeMap()).filter((t) => isObjectType(t) && t.getInterfaces().includes(type));
772 return {
773 kind: Kind.SELECTION_SET,
774 selections: types
775 .filter(t => !hasCircularRef([...ancestors, t], {
776 depth: circularReferenceDepth,
777 }))
778 .map(t => {
779 return {
780 kind: Kind.INLINE_FRAGMENT,
781 typeCondition: {
782 kind: Kind.NAMED_TYPE,
783 name: {
784 kind: Kind.NAME,
785 value: t.name,
786 },
787 },
788 selectionSet: resolveSelectionSet({
789 parent: type,
790 type: t,
791 models,
792 path,
793 ancestors,
794 ignore,
795 depthLimit,
796 circularReferenceDepth,
797 schema,
798 depth,
799 argNames,
800 selectedFields,
801 }),
802 };
803 })
804 .filter(fragmentNode => { var _a, _b; return ((_b = (_a = fragmentNode === null || fragmentNode === void 0 ? void 0 : fragmentNode.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) === null || _b === void 0 ? void 0 : _b.length) > 0; }),
805 };
806 }
807 if (isObjectType(type)) {
808 const isIgnored = ignore.includes(type.name) || ignore.includes(`${parent.name}.${path[path.length - 1]}`);
809 const isModel = models.includes(type.name);
810 if (!firstCall && isModel && !isIgnored) {
811 return {
812 kind: Kind.SELECTION_SET,
813 selections: [
814 {
815 kind: Kind.FIELD,
816 name: {
817 kind: Kind.NAME,
818 value: 'id',
819 },
820 },
821 ],
822 };
823 }
824 const fields = type.getFields();
825 return {
826 kind: Kind.SELECTION_SET,
827 selections: Object.keys(fields)
828 .filter(fieldName => {
829 return !hasCircularRef([...ancestors, getNamedType(fields[fieldName].type)], {
830 depth: circularReferenceDepth,
831 });
832 })
833 .map(fieldName => {
834 const selectedSubFields = typeof selectedFields === 'object' ? selectedFields[fieldName] : true;
835 if (selectedSubFields) {
836 return resolveField({
837 type: type,
838 field: fields[fieldName],
839 models,
840 path: [...path, fieldName],
841 ancestors,
842 ignore,
843 depthLimit,
844 circularReferenceDepth,
845 schema,
846 depth,
847 argNames,
848 selectedFields: selectedSubFields,
849 });
850 }
851 })
852 .filter(f => {
853 var _a, _b;
854 if (f) {
855 if ('selectionSet' in f) {
856 return (_b = (_a = f.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) === null || _b === void 0 ? void 0 : _b.length;
857 }
858 else {
859 return true;
860 }
861 }
862 return false;
863 }),
864 };
865 }
866}
867function resolveVariable(arg, name) {
868 function resolveVariableType(type) {
869 if (isListType(type)) {
870 return {
871 kind: Kind.LIST_TYPE,
872 type: resolveVariableType(type.ofType),
873 };
874 }
875 if (isNonNullType(type)) {
876 return {
877 kind: Kind.NON_NULL_TYPE,
878 type: resolveVariableType(type.ofType),
879 };
880 }
881 return {
882 kind: Kind.NAMED_TYPE,
883 name: {
884 kind: Kind.NAME,
885 value: type.name,
886 },
887 };
888 }
889 return {
890 kind: Kind.VARIABLE_DEFINITION,
891 variable: {
892 kind: Kind.VARIABLE,
893 name: {
894 kind: Kind.NAME,
895 value: name || arg.name,
896 },
897 },
898 type: resolveVariableType(arg.type),
899 };
900}
901function getArgumentName(name, path) {
902 return camelCase([...path, name].join('_'));
903}
904function resolveField({ type, field, models, firstCall, path, ancestors, ignore, depthLimit, circularReferenceDepth, schema, depth, argNames, selectedFields, }) {
905 const namedType = getNamedType(field.type);
906 let args = [];
907 let removeField = false;
908 if (field.args && field.args.length) {
909 args = field.args
910 .map(arg => {
911 const argumentName = getArgumentName(arg.name, path);
912 if (argNames && !argNames.includes(argumentName)) {
913 if (isNonNullType(arg.type)) {
914 removeField = true;
915 }
916 return null;
917 }
918 if (!firstCall) {
919 addOperationVariable(resolveVariable(arg, argumentName));
920 }
921 return {
922 kind: Kind.ARGUMENT,
923 name: {
924 kind: Kind.NAME,
925 value: arg.name,
926 },
927 value: {
928 kind: Kind.VARIABLE,
929 name: {
930 kind: Kind.NAME,
931 value: getArgumentName(arg.name, path),
932 },
933 },
934 };
935 })
936 .filter(Boolean);
937 }
938 if (removeField) {
939 return null;
940 }
941 let fieldName = field.name;
942 if (fieldTypeMap.has(fieldName) && fieldTypeMap.get(fieldName) !== field.type.toString()) {
943 fieldName += field.type.toString().replace('!', 'NonNull');
944 }
945 fieldTypeMap.set(fieldName, field.type.toString());
946 if (!isScalarType(namedType) && !isEnumType(namedType)) {
947 return {
948 kind: Kind.FIELD,
949 name: {
950 kind: Kind.NAME,
951 value: field.name,
952 },
953 ...(fieldName !== field.name && { alias: { kind: Kind.NAME, value: fieldName } }),
954 selectionSet: resolveSelectionSet({
955 parent: type,
956 type: namedType,
957 models,
958 firstCall,
959 path: [...path, field.name],
960 ancestors: [...ancestors, type],
961 ignore,
962 depthLimit,
963 circularReferenceDepth,
964 schema,
965 depth: depth + 1,
966 argNames,
967 selectedFields,
968 }) || undefined,
969 arguments: args,
970 };
971 }
972 return {
973 kind: Kind.FIELD,
974 name: {
975 kind: Kind.NAME,
976 value: field.name,
977 },
978 ...(fieldName !== field.name && { alias: { kind: Kind.NAME, value: fieldName } }),
979 arguments: args,
980 };
981}
982function hasCircularRef(types, config = {
983 depth: 1,
984}) {
985 const type = types[types.length - 1];
986 if (isScalarType(type)) {
987 return false;
988 }
989 const size = types.filter(t => t.name === type.name).length;
990 return size > config.depth;
991}
992
993var VisitSchemaKind;
994(function (VisitSchemaKind) {
995 VisitSchemaKind["TYPE"] = "VisitSchemaKind.TYPE";
996 VisitSchemaKind["SCALAR_TYPE"] = "VisitSchemaKind.SCALAR_TYPE";
997 VisitSchemaKind["ENUM_TYPE"] = "VisitSchemaKind.ENUM_TYPE";
998 VisitSchemaKind["COMPOSITE_TYPE"] = "VisitSchemaKind.COMPOSITE_TYPE";
999 VisitSchemaKind["OBJECT_TYPE"] = "VisitSchemaKind.OBJECT_TYPE";
1000 VisitSchemaKind["INPUT_OBJECT_TYPE"] = "VisitSchemaKind.INPUT_OBJECT_TYPE";
1001 VisitSchemaKind["ABSTRACT_TYPE"] = "VisitSchemaKind.ABSTRACT_TYPE";
1002 VisitSchemaKind["UNION_TYPE"] = "VisitSchemaKind.UNION_TYPE";
1003 VisitSchemaKind["INTERFACE_TYPE"] = "VisitSchemaKind.INTERFACE_TYPE";
1004 VisitSchemaKind["ROOT_OBJECT"] = "VisitSchemaKind.ROOT_OBJECT";
1005 VisitSchemaKind["QUERY"] = "VisitSchemaKind.QUERY";
1006 VisitSchemaKind["MUTATION"] = "VisitSchemaKind.MUTATION";
1007 VisitSchemaKind["SUBSCRIPTION"] = "VisitSchemaKind.SUBSCRIPTION";
1008})(VisitSchemaKind || (VisitSchemaKind = {}));
1009var MapperKind;
1010(function (MapperKind) {
1011 MapperKind["TYPE"] = "MapperKind.TYPE";
1012 MapperKind["SCALAR_TYPE"] = "MapperKind.SCALAR_TYPE";
1013 MapperKind["ENUM_TYPE"] = "MapperKind.ENUM_TYPE";
1014 MapperKind["COMPOSITE_TYPE"] = "MapperKind.COMPOSITE_TYPE";
1015 MapperKind["OBJECT_TYPE"] = "MapperKind.OBJECT_TYPE";
1016 MapperKind["INPUT_OBJECT_TYPE"] = "MapperKind.INPUT_OBJECT_TYPE";
1017 MapperKind["ABSTRACT_TYPE"] = "MapperKind.ABSTRACT_TYPE";
1018 MapperKind["UNION_TYPE"] = "MapperKind.UNION_TYPE";
1019 MapperKind["INTERFACE_TYPE"] = "MapperKind.INTERFACE_TYPE";
1020 MapperKind["ROOT_OBJECT"] = "MapperKind.ROOT_OBJECT";
1021 MapperKind["QUERY"] = "MapperKind.QUERY";
1022 MapperKind["MUTATION"] = "MapperKind.MUTATION";
1023 MapperKind["SUBSCRIPTION"] = "MapperKind.SUBSCRIPTION";
1024 MapperKind["DIRECTIVE"] = "MapperKind.DIRECTIVE";
1025 MapperKind["FIELD"] = "MapperKind.FIELD";
1026 MapperKind["COMPOSITE_FIELD"] = "MapperKind.COMPOSITE_FIELD";
1027 MapperKind["OBJECT_FIELD"] = "MapperKind.OBJECT_FIELD";
1028 MapperKind["ROOT_FIELD"] = "MapperKind.ROOT_FIELD";
1029 MapperKind["QUERY_ROOT_FIELD"] = "MapperKind.QUERY_ROOT_FIELD";
1030 MapperKind["MUTATION_ROOT_FIELD"] = "MapperKind.MUTATION_ROOT_FIELD";
1031 MapperKind["SUBSCRIPTION_ROOT_FIELD"] = "MapperKind.SUBSCRIPTION_ROOT_FIELD";
1032 MapperKind["INTERFACE_FIELD"] = "MapperKind.INTERFACE_FIELD";
1033 MapperKind["INPUT_OBJECT_FIELD"] = "MapperKind.INPUT_OBJECT_FIELD";
1034 MapperKind["ARGUMENT"] = "MapperKind.ARGUMENT";
1035 MapperKind["ENUM_VALUE"] = "MapperKind.ENUM_VALUE";
1036})(MapperKind || (MapperKind = {}));
1037
1038function createNamedStub(name, type) {
1039 let constructor;
1040 if (type === 'object') {
1041 constructor = GraphQLObjectType;
1042 }
1043 else if (type === 'interface') {
1044 constructor = GraphQLInterfaceType;
1045 }
1046 else {
1047 constructor = GraphQLInputObjectType;
1048 }
1049 return new constructor({
1050 name,
1051 fields: {
1052 __fake: {
1053 type: GraphQLString,
1054 },
1055 },
1056 });
1057}
1058function createStub(node, type) {
1059 switch (node.kind) {
1060 case Kind.LIST_TYPE:
1061 return new GraphQLList(createStub(node.type, type));
1062 case Kind.NON_NULL_TYPE:
1063 return new GraphQLNonNull(createStub(node.type, type));
1064 default:
1065 if (type === 'output') {
1066 return createNamedStub(node.name.value, 'object');
1067 }
1068 return createNamedStub(node.name.value, 'input');
1069 }
1070}
1071function isNamedStub(type) {
1072 if (isObjectType(type) || isInterfaceType(type) || isInputObjectType(type)) {
1073 const fields = type.getFields();
1074 const fieldNames = Object.keys(fields);
1075 return fieldNames.length === 1 && fields[fieldNames[0]].name === '__fake';
1076 }
1077 return false;
1078}
1079function getBuiltInForStub(type) {
1080 switch (type.name) {
1081 case GraphQLInt.name:
1082 return GraphQLInt;
1083 case GraphQLFloat.name:
1084 return GraphQLFloat;
1085 case GraphQLString.name:
1086 return GraphQLString;
1087 case GraphQLBoolean.name:
1088 return GraphQLBoolean;
1089 case GraphQLID.name:
1090 return GraphQLID;
1091 default:
1092 return type;
1093 }
1094}
1095
1096function rewireTypes(originalTypeMap, directives, options = {
1097 skipPruning: false,
1098}) {
1099 const newTypeMap = Object.create(null);
1100 Object.keys(originalTypeMap).forEach(typeName => {
1101 const namedType = originalTypeMap[typeName];
1102 if (namedType == null || typeName.startsWith('__')) {
1103 return;
1104 }
1105 const newName = namedType.name;
1106 if (newName.startsWith('__')) {
1107 return;
1108 }
1109 if (newTypeMap[newName] != null) {
1110 throw new Error(`Duplicate schema type name ${newName}`);
1111 }
1112 newTypeMap[newName] = namedType;
1113 });
1114 Object.keys(newTypeMap).forEach(typeName => {
1115 newTypeMap[typeName] = rewireNamedType(newTypeMap[typeName]);
1116 });
1117 const newDirectives = directives.map(directive => rewireDirective(directive));
1118 // TODO:
1119 // consider removing the default level of pruning in v7,
1120 // see comments below on the pruneTypes function.
1121 return options.skipPruning
1122 ? {
1123 typeMap: newTypeMap,
1124 directives: newDirectives,
1125 }
1126 : pruneTypes(newTypeMap, newDirectives);
1127 function rewireDirective(directive) {
1128 if (isSpecifiedDirective(directive)) {
1129 return directive;
1130 }
1131 const directiveConfig = directive.toConfig();
1132 directiveConfig.args = rewireArgs(directiveConfig.args);
1133 return new GraphQLDirective(directiveConfig);
1134 }
1135 function rewireArgs(args) {
1136 const rewiredArgs = {};
1137 Object.keys(args).forEach(argName => {
1138 const arg = args[argName];
1139 const rewiredArgType = rewireType(arg.type);
1140 if (rewiredArgType != null) {
1141 arg.type = rewiredArgType;
1142 rewiredArgs[argName] = arg;
1143 }
1144 });
1145 return rewiredArgs;
1146 }
1147 function rewireNamedType(type) {
1148 if (isObjectType(type)) {
1149 const config = type.toConfig();
1150 const newConfig = {
1151 ...config,
1152 fields: () => rewireFields(config.fields),
1153 interfaces: () => rewireNamedTypes(config.interfaces),
1154 };
1155 return new GraphQLObjectType(newConfig);
1156 }
1157 else if (isInterfaceType(type)) {
1158 const config = type.toConfig();
1159 const newConfig = {
1160 ...config,
1161 fields: () => rewireFields(config.fields),
1162 };
1163 if ('interfaces' in newConfig) {
1164 newConfig.interfaces = () => rewireNamedTypes(config.interfaces);
1165 }
1166 return new GraphQLInterfaceType(newConfig);
1167 }
1168 else if (isUnionType(type)) {
1169 const config = type.toConfig();
1170 const newConfig = {
1171 ...config,
1172 types: () => rewireNamedTypes(config.types),
1173 };
1174 return new GraphQLUnionType(newConfig);
1175 }
1176 else if (isInputObjectType(type)) {
1177 const config = type.toConfig();
1178 const newConfig = {
1179 ...config,
1180 fields: () => rewireInputFields(config.fields),
1181 };
1182 return new GraphQLInputObjectType(newConfig);
1183 }
1184 else if (isEnumType(type)) {
1185 const enumConfig = type.toConfig();
1186 return new GraphQLEnumType(enumConfig);
1187 }
1188 else if (isScalarType(type)) {
1189 if (isSpecifiedScalarType(type)) {
1190 return type;
1191 }
1192 const scalarConfig = type.toConfig();
1193 return new GraphQLScalarType(scalarConfig);
1194 }
1195 throw new Error(`Unexpected schema type: ${type}`);
1196 }
1197 function rewireFields(fields) {
1198 const rewiredFields = {};
1199 Object.keys(fields).forEach(fieldName => {
1200 const field = fields[fieldName];
1201 const rewiredFieldType = rewireType(field.type);
1202 if (rewiredFieldType != null) {
1203 field.type = rewiredFieldType;
1204 field.args = rewireArgs(field.args);
1205 rewiredFields[fieldName] = field;
1206 }
1207 });
1208 return rewiredFields;
1209 }
1210 function rewireInputFields(fields) {
1211 const rewiredFields = {};
1212 Object.keys(fields).forEach(fieldName => {
1213 const field = fields[fieldName];
1214 const rewiredFieldType = rewireType(field.type);
1215 if (rewiredFieldType != null) {
1216 field.type = rewiredFieldType;
1217 rewiredFields[fieldName] = field;
1218 }
1219 });
1220 return rewiredFields;
1221 }
1222 function rewireNamedTypes(namedTypes) {
1223 const rewiredTypes = [];
1224 namedTypes.forEach(namedType => {
1225 const rewiredType = rewireType(namedType);
1226 if (rewiredType != null) {
1227 rewiredTypes.push(rewiredType);
1228 }
1229 });
1230 return rewiredTypes;
1231 }
1232 function rewireType(type) {
1233 if (isListType(type)) {
1234 const rewiredType = rewireType(type.ofType);
1235 return rewiredType != null ? new GraphQLList(rewiredType) : null;
1236 }
1237 else if (isNonNullType(type)) {
1238 const rewiredType = rewireType(type.ofType);
1239 return rewiredType != null ? new GraphQLNonNull(rewiredType) : null;
1240 }
1241 else if (isNamedType(type)) {
1242 let rewiredType = originalTypeMap[type.name];
1243 if (rewiredType === undefined) {
1244 rewiredType = isNamedStub(type) ? getBuiltInForStub(type) : type;
1245 newTypeMap[rewiredType.name] = rewiredType;
1246 }
1247 return rewiredType != null ? newTypeMap[rewiredType.name] : null;
1248 }
1249 return null;
1250 }
1251}
1252// TODO:
1253// consider removing the default level of pruning in v7
1254//
1255// Pruning during mapSchema limits the ability to create an unpruned schema, which may be of use
1256// to some library users. pruning is now recommended via the dedicated pruneSchema function
1257// which does not force pruning on library users and gives granular control in terms of pruning
1258// types.
1259function pruneTypes(typeMap, directives) {
1260 const newTypeMap = {};
1261 const implementedInterfaces = {};
1262 Object.keys(typeMap).forEach(typeName => {
1263 const namedType = typeMap[typeName];
1264 if ('getInterfaces' in namedType) {
1265 namedType.getInterfaces().forEach(iface => {
1266 implementedInterfaces[iface.name] = true;
1267 });
1268 }
1269 });
1270 let prunedTypeMap = false;
1271 const typeNames = Object.keys(typeMap);
1272 for (let i = 0; i < typeNames.length; i++) {
1273 const typeName = typeNames[i];
1274 const type = typeMap[typeName];
1275 if (isObjectType(type) || isInputObjectType(type)) {
1276 // prune types with no fields
1277 if (Object.keys(type.getFields()).length) {
1278 newTypeMap[typeName] = type;
1279 }
1280 else {
1281 prunedTypeMap = true;
1282 }
1283 }
1284 else if (isUnionType(type)) {
1285 // prune unions without underlying types
1286 if (type.getTypes().length) {
1287 newTypeMap[typeName] = type;
1288 }
1289 else {
1290 prunedTypeMap = true;
1291 }
1292 }
1293 else if (isInterfaceType(type)) {
1294 // prune interfaces without fields or without implementations
1295 if (Object.keys(type.getFields()).length && implementedInterfaces[type.name]) {
1296 newTypeMap[typeName] = type;
1297 }
1298 else {
1299 prunedTypeMap = true;
1300 }
1301 }
1302 else {
1303 newTypeMap[typeName] = type;
1304 }
1305 }
1306 // every prune requires another round of healing
1307 return prunedTypeMap ? rewireTypes(newTypeMap, directives) : { typeMap, directives };
1308}
1309
1310function transformInputValue(type, value, transformer) {
1311 if (value == null) {
1312 return value;
1313 }
1314 const nullableType = getNullableType(type);
1315 if (isLeafType(nullableType)) {
1316 return transformer(nullableType, value);
1317 }
1318 else if (isListType(nullableType)) {
1319 return value.map((listMember) => transformInputValue(nullableType.ofType, listMember, transformer));
1320 }
1321 else if (isInputObjectType(nullableType)) {
1322 const fields = nullableType.getFields();
1323 const newValue = {};
1324 Object.keys(value).forEach(key => {
1325 newValue[key] = transformInputValue(fields[key].type, value[key], transformer);
1326 });
1327 return newValue;
1328 }
1329 // unreachable, no other possible return value
1330}
1331function serializeInputValue(type, value) {
1332 return transformInputValue(type, value, (t, v) => t.serialize(v));
1333}
1334function parseInputValue(type, value) {
1335 return transformInputValue(type, value, (t, v) => t.parseValue(v));
1336}
1337function parseInputValueLiteral(type, value) {
1338 return transformInputValue(type, value, (t, v) => t.parseLiteral(v, {}));
1339}
1340
1341function mapSchema(schema, schemaMapper = {}) {
1342 const originalTypeMap = schema.getTypeMap();
1343 let newTypeMap = mapDefaultValues(originalTypeMap, schema, serializeInputValue);
1344 newTypeMap = mapTypes(newTypeMap, schema, schemaMapper, type => isLeafType(type));
1345 newTypeMap = mapEnumValues(newTypeMap, schema, schemaMapper);
1346 newTypeMap = mapDefaultValues(newTypeMap, schema, parseInputValue);
1347 newTypeMap = mapTypes(newTypeMap, schema, schemaMapper, type => !isLeafType(type));
1348 newTypeMap = mapFields(newTypeMap, schema, schemaMapper);
1349 newTypeMap = mapArguments(newTypeMap, schema, schemaMapper);
1350 const originalDirectives = schema.getDirectives();
1351 const newDirectives = mapDirectives(originalDirectives, schema, schemaMapper);
1352 const queryType = schema.getQueryType();
1353 const mutationType = schema.getMutationType();
1354 const subscriptionType = schema.getSubscriptionType();
1355 const newQueryTypeName = queryType != null ? (newTypeMap[queryType.name] != null ? newTypeMap[queryType.name].name : undefined) : undefined;
1356 const newMutationTypeName = mutationType != null
1357 ? newTypeMap[mutationType.name] != null
1358 ? newTypeMap[mutationType.name].name
1359 : undefined
1360 : undefined;
1361 const newSubscriptionTypeName = subscriptionType != null
1362 ? newTypeMap[subscriptionType.name] != null
1363 ? newTypeMap[subscriptionType.name].name
1364 : undefined
1365 : undefined;
1366 const { typeMap, directives } = rewireTypes(newTypeMap, newDirectives);
1367 return new GraphQLSchema({
1368 ...schema.toConfig(),
1369 query: newQueryTypeName ? typeMap[newQueryTypeName] : undefined,
1370 mutation: newMutationTypeName ? typeMap[newMutationTypeName] : undefined,
1371 subscription: newSubscriptionTypeName != null ? typeMap[newSubscriptionTypeName] : undefined,
1372 types: Object.keys(typeMap).map(typeName => typeMap[typeName]),
1373 directives,
1374 });
1375}
1376function mapTypes(originalTypeMap, schema, schemaMapper, testFn = () => true) {
1377 const newTypeMap = {};
1378 Object.keys(originalTypeMap).forEach(typeName => {
1379 if (!typeName.startsWith('__')) {
1380 const originalType = originalTypeMap[typeName];
1381 if (originalType == null || !testFn(originalType)) {
1382 newTypeMap[typeName] = originalType;
1383 return;
1384 }
1385 const typeMapper = getTypeMapper(schema, schemaMapper, typeName);
1386 if (typeMapper == null) {
1387 newTypeMap[typeName] = originalType;
1388 return;
1389 }
1390 const maybeNewType = typeMapper(originalType, schema);
1391 if (maybeNewType === undefined) {
1392 newTypeMap[typeName] = originalType;
1393 return;
1394 }
1395 newTypeMap[typeName] = maybeNewType;
1396 }
1397 });
1398 return newTypeMap;
1399}
1400function mapEnumValues(originalTypeMap, schema, schemaMapper) {
1401 const enumValueMapper = getEnumValueMapper(schemaMapper);
1402 if (!enumValueMapper) {
1403 return originalTypeMap;
1404 }
1405 return mapTypes(originalTypeMap, schema, {
1406 [MapperKind.ENUM_TYPE]: type => {
1407 const config = type.toConfig();
1408 const originalEnumValueConfigMap = config.values;
1409 const newEnumValueConfigMap = {};
1410 Object.keys(originalEnumValueConfigMap).forEach(externalValue => {
1411 const originalEnumValueConfig = originalEnumValueConfigMap[externalValue];
1412 const mappedEnumValue = enumValueMapper(originalEnumValueConfig, type.name, schema, externalValue);
1413 if (mappedEnumValue === undefined) {
1414 newEnumValueConfigMap[externalValue] = originalEnumValueConfig;
1415 }
1416 else if (Array.isArray(mappedEnumValue)) {
1417 const [newExternalValue, newEnumValueConfig] = mappedEnumValue;
1418 newEnumValueConfigMap[newExternalValue] =
1419 newEnumValueConfig === undefined ? originalEnumValueConfig : newEnumValueConfig;
1420 }
1421 else if (mappedEnumValue !== null) {
1422 newEnumValueConfigMap[externalValue] = mappedEnumValue;
1423 }
1424 });
1425 return correctASTNodes(new GraphQLEnumType({
1426 ...config,
1427 values: newEnumValueConfigMap,
1428 }));
1429 },
1430 }, type => isEnumType(type));
1431}
1432function mapDefaultValues(originalTypeMap, schema, fn) {
1433 const newTypeMap = mapArguments(originalTypeMap, schema, {
1434 [MapperKind.ARGUMENT]: argumentConfig => {
1435 if (argumentConfig.defaultValue === undefined) {
1436 return argumentConfig;
1437 }
1438 const maybeNewType = getNewType(originalTypeMap, argumentConfig.type);
1439 if (maybeNewType != null) {
1440 return {
1441 ...argumentConfig,
1442 defaultValue: fn(maybeNewType, argumentConfig.defaultValue),
1443 };
1444 }
1445 },
1446 });
1447 return mapFields(newTypeMap, schema, {
1448 [MapperKind.INPUT_OBJECT_FIELD]: inputFieldConfig => {
1449 if (inputFieldConfig.defaultValue === undefined) {
1450 return inputFieldConfig;
1451 }
1452 const maybeNewType = getNewType(newTypeMap, inputFieldConfig.type);
1453 if (maybeNewType != null) {
1454 return {
1455 ...inputFieldConfig,
1456 defaultValue: fn(maybeNewType, inputFieldConfig.defaultValue),
1457 };
1458 }
1459 },
1460 });
1461}
1462function getNewType(newTypeMap, type) {
1463 if (isListType(type)) {
1464 const newType = getNewType(newTypeMap, type.ofType);
1465 return newType != null ? new GraphQLList(newType) : null;
1466 }
1467 else if (isNonNullType(type)) {
1468 const newType = getNewType(newTypeMap, type.ofType);
1469 return newType != null ? new GraphQLNonNull(newType) : null;
1470 }
1471 else if (isNamedType(type)) {
1472 const newType = newTypeMap[type.name];
1473 return newType != null ? newType : null;
1474 }
1475 return null;
1476}
1477function mapFields(originalTypeMap, schema, schemaMapper) {
1478 const newTypeMap = {};
1479 Object.keys(originalTypeMap).forEach(typeName => {
1480 if (!typeName.startsWith('__')) {
1481 const originalType = originalTypeMap[typeName];
1482 if (!isObjectType(originalType) && !isInterfaceType(originalType) && !isInputObjectType(originalType)) {
1483 newTypeMap[typeName] = originalType;
1484 return;
1485 }
1486 const fieldMapper = getFieldMapper(schema, schemaMapper, typeName);
1487 if (fieldMapper == null) {
1488 newTypeMap[typeName] = originalType;
1489 return;
1490 }
1491 const config = originalType.toConfig();
1492 const originalFieldConfigMap = config.fields;
1493 const newFieldConfigMap = {};
1494 Object.keys(originalFieldConfigMap).forEach(fieldName => {
1495 const originalFieldConfig = originalFieldConfigMap[fieldName];
1496 const mappedField = fieldMapper(originalFieldConfig, fieldName, typeName, schema);
1497 if (mappedField === undefined) {
1498 newFieldConfigMap[fieldName] = originalFieldConfig;
1499 }
1500 else if (Array.isArray(mappedField)) {
1501 const [newFieldName, newFieldConfig] = mappedField;
1502 if (newFieldConfig.astNode != null) {
1503 newFieldConfig.astNode = {
1504 ...newFieldConfig.astNode,
1505 name: {
1506 ...newFieldConfig.astNode.name,
1507 value: newFieldName,
1508 },
1509 };
1510 }
1511 newFieldConfigMap[newFieldName] = newFieldConfig === undefined ? originalFieldConfig : newFieldConfig;
1512 }
1513 else if (mappedField !== null) {
1514 newFieldConfigMap[fieldName] = mappedField;
1515 }
1516 });
1517 if (isObjectType(originalType)) {
1518 newTypeMap[typeName] = correctASTNodes(new GraphQLObjectType({
1519 ...config,
1520 fields: newFieldConfigMap,
1521 }));
1522 }
1523 else if (isInterfaceType(originalType)) {
1524 newTypeMap[typeName] = correctASTNodes(new GraphQLInterfaceType({
1525 ...config,
1526 fields: newFieldConfigMap,
1527 }));
1528 }
1529 else {
1530 newTypeMap[typeName] = correctASTNodes(new GraphQLInputObjectType({
1531 ...config,
1532 fields: newFieldConfigMap,
1533 }));
1534 }
1535 }
1536 });
1537 return newTypeMap;
1538}
1539function mapArguments(originalTypeMap, schema, schemaMapper) {
1540 const newTypeMap = {};
1541 Object.keys(originalTypeMap).forEach(typeName => {
1542 if (!typeName.startsWith('__')) {
1543 const originalType = originalTypeMap[typeName];
1544 if (!isObjectType(originalType) && !isInterfaceType(originalType)) {
1545 newTypeMap[typeName] = originalType;
1546 return;
1547 }
1548 const argumentMapper = getArgumentMapper(schemaMapper);
1549 if (argumentMapper == null) {
1550 newTypeMap[typeName] = originalType;
1551 return;
1552 }
1553 const config = originalType.toConfig();
1554 const originalFieldConfigMap = config.fields;
1555 const newFieldConfigMap = {};
1556 Object.keys(originalFieldConfigMap).forEach(fieldName => {
1557 const originalFieldConfig = originalFieldConfigMap[fieldName];
1558 const originalArgumentConfigMap = originalFieldConfig.args;
1559 if (originalArgumentConfigMap == null) {
1560 newFieldConfigMap[fieldName] = originalFieldConfig;
1561 return;
1562 }
1563 const argumentNames = Object.keys(originalArgumentConfigMap);
1564 if (!argumentNames.length) {
1565 newFieldConfigMap[fieldName] = originalFieldConfig;
1566 return;
1567 }
1568 const newArgumentConfigMap = {};
1569 argumentNames.forEach(argumentName => {
1570 const originalArgumentConfig = originalArgumentConfigMap[argumentName];
1571 const mappedArgument = argumentMapper(originalArgumentConfig, fieldName, typeName, schema);
1572 if (mappedArgument === undefined) {
1573 newArgumentConfigMap[argumentName] = originalArgumentConfig;
1574 }
1575 else if (Array.isArray(mappedArgument)) {
1576 const [newArgumentName, newArgumentConfig] = mappedArgument;
1577 newArgumentConfigMap[newArgumentName] = newArgumentConfig;
1578 }
1579 else if (mappedArgument !== null) {
1580 newArgumentConfigMap[argumentName] = mappedArgument;
1581 }
1582 });
1583 newFieldConfigMap[fieldName] = {
1584 ...originalFieldConfig,
1585 args: newArgumentConfigMap,
1586 };
1587 });
1588 if (isObjectType(originalType)) {
1589 newTypeMap[typeName] = new GraphQLObjectType({
1590 ...config,
1591 fields: newFieldConfigMap,
1592 });
1593 }
1594 else if (isInterfaceType(originalType)) {
1595 newTypeMap[typeName] = new GraphQLInterfaceType({
1596 ...config,
1597 fields: newFieldConfigMap,
1598 });
1599 }
1600 else {
1601 newTypeMap[typeName] = new GraphQLInputObjectType({
1602 ...config,
1603 fields: newFieldConfigMap,
1604 });
1605 }
1606 }
1607 });
1608 return newTypeMap;
1609}
1610function mapDirectives(originalDirectives, schema, schemaMapper) {
1611 const directiveMapper = getDirectiveMapper(schemaMapper);
1612 if (directiveMapper == null) {
1613 return originalDirectives.slice();
1614 }
1615 const newDirectives = [];
1616 originalDirectives.forEach(directive => {
1617 const mappedDirective = directiveMapper(directive, schema);
1618 if (mappedDirective === undefined) {
1619 newDirectives.push(directive);
1620 }
1621 else if (mappedDirective !== null) {
1622 newDirectives.push(mappedDirective);
1623 }
1624 });
1625 return newDirectives;
1626}
1627function getTypeSpecifiers(schema, typeName) {
1628 const type = schema.getType(typeName);
1629 const specifiers = [MapperKind.TYPE];
1630 if (isObjectType(type)) {
1631 specifiers.push(MapperKind.COMPOSITE_TYPE, MapperKind.OBJECT_TYPE);
1632 const query = schema.getQueryType();
1633 const mutation = schema.getMutationType();
1634 const subscription = schema.getSubscriptionType();
1635 if (query != null && typeName === query.name) {
1636 specifiers.push(MapperKind.ROOT_OBJECT, MapperKind.QUERY);
1637 }
1638 else if (mutation != null && typeName === mutation.name) {
1639 specifiers.push(MapperKind.ROOT_OBJECT, MapperKind.MUTATION);
1640 }
1641 else if (subscription != null && typeName === subscription.name) {
1642 specifiers.push(MapperKind.ROOT_OBJECT, MapperKind.SUBSCRIPTION);
1643 }
1644 }
1645 else if (isInputObjectType(type)) {
1646 specifiers.push(MapperKind.INPUT_OBJECT_TYPE);
1647 }
1648 else if (isInterfaceType(type)) {
1649 specifiers.push(MapperKind.COMPOSITE_TYPE, MapperKind.ABSTRACT_TYPE, MapperKind.INTERFACE_TYPE);
1650 }
1651 else if (isUnionType(type)) {
1652 specifiers.push(MapperKind.COMPOSITE_TYPE, MapperKind.ABSTRACT_TYPE, MapperKind.UNION_TYPE);
1653 }
1654 else if (isEnumType(type)) {
1655 specifiers.push(MapperKind.ENUM_TYPE);
1656 }
1657 else if (isScalarType(type)) {
1658 specifiers.push(MapperKind.SCALAR_TYPE);
1659 }
1660 return specifiers;
1661}
1662function getTypeMapper(schema, schemaMapper, typeName) {
1663 const specifiers = getTypeSpecifiers(schema, typeName);
1664 let typeMapper;
1665 const stack = [...specifiers];
1666 while (!typeMapper && stack.length > 0) {
1667 const next = stack.pop();
1668 typeMapper = schemaMapper[next];
1669 }
1670 return typeMapper != null ? typeMapper : null;
1671}
1672function getFieldSpecifiers(schema, typeName) {
1673 const type = schema.getType(typeName);
1674 const specifiers = [MapperKind.FIELD];
1675 if (isObjectType(type)) {
1676 specifiers.push(MapperKind.COMPOSITE_FIELD, MapperKind.OBJECT_FIELD);
1677 const query = schema.getQueryType();
1678 const mutation = schema.getMutationType();
1679 const subscription = schema.getSubscriptionType();
1680 if (query != null && typeName === query.name) {
1681 specifiers.push(MapperKind.ROOT_FIELD, MapperKind.QUERY_ROOT_FIELD);
1682 }
1683 else if (mutation != null && typeName === mutation.name) {
1684 specifiers.push(MapperKind.ROOT_FIELD, MapperKind.MUTATION_ROOT_FIELD);
1685 }
1686 else if (subscription != null && typeName === subscription.name) {
1687 specifiers.push(MapperKind.ROOT_FIELD, MapperKind.SUBSCRIPTION_ROOT_FIELD);
1688 }
1689 }
1690 else if (isInterfaceType(type)) {
1691 specifiers.push(MapperKind.COMPOSITE_FIELD, MapperKind.INTERFACE_FIELD);
1692 }
1693 else if (isInputObjectType(type)) {
1694 specifiers.push(MapperKind.INPUT_OBJECT_FIELD);
1695 }
1696 return specifiers;
1697}
1698function getFieldMapper(schema, schemaMapper, typeName) {
1699 const specifiers = getFieldSpecifiers(schema, typeName);
1700 let fieldMapper;
1701 const stack = [...specifiers];
1702 while (!fieldMapper && stack.length > 0) {
1703 const next = stack.pop();
1704 fieldMapper = schemaMapper[next];
1705 }
1706 return fieldMapper != null ? fieldMapper : null;
1707}
1708function getArgumentMapper(schemaMapper) {
1709 const argumentMapper = schemaMapper[MapperKind.ARGUMENT];
1710 return argumentMapper != null ? argumentMapper : null;
1711}
1712function getDirectiveMapper(schemaMapper) {
1713 const directiveMapper = schemaMapper[MapperKind.DIRECTIVE];
1714 return directiveMapper != null ? directiveMapper : null;
1715}
1716function getEnumValueMapper(schemaMapper) {
1717 const enumValueMapper = schemaMapper[MapperKind.ENUM_VALUE];
1718 return enumValueMapper != null ? enumValueMapper : null;
1719}
1720function correctASTNodes(type) {
1721 if (isObjectType(type)) {
1722 const config = type.toConfig();
1723 if (config.astNode != null) {
1724 const fields = [];
1725 Object.values(config.fields).forEach(fieldConfig => {
1726 if (fieldConfig.astNode != null) {
1727 fields.push(fieldConfig.astNode);
1728 }
1729 });
1730 config.astNode = {
1731 ...config.astNode,
1732 kind: Kind.OBJECT_TYPE_DEFINITION,
1733 fields,
1734 };
1735 }
1736 if (config.extensionASTNodes != null) {
1737 config.extensionASTNodes = config.extensionASTNodes.map(node => ({
1738 ...node,
1739 kind: Kind.OBJECT_TYPE_EXTENSION,
1740 fields: undefined,
1741 }));
1742 }
1743 return new GraphQLObjectType(config);
1744 }
1745 else if (isInterfaceType(type)) {
1746 const config = type.toConfig();
1747 if (config.astNode != null) {
1748 const fields = [];
1749 Object.values(config.fields).forEach(fieldConfig => {
1750 if (fieldConfig.astNode != null) {
1751 fields.push(fieldConfig.astNode);
1752 }
1753 });
1754 config.astNode = {
1755 ...config.astNode,
1756 kind: Kind.INTERFACE_TYPE_DEFINITION,
1757 fields,
1758 };
1759 }
1760 if (config.extensionASTNodes != null) {
1761 config.extensionASTNodes = config.extensionASTNodes.map(node => ({
1762 ...node,
1763 kind: Kind.INTERFACE_TYPE_EXTENSION,
1764 fields: undefined,
1765 }));
1766 }
1767 return new GraphQLInterfaceType(config);
1768 }
1769 else if (isInputObjectType(type)) {
1770 const config = type.toConfig();
1771 if (config.astNode != null) {
1772 const fields = [];
1773 Object.values(config.fields).forEach(fieldConfig => {
1774 if (fieldConfig.astNode != null) {
1775 fields.push(fieldConfig.astNode);
1776 }
1777 });
1778 config.astNode = {
1779 ...config.astNode,
1780 kind: Kind.INPUT_OBJECT_TYPE_DEFINITION,
1781 fields,
1782 };
1783 }
1784 if (config.extensionASTNodes != null) {
1785 config.extensionASTNodes = config.extensionASTNodes.map(node => ({
1786 ...node,
1787 kind: Kind.INPUT_OBJECT_TYPE_EXTENSION,
1788 fields: undefined,
1789 }));
1790 }
1791 return new GraphQLInputObjectType(config);
1792 }
1793 else if (isEnumType(type)) {
1794 const config = type.toConfig();
1795 if (config.astNode != null) {
1796 const values = [];
1797 Object.values(config.values).forEach(enumValueConfig => {
1798 if (enumValueConfig.astNode != null) {
1799 values.push(enumValueConfig.astNode);
1800 }
1801 });
1802 config.astNode = {
1803 ...config.astNode,
1804 values,
1805 };
1806 }
1807 if (config.extensionASTNodes != null) {
1808 config.extensionASTNodes = config.extensionASTNodes.map(node => ({
1809 ...node,
1810 values: undefined,
1811 }));
1812 }
1813 return new GraphQLEnumType(config);
1814 }
1815 else {
1816 return type;
1817 }
1818}
1819
1820function filterSchema({ schema, rootFieldFilter = () => true, typeFilter = () => true, fieldFilter = () => true, }) {
1821 const filteredSchema = mapSchema(schema, {
1822 [MapperKind.QUERY]: (type) => filterRootFields(type, 'Query', rootFieldFilter),
1823 [MapperKind.MUTATION]: (type) => filterRootFields(type, 'Mutation', rootFieldFilter),
1824 [MapperKind.SUBSCRIPTION]: (type) => filterRootFields(type, 'Subscription', rootFieldFilter),
1825 [MapperKind.OBJECT_TYPE]: (type) => typeFilter(type.name, type) ? filterObjectFields(type, fieldFilter) : null,
1826 [MapperKind.INTERFACE_TYPE]: (type) => (typeFilter(type.name, type) ? undefined : null),
1827 [MapperKind.UNION_TYPE]: (type) => (typeFilter(type.name, type) ? undefined : null),
1828 [MapperKind.INPUT_OBJECT_TYPE]: (type) => (typeFilter(type.name, type) ? undefined : null),
1829 [MapperKind.ENUM_TYPE]: (type) => (typeFilter(type.name, type) ? undefined : null),
1830 [MapperKind.SCALAR_TYPE]: (type) => (typeFilter(type.name, type) ? undefined : null),
1831 });
1832 return filteredSchema;
1833}
1834function filterRootFields(type, operation, rootFieldFilter) {
1835 const config = type.toConfig();
1836 Object.keys(config.fields).forEach(fieldName => {
1837 if (!rootFieldFilter(operation, fieldName, config.fields[fieldName])) {
1838 delete config.fields[fieldName];
1839 }
1840 });
1841 return new GraphQLObjectType(config);
1842}
1843function filterObjectFields(type, fieldFilter) {
1844 const config = type.toConfig();
1845 Object.keys(config.fields).forEach(fieldName => {
1846 if (!fieldFilter(type.name, fieldName, config.fields[fieldName])) {
1847 delete config.fields[fieldName];
1848 }
1849 });
1850 return new GraphQLObjectType(config);
1851}
1852
1853function cloneDirective(directive) {
1854 return isSpecifiedDirective(directive) ? directive : new GraphQLDirective(directive.toConfig());
1855}
1856function cloneType(type) {
1857 if (isObjectType(type)) {
1858 const config = type.toConfig();
1859 return new GraphQLObjectType({
1860 ...config,
1861 interfaces: typeof config.interfaces === 'function' ? config.interfaces : config.interfaces.slice(),
1862 });
1863 }
1864 else if (isInterfaceType(type)) {
1865 const config = type.toConfig();
1866 const newConfig = {
1867 ...config,
1868 interfaces: [...((typeof config.interfaces === 'function' ? config.interfaces() : config.interfaces) || [])],
1869 };
1870 return new GraphQLInterfaceType(newConfig);
1871 }
1872 else if (isUnionType(type)) {
1873 const config = type.toConfig();
1874 return new GraphQLUnionType({
1875 ...config,
1876 types: config.types.slice(),
1877 });
1878 }
1879 else if (isInputObjectType(type)) {
1880 return new GraphQLInputObjectType(type.toConfig());
1881 }
1882 else if (isEnumType(type)) {
1883 return new GraphQLEnumType(type.toConfig());
1884 }
1885 else if (isScalarType(type)) {
1886 return isSpecifiedScalarType(type) ? type : new GraphQLScalarType(type.toConfig());
1887 }
1888 throw new Error(`Invalid type ${type}`);
1889}
1890function cloneSchema(schema) {
1891 return mapSchema(schema);
1892}
1893
1894// Update any references to named schema types that disagree with the named
1895// types found in schema.getTypeMap().
1896//
1897// healSchema and its callers (visitSchema/visitSchemaDirectives) all modify the schema in place.
1898// Therefore, private variables (such as the stored implementation map and the proper root types)
1899// are not updated.
1900//
1901// If this causes issues, the schema could be more aggressively healed as follows:
1902//
1903// healSchema(schema);
1904// const config = schema.toConfig()
1905// const healedSchema = new GraphQLSchema({
1906// ...config,
1907// query: schema.getType('<desired new root query type name>'),
1908// mutation: schema.getType('<desired new root mutation type name>'),
1909// subscription: schema.getType('<desired new root subscription type name>'),
1910// });
1911//
1912// One can then also -- if necessary -- assign the correct private variables to the initial schema
1913// as follows:
1914// Object.assign(schema, healedSchema);
1915//
1916// These steps are not taken automatically to preserve backwards compatibility with graphql-tools v4.
1917// See https://github.com/ardatan/graphql-tools/issues/1462
1918//
1919// They were briefly taken in v5, but can now be phased out as they were only required when other
1920// areas of the codebase were using healSchema and visitSchema more extensively.
1921//
1922function healSchema(schema) {
1923 healTypes(schema.getTypeMap(), schema.getDirectives());
1924 return schema;
1925}
1926function healTypes(originalTypeMap, directives, config = {
1927 skipPruning: false,
1928}) {
1929 const actualNamedTypeMap = Object.create(null);
1930 // If any of the .name properties of the GraphQLNamedType objects in
1931 // schema.getTypeMap() have changed, the keys of the type map need to
1932 // be updated accordingly.
1933 Object.entries(originalTypeMap).forEach(([typeName, namedType]) => {
1934 if (namedType == null || typeName.startsWith('__')) {
1935 return;
1936 }
1937 const actualName = namedType.name;
1938 if (actualName.startsWith('__')) {
1939 return;
1940 }
1941 if (actualName in actualNamedTypeMap) {
1942 throw new Error(`Duplicate schema type name ${actualName}`);
1943 }
1944 actualNamedTypeMap[actualName] = namedType;
1945 // Note: we are deliberately leaving namedType in the schema by its
1946 // original name (which might be different from actualName), so that
1947 // references by that name can be healed.
1948 });
1949 // Now add back every named type by its actual name.
1950 Object.entries(actualNamedTypeMap).forEach(([typeName, namedType]) => {
1951 originalTypeMap[typeName] = namedType;
1952 });
1953 // Directive declaration argument types can refer to named types.
1954 directives.forEach((decl) => {
1955 decl.args = decl.args.filter(arg => {
1956 arg.type = healType(arg.type);
1957 return arg.type !== null;
1958 });
1959 });
1960 Object.entries(originalTypeMap).forEach(([typeName, namedType]) => {
1961 // Heal all named types, except for dangling references, kept only to redirect.
1962 if (!typeName.startsWith('__') && typeName in actualNamedTypeMap) {
1963 if (namedType != null) {
1964 healNamedType(namedType);
1965 }
1966 }
1967 });
1968 for (const typeName of Object.keys(originalTypeMap)) {
1969 if (!typeName.startsWith('__') && !(typeName in actualNamedTypeMap)) {
1970 delete originalTypeMap[typeName];
1971 }
1972 }
1973 if (!config.skipPruning) {
1974 // TODO:
1975 // consider removing the default level of pruning in v7,
1976 // see comments below on the pruneTypes function.
1977 pruneTypes$1(originalTypeMap, directives);
1978 }
1979 function healNamedType(type) {
1980 if (isObjectType(type)) {
1981 healFields(type);
1982 healInterfaces(type);
1983 return;
1984 }
1985 else if (isInterfaceType(type)) {
1986 healFields(type);
1987 if ('getInterfaces' in type) {
1988 healInterfaces(type);
1989 }
1990 return;
1991 }
1992 else if (isUnionType(type)) {
1993 healUnderlyingTypes(type);
1994 return;
1995 }
1996 else if (isInputObjectType(type)) {
1997 healInputFields(type);
1998 return;
1999 }
2000 else if (isLeafType(type)) {
2001 return;
2002 }
2003 throw new Error(`Unexpected schema type: ${type}`);
2004 }
2005 function healFields(type) {
2006 const fieldMap = type.getFields();
2007 for (const [key, field] of Object.entries(fieldMap)) {
2008 field.args
2009 .map(arg => {
2010 arg.type = healType(arg.type);
2011 return arg.type === null ? null : arg;
2012 })
2013 .filter(Boolean);
2014 field.type = healType(field.type);
2015 if (field.type === null) {
2016 delete fieldMap[key];
2017 }
2018 }
2019 }
2020 function healInterfaces(type) {
2021 if ('getInterfaces' in type) {
2022 const interfaces = type.getInterfaces();
2023 interfaces.push(...interfaces
2024 .splice(0)
2025 .map(iface => healType(iface))
2026 .filter(Boolean));
2027 }
2028 }
2029 function healInputFields(type) {
2030 const fieldMap = type.getFields();
2031 for (const [key, field] of Object.entries(fieldMap)) {
2032 field.type = healType(field.type);
2033 if (field.type === null) {
2034 delete fieldMap[key];
2035 }
2036 }
2037 }
2038 function healUnderlyingTypes(type) {
2039 const types = type.getTypes();
2040 types.push(...types
2041 .splice(0)
2042 .map(t => healType(t))
2043 .filter(Boolean));
2044 }
2045 function healType(type) {
2046 // Unwrap the two known wrapper types
2047 if (isListType(type)) {
2048 const healedType = healType(type.ofType);
2049 return healedType != null ? new GraphQLList(healedType) : null;
2050 }
2051 else if (isNonNullType(type)) {
2052 const healedType = healType(type.ofType);
2053 return healedType != null ? new GraphQLNonNull(healedType) : null;
2054 }
2055 else if (isNamedType(type)) {
2056 // If a type annotation on a field or an argument or a union member is
2057 // any `GraphQLNamedType` with a `name`, then it must end up identical
2058 // to `schema.getType(name)`, since `schema.getTypeMap()` is the source
2059 // of truth for all named schema types.
2060 // Note that new types can still be simply added by adding a field, as
2061 // the official type will be undefined, not null.
2062 const officialType = originalTypeMap[type.name];
2063 if (officialType && type !== officialType) {
2064 return officialType;
2065 }
2066 }
2067 return type;
2068 }
2069}
2070// TODO:
2071// consider removing the default level of pruning in v7
2072//
2073// Pruning was introduced into healSchema in v5, so legacy schema directives relying on pruning
2074// during healing are likely to be rare. pruning is now recommended via the dedicated pruneSchema
2075// function which does not force pruning on library users and gives granular control in terms of
2076// pruning types. pruneSchema does recreate the schema -- a parallel version that prunes in place
2077// could be considered.
2078function pruneTypes$1(typeMap, directives) {
2079 const implementedInterfaces = {};
2080 Object.values(typeMap).forEach(namedType => {
2081 if ('getInterfaces' in namedType) {
2082 namedType.getInterfaces().forEach(iface => {
2083 implementedInterfaces[iface.name] = true;
2084 });
2085 }
2086 });
2087 let prunedTypeMap = false;
2088 const typeNames = Object.keys(typeMap);
2089 for (let i = 0; i < typeNames.length; i++) {
2090 const typeName = typeNames[i];
2091 const type = typeMap[typeName];
2092 if (isObjectType(type) || isInputObjectType(type)) {
2093 // prune types with no fields
2094 if (!Object.keys(type.getFields()).length) {
2095 typeMap[typeName] = null;
2096 prunedTypeMap = true;
2097 }
2098 }
2099 else if (isUnionType(type)) {
2100 // prune unions without underlying types
2101 if (!type.getTypes().length) {
2102 typeMap[typeName] = null;
2103 prunedTypeMap = true;
2104 }
2105 }
2106 else if (isInterfaceType(type)) {
2107 // prune interfaces without fields or without implementations
2108 if (!Object.keys(type.getFields()).length || !(type.name in implementedInterfaces)) {
2109 typeMap[typeName] = null;
2110 prunedTypeMap = true;
2111 }
2112 }
2113 }
2114 // every prune requires another round of healing
2115 if (prunedTypeMap) {
2116 healTypes(typeMap, directives);
2117 }
2118}
2119
2120// Abstract base class of any visitor implementation, defining the available
2121// visitor methods along with their parameter types, and providing a static
2122// helper function for determining whether a subclass implements a given
2123// visitor method, as opposed to inheriting one of the stubs defined here.
2124class SchemaVisitor {
2125 // Determine if this SchemaVisitor (sub)class implements a particular
2126 // visitor method.
2127 static implementsVisitorMethod(methodName) {
2128 if (!methodName.startsWith('visit')) {
2129 return false;
2130 }
2131 const method = this.prototype[methodName];
2132 if (typeof method !== 'function') {
2133 return false;
2134 }
2135 if (this.name === 'SchemaVisitor') {
2136 // The SchemaVisitor class implements every visitor method.
2137 return true;
2138 }
2139 const stub = SchemaVisitor.prototype[methodName];
2140 if (method === stub) {
2141 // If this.prototype[methodName] was just inherited from SchemaVisitor,
2142 // then this class does not really implement the method.
2143 return false;
2144 }
2145 return true;
2146 }
2147 // Concrete subclasses of SchemaVisitor should override one or more of these
2148 // visitor methods, in order to express their interest in handling certain
2149 // schema types/locations. Each method may return null to remove the given
2150 // type from the schema, a non-null value of the same type to update the
2151 // type in the schema, or nothing to leave the type as it was.
2152 // eslint-disable-next-line @typescript-eslint/no-empty-function
2153 visitSchema(_schema) { }
2154 visitScalar(_scalar
2155 // eslint-disable-next-line @typescript-eslint/no-empty-function
2156 ) { }
2157 visitObject(_object
2158 // eslint-disable-next-line @typescript-eslint/no-empty-function
2159 ) { }
2160 visitFieldDefinition(_field, _details
2161 // eslint-disable-next-line @typescript-eslint/no-empty-function
2162 ) { }
2163 visitArgumentDefinition(_argument, _details
2164 // eslint-disable-next-line @typescript-eslint/no-empty-function
2165 ) { }
2166 visitInterface(_iface
2167 // eslint-disable-next-line @typescript-eslint/no-empty-function
2168 ) { }
2169 // eslint-disable-next-line @typescript-eslint/no-empty-function
2170 visitUnion(_union) { }
2171 // eslint-disable-next-line @typescript-eslint/no-empty-function
2172 visitEnum(_type) { }
2173 visitEnumValue(_value, _details
2174 // eslint-disable-next-line @typescript-eslint/no-empty-function
2175 ) { }
2176 visitInputObject(_object
2177 // eslint-disable-next-line @typescript-eslint/no-empty-function
2178 ) { }
2179 visitInputFieldDefinition(_field, _details
2180 // eslint-disable-next-line @typescript-eslint/no-empty-function
2181 ) { }
2182}
2183
2184function isSchemaVisitor(obj) {
2185 if ('schema' in obj && isSchema(obj.schema)) {
2186 if ('visitSchema' in obj && typeof obj.visitSchema === 'function') {
2187 return true;
2188 }
2189 }
2190 return false;
2191}
2192// Generic function for visiting GraphQLSchema objects.
2193function visitSchema(schema,
2194// To accommodate as many different visitor patterns as possible, the
2195// visitSchema function does not simply accept a single instance of the
2196// SchemaVisitor class, but instead accepts a function that takes the
2197// current VisitableSchemaType object and the name of a visitor method and
2198// returns an array of SchemaVisitor instances that implement the visitor
2199// method and have an interest in handling the given VisitableSchemaType
2200// object. In the simplest case, this function can always return an array
2201// containing a single visitor object, without even looking at the type or
2202// methodName parameters. In other cases, this function might sometimes
2203// return an empty array to indicate there are no visitors that should be
2204// applied to the given VisitableSchemaType object. For an example of a
2205// visitor pattern that benefits from this abstraction, see the
2206// SchemaDirectiveVisitor class below.
2207visitorOrVisitorSelector) {
2208 const visitorSelector = typeof visitorOrVisitorSelector === 'function' ? visitorOrVisitorSelector : () => visitorOrVisitorSelector;
2209 // Helper function that calls visitorSelector and applies the resulting
2210 // visitors to the given type, with arguments [type, ...args].
2211 function callMethod(methodName, type, ...args) {
2212 let visitors = visitorSelector(type, methodName);
2213 visitors = Array.isArray(visitors) ? visitors : [visitors];
2214 let finalType = type;
2215 visitors.every(visitorOrVisitorDef => {
2216 let newType;
2217 if (isSchemaVisitor(visitorOrVisitorDef)) {
2218 newType = visitorOrVisitorDef[methodName](finalType, ...args);
2219 }
2220 else if (isNamedType(finalType) &&
2221 (methodName === 'visitScalar' ||
2222 methodName === 'visitEnum' ||
2223 methodName === 'visitObject' ||
2224 methodName === 'visitInputObject' ||
2225 methodName === 'visitUnion' ||
2226 methodName === 'visitInterface')) {
2227 const specifiers = getTypeSpecifiers$1(finalType, schema);
2228 const typeVisitor = getVisitor(visitorOrVisitorDef, specifiers);
2229 newType = typeVisitor != null ? typeVisitor(finalType, schema) : undefined;
2230 }
2231 if (typeof newType === 'undefined') {
2232 // Keep going without modifying type.
2233 return true;
2234 }
2235 if (methodName === 'visitSchema' || isSchema(finalType)) {
2236 throw new Error(`Method ${methodName} cannot replace schema with ${newType}`);
2237 }
2238 if (newType === null) {
2239 // Stop the loop and return null form callMethod, which will cause
2240 // the type to be removed from the schema.
2241 finalType = null;
2242 return false;
2243 }
2244 // Update type to the new type returned by the visitor method, so that
2245 // later directives will see the new type, and callMethod will return
2246 // the final type.
2247 finalType = newType;
2248 return true;
2249 });
2250 // If there were no directives for this type object, or if all visitor
2251 // methods returned nothing, type will be returned unmodified.
2252 return finalType;
2253 }
2254 // Recursive helper function that calls any appropriate visitor methods for
2255 // each object in the schema, then traverses the object's children (if any).
2256 function visit(type) {
2257 if (isSchema(type)) {
2258 // Unlike the other types, the root GraphQLSchema object cannot be
2259 // replaced by visitor methods, because that would make life very hard
2260 // for SchemaVisitor subclasses that rely on the original schema object.
2261 callMethod('visitSchema', type);
2262 const typeMap = type.getTypeMap();
2263 Object.entries(typeMap).forEach(([typeName, namedType]) => {
2264 if (!typeName.startsWith('__') && namedType != null) {
2265 // Call visit recursively to let it determine which concrete
2266 // subclass of GraphQLNamedType we found in the type map.
2267 // We do not use updateEachKey because we want to preserve
2268 // deleted types in the typeMap so that other types that reference
2269 // the deleted types can be healed.
2270 typeMap[typeName] = visit(namedType);
2271 }
2272 });
2273 return type;
2274 }
2275 if (isObjectType(type)) {
2276 // Note that callMethod('visitObject', type) may not actually call any
2277 // methods, if there are no @directive annotations associated with this
2278 // type, or if this SchemaDirectiveVisitor subclass does not override
2279 // the visitObject method.
2280 const newObject = callMethod('visitObject', type);
2281 if (newObject != null) {
2282 visitFields(newObject);
2283 }
2284 return newObject;
2285 }
2286 if (isInterfaceType(type)) {
2287 const newInterface = callMethod('visitInterface', type);
2288 if (newInterface != null) {
2289 visitFields(newInterface);
2290 }
2291 return newInterface;
2292 }
2293 if (isInputObjectType(type)) {
2294 const newInputObject = callMethod('visitInputObject', type);
2295 if (newInputObject != null) {
2296 const fieldMap = newInputObject.getFields();
2297 for (const key of Object.keys(fieldMap)) {
2298 fieldMap[key] = callMethod('visitInputFieldDefinition', fieldMap[key], {
2299 // Since we call a different method for input object fields, we
2300 // can't reuse the visitFields function here.
2301 objectType: newInputObject,
2302 });
2303 if (!fieldMap[key]) {
2304 delete fieldMap[key];
2305 }
2306 }
2307 }
2308 return newInputObject;
2309 }
2310 if (isScalarType(type)) {
2311 return callMethod('visitScalar', type);
2312 }
2313 if (isUnionType(type)) {
2314 return callMethod('visitUnion', type);
2315 }
2316 if (isEnumType(type)) {
2317 let newEnum = callMethod('visitEnum', type);
2318 if (newEnum != null) {
2319 const newValues = newEnum
2320 .getValues()
2321 .map(value => callMethod('visitEnumValue', value, {
2322 enumType: newEnum,
2323 }))
2324 .filter(Boolean);
2325 // Recreate the enum type if any of the values changed
2326 const valuesUpdated = newValues.some((value, index) => value !== newEnum.getValues()[index]);
2327 if (valuesUpdated) {
2328 newEnum = new GraphQLEnumType({
2329 ...newEnum.toConfig(),
2330 values: newValues.reduce((prev, value) => ({
2331 ...prev,
2332 [value.name]: {
2333 value: value.value,
2334 deprecationReason: value.deprecationReason,
2335 description: value.description,
2336 astNode: value.astNode,
2337 },
2338 }), {}),
2339 });
2340 }
2341 }
2342 return newEnum;
2343 }
2344 throw new Error(`Unexpected schema type: ${type}`);
2345 }
2346 function visitFields(type) {
2347 const fieldMap = type.getFields();
2348 for (const [key, field] of Object.entries(fieldMap)) {
2349 // It would be nice if we could call visit(field) recursively here, but
2350 // GraphQLField is merely a type, not a value that can be detected using
2351 // an instanceof check, so we have to visit the fields in this lexical
2352 // context, so that TypeScript can validate the call to
2353 // visitFieldDefinition.
2354 const newField = callMethod('visitFieldDefinition', field, {
2355 // While any field visitor needs a reference to the field object, some
2356 // field visitors may also need to know the enclosing (parent) type,
2357 // perhaps to determine if the parent is a GraphQLObjectType or a
2358 // GraphQLInterfaceType. To obtain a reference to the parent, a
2359 // visitor method can have a second parameter, which will be an object
2360 // with an .objectType property referring to the parent.
2361 objectType: type,
2362 });
2363 if (newField.args != null) {
2364 newField.args = newField.args
2365 .map(arg => callMethod('visitArgumentDefinition', arg, {
2366 // Like visitFieldDefinition, visitArgumentDefinition takes a
2367 // second parameter that provides additional context, namely the
2368 // parent .field and grandparent .objectType. Remember that the
2369 // current GraphQLSchema is always available via this.schema.
2370 field: newField,
2371 objectType: type,
2372 }))
2373 .filter(Boolean);
2374 }
2375 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2376 if (newField) {
2377 fieldMap[key] = newField;
2378 }
2379 else {
2380 delete fieldMap[key];
2381 }
2382 }
2383 }
2384 visit(schema);
2385 // Automatically update any references to named schema types replaced
2386 // during the traversal, so implementors don't have to worry about that.
2387 healSchema(schema);
2388 // Return schema for convenience, even though schema parameter has all updated types.
2389 return schema;
2390}
2391function getTypeSpecifiers$1(type, schema) {
2392 const specifiers = [VisitSchemaKind.TYPE];
2393 if (isObjectType(type)) {
2394 specifiers.push(VisitSchemaKind.COMPOSITE_TYPE, VisitSchemaKind.OBJECT_TYPE);
2395 const query = schema.getQueryType();
2396 const mutation = schema.getMutationType();
2397 const subscription = schema.getSubscriptionType();
2398 if (type === query) {
2399 specifiers.push(VisitSchemaKind.ROOT_OBJECT, VisitSchemaKind.QUERY);
2400 }
2401 else if (type === mutation) {
2402 specifiers.push(VisitSchemaKind.ROOT_OBJECT, VisitSchemaKind.MUTATION);
2403 }
2404 else if (type === subscription) {
2405 specifiers.push(VisitSchemaKind.ROOT_OBJECT, VisitSchemaKind.SUBSCRIPTION);
2406 }
2407 }
2408 else if (isInputType(type)) {
2409 specifiers.push(VisitSchemaKind.INPUT_OBJECT_TYPE);
2410 }
2411 else if (isInterfaceType(type)) {
2412 specifiers.push(VisitSchemaKind.COMPOSITE_TYPE, VisitSchemaKind.ABSTRACT_TYPE, VisitSchemaKind.INTERFACE_TYPE);
2413 }
2414 else if (isUnionType(type)) {
2415 specifiers.push(VisitSchemaKind.COMPOSITE_TYPE, VisitSchemaKind.ABSTRACT_TYPE, VisitSchemaKind.UNION_TYPE);
2416 }
2417 else if (isEnumType(type)) {
2418 specifiers.push(VisitSchemaKind.ENUM_TYPE);
2419 }
2420 else if (isScalarType(type)) {
2421 specifiers.push(VisitSchemaKind.SCALAR_TYPE);
2422 }
2423 return specifiers;
2424}
2425function getVisitor(visitorDef, specifiers) {
2426 let typeVisitor;
2427 const stack = [...specifiers];
2428 while (!typeVisitor && stack.length > 0) {
2429 const next = stack.pop();
2430 typeVisitor = visitorDef[next];
2431 }
2432 return typeVisitor != null ? typeVisitor : null;
2433}
2434
2435// This class represents a reusable implementation of a @directive that may
2436// appear in a GraphQL schema written in Schema Definition Language.
2437//
2438// By overriding one or more visit{Object,Union,...} methods, a subclass
2439// registers interest in certain schema types, such as GraphQLObjectType,
2440// GraphQLUnionType, etc. When SchemaDirectiveVisitor.visitSchemaDirectives is
2441// called with a GraphQLSchema object and a map of visitor subclasses, the
2442// overidden methods of those subclasses allow the visitors to obtain
2443// references to any type objects that have @directives attached to them,
2444// enabling visitors to inspect or modify the schema as appropriate.
2445//
2446// For example, if a directive called @rest(url: "...") appears after a field
2447// definition, a SchemaDirectiveVisitor subclass could provide meaning to that
2448// directive by overriding the visitFieldDefinition method (which receives a
2449// GraphQLField parameter), and then the body of that visitor method could
2450// manipulate the field's resolver function to fetch data from a REST endpoint
2451// described by the url argument passed to the @rest directive:
2452//
2453// const typeDefs = `
2454// type Query {
2455// people: [Person] @rest(url: "/api/v1/people")
2456// }`;
2457//
2458// const schema = makeExecutableSchema({ typeDefs });
2459//
2460// SchemaDirectiveVisitor.visitSchemaDirectives(schema, {
2461// rest: class extends SchemaDirectiveVisitor {
2462// public visitFieldDefinition(field: GraphQLField<any, any>) {
2463// const { url } = this.args;
2464// field.resolve = () => fetch(url);
2465// }
2466// }
2467// });
2468//
2469// The subclass in this example is defined as an anonymous class expression,
2470// for brevity. A truly reusable SchemaDirectiveVisitor would most likely be
2471// defined in a library using a named class declaration, and then exported for
2472// consumption by other modules and packages.
2473//
2474// See below for a complete list of overridable visitor methods, their
2475// parameter types, and more details about the properties exposed by instances
2476// of the SchemaDirectiveVisitor class.
2477class SchemaDirectiveVisitor extends SchemaVisitor {
2478 // Mark the constructor protected to enforce passing SchemaDirectiveVisitor
2479 // subclasses (not instances) to visitSchemaDirectives.
2480 constructor(config) {
2481 super();
2482 this.name = config.name;
2483 this.args = config.args;
2484 this.visitedType = config.visitedType;
2485 this.schema = config.schema;
2486 this.context = config.context;
2487 }
2488 // Override this method to return a custom GraphQLDirective (or modify one
2489 // already present in the schema) to enforce argument types, provide default
2490 // argument values, or specify schema locations where this @directive may
2491 // appear. By default, any declaration found in the schema will be returned.
2492 static getDirectiveDeclaration(directiveName, schema) {
2493 return schema.getDirective(directiveName);
2494 }
2495 // Call SchemaDirectiveVisitor.visitSchemaDirectives to visit every
2496 // @directive in the schema and create an appropriate SchemaDirectiveVisitor
2497 // instance to visit the object decorated by the @directive.
2498 static visitSchemaDirectives(schema,
2499 // The keys of this object correspond to directive names as they appear
2500 // in the schema, and the values should be subclasses (not instances!)
2501 // of the SchemaDirectiveVisitor class. This distinction is important
2502 // because a new SchemaDirectiveVisitor instance will be created each
2503 // time a matching directive is found in the schema AST, with arguments
2504 // and other metadata specific to that occurrence. To help prevent the
2505 // mistake of passing instances, the SchemaDirectiveVisitor constructor
2506 // method is marked as protected.
2507 directiveVisitors,
2508 // Optional context object that will be available to all visitor instances
2509 // via this.context. Defaults to an empty null-prototype object.
2510 context = Object.create(null)
2511 // The visitSchemaDirectives method returns a map from directive names to
2512 // lists of SchemaDirectiveVisitors created while visiting the schema.
2513 ) {
2514 // If the schema declares any directives for public consumption, record
2515 // them here so that we can properly coerce arguments when/if we encounter
2516 // an occurrence of the directive while walking the schema below.
2517 const declaredDirectives = this.getDeclaredDirectives(schema, directiveVisitors);
2518 // Map from directive names to lists of SchemaDirectiveVisitor instances
2519 // created while visiting the schema.
2520 const createdVisitors = Object.keys(directiveVisitors).reduce((prev, item) => ({
2521 ...prev,
2522 [item]: [],
2523 }), {});
2524 const directiveVisitorMap = Object.entries(directiveVisitors).reduce((prev, [key, value]) => ({
2525 ...prev,
2526 [key]: value,
2527 }), {});
2528 function visitorSelector(type, methodName) {
2529 var _a, _b;
2530 let directiveNodes = (_b = (_a = type === null || type === void 0 ? void 0 : type.astNode) === null || _a === void 0 ? void 0 : _a.directives) !== null && _b !== void 0 ? _b : [];
2531 const extensionASTNodes = type.extensionASTNodes;
2532 if (extensionASTNodes != null) {
2533 extensionASTNodes.forEach(extensionASTNode => {
2534 if (extensionASTNode.directives != null) {
2535 directiveNodes = directiveNodes.concat(extensionASTNode.directives);
2536 }
2537 });
2538 }
2539 const visitors = [];
2540 directiveNodes.forEach(directiveNode => {
2541 const directiveName = directiveNode.name.value;
2542 if (!(directiveName in directiveVisitorMap)) {
2543 return;
2544 }
2545 const VisitorClass = directiveVisitorMap[directiveName];
2546 // Avoid creating visitor objects if visitorClass does not override
2547 // the visitor method named by methodName.
2548 if (!VisitorClass.implementsVisitorMethod(methodName)) {
2549 return;
2550 }
2551 const decl = declaredDirectives[directiveName];
2552 let args;
2553 if (decl != null) {
2554 // If this directive was explicitly declared, use the declared
2555 // argument types (and any default values) to check, coerce, and/or
2556 // supply default values for the given arguments.
2557 args = getArgumentValues(decl, directiveNode);
2558 }
2559 else {
2560 // If this directive was not explicitly declared, just convert the
2561 // argument nodes to their corresponding JavaScript values.
2562 args = Object.create(null);
2563 if (directiveNode.arguments != null) {
2564 directiveNode.arguments.forEach(arg => {
2565 args[arg.name.value] = valueFromASTUntyped(arg.value);
2566 });
2567 }
2568 }
2569 // As foretold in comments near the top of the visitSchemaDirectives
2570 // method, this is where instances of the SchemaDirectiveVisitor class
2571 // get created and assigned names. While subclasses could override the
2572 // constructor method, the constructor is marked as protected, so
2573 // these are the only arguments that will ever be passed.
2574 visitors.push(new VisitorClass({
2575 name: directiveName,
2576 args,
2577 visitedType: type,
2578 schema,
2579 context,
2580 }));
2581 });
2582 if (visitors.length > 0) {
2583 visitors.forEach(visitor => {
2584 createdVisitors[visitor.name].push(visitor);
2585 });
2586 }
2587 return visitors;
2588 }
2589 visitSchema(schema, visitorSelector);
2590 return createdVisitors;
2591 }
2592 static getDeclaredDirectives(schema, directiveVisitors) {
2593 const declaredDirectives = schema.getDirectives().reduce((prev, curr) => ({
2594 ...prev,
2595 [curr.name]: curr,
2596 }), {});
2597 // If the visitor subclass overrides getDirectiveDeclaration, and it
2598 // returns a non-null GraphQLDirective, use that instead of any directive
2599 // declared in the schema itself. Reasoning: if a SchemaDirectiveVisitor
2600 // goes to the trouble of implementing getDirectiveDeclaration, it should
2601 // be able to rely on that implementation.
2602 Object.entries(directiveVisitors).forEach(([directiveName, visitorClass]) => {
2603 const decl = visitorClass.getDirectiveDeclaration(directiveName, schema);
2604 if (decl != null) {
2605 declaredDirectives[directiveName] = decl;
2606 }
2607 });
2608 Object.entries(declaredDirectives).forEach(([name, decl]) => {
2609 if (!(name in directiveVisitors)) {
2610 // SchemaDirectiveVisitors.visitSchemaDirectives might be called
2611 // multiple times with partial directiveVisitors maps, so it's not
2612 // necessarily an error for directiveVisitors to be missing an
2613 // implementation of a directive that was declared in the schema.
2614 return;
2615 }
2616 const visitorClass = directiveVisitors[name];
2617 decl.locations.forEach(loc => {
2618 const visitorMethodName = directiveLocationToVisitorMethodName(loc);
2619 if (SchemaVisitor.implementsVisitorMethod(visitorMethodName) &&
2620 !visitorClass.implementsVisitorMethod(visitorMethodName)) {
2621 // While visitor subclasses may implement extra visitor methods,
2622 // it's definitely a mistake if the GraphQLDirective declares itself
2623 // applicable to certain schema locations, and the visitor subclass
2624 // does not implement all the corresponding methods.
2625 throw new Error(`SchemaDirectiveVisitor for @${name} must implement ${visitorMethodName} method`);
2626 }
2627 });
2628 });
2629 return declaredDirectives;
2630 }
2631}
2632// Convert a string like "FIELD_DEFINITION" to "visitFieldDefinition".
2633function directiveLocationToVisitorMethodName(loc) {
2634 return ('visit' +
2635 loc.replace(/([^_]*)_?/g, (_wholeMatch, part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()));
2636}
2637
2638function getResolversFromSchema(schema) {
2639 const resolvers = Object.create({});
2640 const typeMap = schema.getTypeMap();
2641 Object.keys(typeMap).forEach(typeName => {
2642 const type = typeMap[typeName];
2643 if (isScalarType(type)) {
2644 if (!isSpecifiedScalarType(type)) {
2645 resolvers[typeName] = cloneType(type);
2646 }
2647 }
2648 else if (isEnumType(type)) {
2649 resolvers[typeName] = {};
2650 const values = type.getValues();
2651 values.forEach(value => {
2652 resolvers[typeName][value.name] = value.value;
2653 });
2654 }
2655 else if (isInterfaceType(type)) {
2656 if (type.resolveType != null) {
2657 resolvers[typeName] = {
2658 __resolveType: type.resolveType,
2659 };
2660 }
2661 }
2662 else if (isUnionType(type)) {
2663 if (type.resolveType != null) {
2664 resolvers[typeName] = {
2665 __resolveType: type.resolveType,
2666 };
2667 }
2668 }
2669 else if (isObjectType(type)) {
2670 resolvers[typeName] = {};
2671 if (type.isTypeOf != null) {
2672 resolvers[typeName].__isTypeOf = type.isTypeOf;
2673 }
2674 const fields = type.getFields();
2675 Object.keys(fields).forEach(fieldName => {
2676 const field = fields[fieldName];
2677 resolvers[typeName][fieldName] = {
2678 resolve: field.resolve,
2679 subscribe: field.subscribe,
2680 };
2681 });
2682 }
2683 });
2684 return resolvers;
2685}
2686
2687function forEachField(schema, fn) {
2688 const typeMap = schema.getTypeMap();
2689 Object.keys(typeMap).forEach(typeName => {
2690 const type = typeMap[typeName];
2691 // TODO: maybe have an option to include these?
2692 if (!getNamedType(type).name.startsWith('__') && isObjectType(type)) {
2693 const fields = type.getFields();
2694 Object.keys(fields).forEach(fieldName => {
2695 const field = fields[fieldName];
2696 fn(field, typeName, fieldName);
2697 });
2698 }
2699 });
2700}
2701
2702function forEachDefaultValue(schema, fn) {
2703 const typeMap = schema.getTypeMap();
2704 Object.keys(typeMap).forEach(typeName => {
2705 const type = typeMap[typeName];
2706 if (!getNamedType(type).name.startsWith('__')) {
2707 if (isObjectType(type)) {
2708 const fields = type.getFields();
2709 Object.keys(fields).forEach(fieldName => {
2710 const field = fields[fieldName];
2711 field.args.forEach(arg => {
2712 arg.defaultValue = fn(arg.type, arg.defaultValue);
2713 });
2714 });
2715 }
2716 else if (isInputObjectType(type)) {
2717 const fields = type.getFields();
2718 Object.keys(fields).forEach(fieldName => {
2719 const field = fields[fieldName];
2720 field.defaultValue = fn(field.type, field.defaultValue);
2721 });
2722 }
2723 }
2724 });
2725}
2726
2727// addTypes uses toConfig to create a new schema with a new or replaced
2728function addTypes(schema, newTypesOrDirectives) {
2729 const queryType = schema.getQueryType();
2730 const mutationType = schema.getMutationType();
2731 const subscriptionType = schema.getSubscriptionType();
2732 const queryTypeName = queryType != null ? queryType.name : undefined;
2733 const mutationTypeName = mutationType != null ? mutationType.name : undefined;
2734 const subscriptionTypeName = subscriptionType != null ? subscriptionType.name : undefined;
2735 const config = schema.toConfig();
2736 const originalTypeMap = {};
2737 config.types.forEach(type => {
2738 originalTypeMap[type.name] = type;
2739 });
2740 const originalDirectiveMap = {};
2741 config.directives.forEach(directive => {
2742 originalDirectiveMap[directive.name] = directive;
2743 });
2744 newTypesOrDirectives.forEach(newTypeOrDirective => {
2745 if (isNamedType(newTypeOrDirective)) {
2746 originalTypeMap[newTypeOrDirective.name] = newTypeOrDirective;
2747 }
2748 else if (isDirective(newTypeOrDirective)) {
2749 originalDirectiveMap[newTypeOrDirective.name] = newTypeOrDirective;
2750 }
2751 });
2752 const { typeMap, directives } = rewireTypes(originalTypeMap, Object.keys(originalDirectiveMap).map(directiveName => originalDirectiveMap[directiveName]));
2753 return new GraphQLSchema({
2754 ...config,
2755 query: queryTypeName ? typeMap[queryTypeName] : undefined,
2756 mutation: mutationTypeName ? typeMap[mutationTypeName] : undefined,
2757 subscription: subscriptionTypeName != null ? typeMap[subscriptionTypeName] : undefined,
2758 types: Object.keys(typeMap).map(typeName => typeMap[typeName]),
2759 directives,
2760 });
2761}
2762
2763/**
2764 * Prunes the provided schema, removing unused and empty types
2765 * @param schema The schema to prune
2766 * @param options Additional options for removing unused types from the schema
2767 */
2768function pruneSchema(schema, options = {}) {
2769 const pruningContext = {
2770 schema,
2771 unusedTypes: Object.create(null),
2772 implementations: Object.create(null),
2773 };
2774 Object.keys(schema.getTypeMap()).forEach(typeName => {
2775 const type = schema.getType(typeName);
2776 if ('getInterfaces' in type) {
2777 type.getInterfaces().forEach(iface => {
2778 if (pruningContext.implementations[iface.name] == null) {
2779 pruningContext.implementations[iface.name] = Object.create(null);
2780 }
2781 pruningContext.implementations[iface.name][type.name] = true;
2782 });
2783 }
2784 });
2785 visitTypes(pruningContext, schema);
2786 return mapSchema(schema, {
2787 [MapperKind.TYPE]: (type) => {
2788 if (isObjectType(type) || isInputObjectType(type)) {
2789 if ((!Object.keys(type.getFields()).length && !options.skipEmptyCompositeTypePruning) ||
2790 (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning)) {
2791 return null;
2792 }
2793 }
2794 else if (isUnionType(type)) {
2795 if ((!type.getTypes().length && !options.skipEmptyUnionPruning) ||
2796 (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning)) {
2797 return null;
2798 }
2799 }
2800 else if (isInterfaceType(type)) {
2801 if ((!Object.keys(type.getFields()).length && !options.skipEmptyCompositeTypePruning) ||
2802 (!Object.keys(pruningContext.implementations[type.name]).length &&
2803 !options.skipUnimplementedInterfacesPruning) ||
2804 (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning)) {
2805 return null;
2806 }
2807 }
2808 else {
2809 if (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning) {
2810 return null;
2811 }
2812 }
2813 },
2814 });
2815}
2816function visitOutputType(visitedTypes, pruningContext, type) {
2817 if (visitedTypes[type.name]) {
2818 return;
2819 }
2820 visitedTypes[type.name] = true;
2821 pruningContext.unusedTypes[type.name] = false;
2822 if (isObjectType(type) || isInterfaceType(type)) {
2823 const fields = type.getFields();
2824 Object.keys(fields).forEach(fieldName => {
2825 const field = fields[fieldName];
2826 const namedType = getNamedType(field.type);
2827 visitOutputType(visitedTypes, pruningContext, namedType);
2828 const args = field.args;
2829 args.forEach(arg => {
2830 const type = getNamedType(arg.type);
2831 visitInputType(visitedTypes, pruningContext, type);
2832 });
2833 });
2834 if (isInterfaceType(type)) {
2835 Object.keys(pruningContext.implementations[type.name]).forEach(typeName => {
2836 visitOutputType(visitedTypes, pruningContext, pruningContext.schema.getType(typeName));
2837 });
2838 }
2839 if ('getInterfaces' in type) {
2840 type.getInterfaces().forEach(type => {
2841 visitOutputType(visitedTypes, pruningContext, type);
2842 });
2843 }
2844 }
2845 else if (isUnionType(type)) {
2846 const types = type.getTypes();
2847 types.forEach(type => visitOutputType(visitedTypes, pruningContext, type));
2848 }
2849}
2850function visitInputType(visitedTypes, pruningContext, type) {
2851 if (visitedTypes[type.name]) {
2852 return;
2853 }
2854 pruningContext.unusedTypes[type.name] = false;
2855 if (isInputObjectType(type)) {
2856 const fields = type.getFields();
2857 Object.keys(fields).forEach(fieldName => {
2858 const field = fields[fieldName];
2859 const namedType = getNamedType(field.type);
2860 visitInputType(visitedTypes, pruningContext, namedType);
2861 });
2862 }
2863 visitedTypes[type.name] = true;
2864}
2865function visitTypes(pruningContext, schema) {
2866 Object.keys(schema.getTypeMap()).forEach(typeName => {
2867 if (!typeName.startsWith('__')) {
2868 pruningContext.unusedTypes[typeName] = true;
2869 }
2870 });
2871 const visitedTypes = Object.create(null);
2872 const rootTypes = [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()].filter(type => type != null);
2873 rootTypes.forEach(rootType => visitOutputType(visitedTypes, pruningContext, rootType));
2874 schema.getDirectives().forEach(directive => {
2875 directive.args.forEach(arg => {
2876 const type = getNamedType(arg.type);
2877 visitInputType(visitedTypes, pruningContext, type);
2878 });
2879 });
2880}
2881
2882/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2883function mergeDeep(target, ...sources) {
2884 if (isScalarType(target)) {
2885 return target;
2886 }
2887 const output = {
2888 ...target,
2889 };
2890 for (const source of sources) {
2891 if (isObject(target) && isObject(source)) {
2892 for (const key in source) {
2893 if (isObject(source[key])) {
2894 if (!(key in target)) {
2895 Object.assign(output, { [key]: source[key] });
2896 }
2897 else {
2898 output[key] = mergeDeep(target[key], source[key]);
2899 }
2900 }
2901 else {
2902 Object.assign(output, { [key]: source[key] });
2903 }
2904 }
2905 }
2906 }
2907 return output;
2908}
2909function isObject(item) {
2910 return item && typeof item === 'object' && !Array.isArray(item);
2911}
2912
2913function renameFieldNode(fieldNode, name) {
2914 return {
2915 ...fieldNode,
2916 alias: {
2917 kind: Kind.NAME,
2918 value: fieldNode.alias != null ? fieldNode.alias.value : fieldNode.name.value,
2919 },
2920 name: {
2921 kind: Kind.NAME,
2922 value: name,
2923 },
2924 };
2925}
2926function preAliasFieldNode(fieldNode, str) {
2927 return {
2928 ...fieldNode,
2929 alias: {
2930 kind: Kind.NAME,
2931 value: `${str}${fieldNode.alias != null ? fieldNode.alias.value : fieldNode.name.value}`,
2932 },
2933 };
2934}
2935function wrapFieldNode(fieldNode, path) {
2936 let newFieldNode = fieldNode;
2937 path.forEach(fieldName => {
2938 newFieldNode = {
2939 kind: Kind.FIELD,
2940 name: {
2941 kind: Kind.NAME,
2942 value: fieldName,
2943 },
2944 selectionSet: {
2945 kind: Kind.SELECTION_SET,
2946 selections: [fieldNode],
2947 },
2948 };
2949 });
2950 return newFieldNode;
2951}
2952function collectFields(selectionSet, fragments, fields = [], visitedFragmentNames = {}) {
2953 if (selectionSet != null) {
2954 selectionSet.selections.forEach(selection => {
2955 switch (selection.kind) {
2956 case Kind.FIELD:
2957 fields.push(selection);
2958 break;
2959 case Kind.INLINE_FRAGMENT:
2960 collectFields(selection.selectionSet, fragments, fields, visitedFragmentNames);
2961 break;
2962 case Kind.FRAGMENT_SPREAD: {
2963 const fragmentName = selection.name.value;
2964 if (!visitedFragmentNames[fragmentName]) {
2965 visitedFragmentNames[fragmentName] = true;
2966 collectFields(fragments[fragmentName].selectionSet, fragments, fields, visitedFragmentNames);
2967 }
2968 break;
2969 }
2970 }
2971 });
2972 }
2973 return fields;
2974}
2975function hoistFieldNodes({ fieldNode, fieldNames, path = [], delimeter = '__gqltf__', fragments, }) {
2976 const alias = fieldNode.alias != null ? fieldNode.alias.value : fieldNode.name.value;
2977 let newFieldNodes = [];
2978 if (path.length) {
2979 const remainingPathSegments = path.slice();
2980 const initialPathSegment = remainingPathSegments.shift();
2981 collectFields(fieldNode.selectionSet, fragments).forEach((possibleFieldNode) => {
2982 if (possibleFieldNode.name.value === initialPathSegment) {
2983 newFieldNodes = newFieldNodes.concat(hoistFieldNodes({
2984 fieldNode: preAliasFieldNode(possibleFieldNode, `${alias}${delimeter}`),
2985 fieldNames,
2986 path: remainingPathSegments,
2987 delimeter,
2988 fragments,
2989 }));
2990 }
2991 });
2992 }
2993 else {
2994 collectFields(fieldNode.selectionSet, fragments).forEach((possibleFieldNode) => {
2995 if (!fieldNames || fieldNames.includes(possibleFieldNode.name.value)) {
2996 newFieldNodes.push(preAliasFieldNode(possibleFieldNode, `${alias}${delimeter}`));
2997 }
2998 });
2999 }
3000 return newFieldNodes;
3001}
3002
3003function concatInlineFragments(type, fragments) {
3004 const fragmentSelections = fragments.reduce((selections, fragment) => selections.concat(fragment.selectionSet.selections), []);
3005 const deduplicatedFragmentSelection = deduplicateSelection(fragmentSelections);
3006 return {
3007 kind: Kind.INLINE_FRAGMENT,
3008 typeCondition: {
3009 kind: Kind.NAMED_TYPE,
3010 name: {
3011 kind: Kind.NAME,
3012 value: type,
3013 },
3014 },
3015 selectionSet: {
3016 kind: Kind.SELECTION_SET,
3017 selections: deduplicatedFragmentSelection,
3018 },
3019 };
3020}
3021function deduplicateSelection(nodes) {
3022 const selectionMap = nodes.reduce((map, node) => {
3023 switch (node.kind) {
3024 case 'Field': {
3025 if (node.alias != null) {
3026 if (node.alias.value in map) {
3027 return map;
3028 }
3029 return {
3030 ...map,
3031 [node.alias.value]: node,
3032 };
3033 }
3034 if (node.name.value in map) {
3035 return map;
3036 }
3037 return {
3038 ...map,
3039 [node.name.value]: node,
3040 };
3041 }
3042 case 'FragmentSpread': {
3043 if (node.name.value in map) {
3044 return map;
3045 }
3046 return {
3047 ...map,
3048 [node.name.value]: node,
3049 };
3050 }
3051 case 'InlineFragment': {
3052 if (map.__fragment != null) {
3053 const fragment = map.__fragment;
3054 return {
3055 ...map,
3056 __fragment: concatInlineFragments(fragment.typeCondition.name.value, [fragment, node]),
3057 };
3058 }
3059 return {
3060 ...map,
3061 __fragment: node,
3062 };
3063 }
3064 default: {
3065 return map;
3066 }
3067 }
3068 }, Object.create(null));
3069 const selection = Object.keys(selectionMap).reduce((selectionList, node) => selectionList.concat(selectionMap[node]), []);
3070 return selection;
3071}
3072function parseFragmentToInlineFragment(definitions) {
3073 if (definitions.trim().startsWith('fragment')) {
3074 const document = parse(definitions);
3075 for (const definition of document.definitions) {
3076 if (definition.kind === Kind.FRAGMENT_DEFINITION) {
3077 return {
3078 kind: Kind.INLINE_FRAGMENT,
3079 typeCondition: definition.typeCondition,
3080 selectionSet: definition.selectionSet,
3081 };
3082 }
3083 }
3084 }
3085 const query = parse(`{${definitions}}`).definitions[0];
3086 for (const selection of query.selectionSet.selections) {
3087 if (selection.kind === Kind.INLINE_FRAGMENT) {
3088 return selection;
3089 }
3090 }
3091 throw new Error('Could not parse fragment');
3092}
3093
3094function parseSelectionSet(selectionSet) {
3095 const query = parse(selectionSet).definitions[0];
3096 return query.selectionSet;
3097}
3098function typeContainsSelectionSet(type, selectionSet) {
3099 const fields = type.getFields();
3100 for (const selection of selectionSet.selections) {
3101 if (selection.kind === Kind.FIELD) {
3102 const field = fields[selection.name.value];
3103 if (field == null) {
3104 return false;
3105 }
3106 if (selection.selectionSet != null) {
3107 return typeContainsSelectionSet(getNamedType(field.type), selection.selectionSet);
3108 }
3109 }
3110 else if (selection.kind === Kind.INLINE_FRAGMENT) {
3111 const containsSelectionSet = typeContainsSelectionSet(type, selection.selectionSet);
3112 if (!containsSelectionSet) {
3113 return false;
3114 }
3115 }
3116 }
3117 return true;
3118}
3119
3120/**
3121 * Get the key under which the result of this resolver will be placed in the response JSON. Basically, just
3122 * resolves aliases.
3123 * @param info The info argument to the resolver.
3124 */
3125function getResponseKeyFromInfo(info) {
3126 return info.fieldNodes[0].alias != null ? info.fieldNodes[0].alias.value : info.fieldName;
3127}
3128
3129function applySchemaTransforms(originalSchema, transforms) {
3130 return transforms.reduce((schema, transform) => transform.transformSchema != null ? transform.transformSchema(cloneSchema(schema)) : schema, originalSchema);
3131}
3132function applyRequestTransforms(originalRequest, transforms) {
3133 return transforms.reduce((request, transform) => transform.transformRequest != null ? transform.transformRequest(request) : request, originalRequest);
3134}
3135function applyResultTransforms(originalResult, transforms) {
3136 return transforms.reduceRight((result, transform) => transform.transformResult != null ? transform.transformResult(result) : result, originalResult);
3137}
3138
3139function appendObjectFields(schema, typeName, additionalFields) {
3140 if (schema.getType(typeName) == null) {
3141 return addTypes(schema, [
3142 new GraphQLObjectType({
3143 name: typeName,
3144 fields: additionalFields,
3145 }),
3146 ]);
3147 }
3148 return mapSchema(schema, {
3149 [MapperKind.OBJECT_TYPE]: type => {
3150 if (type.name === typeName) {
3151 const config = type.toConfig();
3152 const originalFieldConfigMap = config.fields;
3153 const newFieldConfigMap = {};
3154 Object.keys(originalFieldConfigMap).forEach(fieldName => {
3155 newFieldConfigMap[fieldName] = originalFieldConfigMap[fieldName];
3156 });
3157 Object.keys(additionalFields).forEach(fieldName => {
3158 newFieldConfigMap[fieldName] = additionalFields[fieldName];
3159 });
3160 return correctASTNodes(new GraphQLObjectType({
3161 ...config,
3162 fields: newFieldConfigMap,
3163 }));
3164 }
3165 },
3166 });
3167}
3168function removeObjectFields(schema, typeName, testFn) {
3169 const removedFields = {};
3170 const newSchema = mapSchema(schema, {
3171 [MapperKind.OBJECT_TYPE]: type => {
3172 if (type.name === typeName) {
3173 const config = type.toConfig();
3174 const originalFieldConfigMap = config.fields;
3175 const newFieldConfigMap = {};
3176 Object.keys(originalFieldConfigMap).forEach(fieldName => {
3177 const originalFieldConfig = originalFieldConfigMap[fieldName];
3178 if (testFn(fieldName, originalFieldConfig)) {
3179 removedFields[fieldName] = originalFieldConfig;
3180 }
3181 else {
3182 newFieldConfigMap[fieldName] = originalFieldConfig;
3183 }
3184 });
3185 return correctASTNodes(new GraphQLObjectType({
3186 ...config,
3187 fields: newFieldConfigMap,
3188 }));
3189 }
3190 },
3191 });
3192 return [newSchema, removedFields];
3193}
3194function selectObjectFields(schema, typeName, testFn) {
3195 const selectedFields = {};
3196 mapSchema(schema, {
3197 [MapperKind.OBJECT_TYPE]: type => {
3198 if (type.name === typeName) {
3199 const config = type.toConfig();
3200 const originalFieldConfigMap = config.fields;
3201 Object.keys(originalFieldConfigMap).forEach(fieldName => {
3202 const originalFieldConfig = originalFieldConfigMap[fieldName];
3203 if (testFn(fieldName, originalFieldConfig)) {
3204 selectedFields[fieldName] = originalFieldConfig;
3205 }
3206 });
3207 }
3208 return undefined;
3209 },
3210 });
3211 return selectedFields;
3212}
3213function modifyObjectFields(schema, typeName, testFn, newFields) {
3214 const removedFields = {};
3215 const newSchema = mapSchema(schema, {
3216 [MapperKind.OBJECT_TYPE]: type => {
3217 if (type.name === typeName) {
3218 const config = type.toConfig();
3219 const originalFieldConfigMap = config.fields;
3220 const newFieldConfigMap = {};
3221 Object.keys(originalFieldConfigMap).forEach(fieldName => {
3222 const originalFieldConfig = originalFieldConfigMap[fieldName];
3223 if (testFn(fieldName, originalFieldConfig)) {
3224 removedFields[fieldName] = originalFieldConfig;
3225 }
3226 else {
3227 newFieldConfigMap[fieldName] = originalFieldConfig;
3228 }
3229 });
3230 Object.keys(newFields).forEach(fieldName => {
3231 const fieldConfig = newFields[fieldName];
3232 newFieldConfigMap[fieldName] = fieldConfig;
3233 });
3234 return correctASTNodes(new GraphQLObjectType({
3235 ...config,
3236 fields: newFieldConfigMap,
3237 }));
3238 }
3239 },
3240 });
3241 return [newSchema, removedFields];
3242}
3243
3244function renameType(type, newTypeName) {
3245 if (isObjectType(type)) {
3246 return new GraphQLObjectType({
3247 ...type.toConfig(),
3248 name: newTypeName,
3249 astNode: type.astNode == null
3250 ? type.astNode
3251 : {
3252 ...type.astNode,
3253 name: {
3254 ...type.astNode.name,
3255 value: newTypeName,
3256 },
3257 },
3258 extensionASTNodes: type.extensionASTNodes == null
3259 ? type.extensionASTNodes
3260 : type.extensionASTNodes.map(node => ({
3261 ...node,
3262 name: {
3263 ...node.name,
3264 value: newTypeName,
3265 },
3266 })),
3267 });
3268 }
3269 else if (isInterfaceType(type)) {
3270 return new GraphQLInterfaceType({
3271 ...type.toConfig(),
3272 name: newTypeName,
3273 astNode: type.astNode == null
3274 ? type.astNode
3275 : {
3276 ...type.astNode,
3277 name: {
3278 ...type.astNode.name,
3279 value: newTypeName,
3280 },
3281 },
3282 extensionASTNodes: type.extensionASTNodes == null
3283 ? type.extensionASTNodes
3284 : type.extensionASTNodes.map(node => ({
3285 ...node,
3286 name: {
3287 ...node.name,
3288 value: newTypeName,
3289 },
3290 })),
3291 });
3292 }
3293 else if (isUnionType(type)) {
3294 return new GraphQLUnionType({
3295 ...type.toConfig(),
3296 name: newTypeName,
3297 astNode: type.astNode == null
3298 ? type.astNode
3299 : {
3300 ...type.astNode,
3301 name: {
3302 ...type.astNode.name,
3303 value: newTypeName,
3304 },
3305 },
3306 extensionASTNodes: type.extensionASTNodes == null
3307 ? type.extensionASTNodes
3308 : type.extensionASTNodes.map(node => ({
3309 ...node,
3310 name: {
3311 ...node.name,
3312 value: newTypeName,
3313 },
3314 })),
3315 });
3316 }
3317 else if (isInputObjectType(type)) {
3318 return new GraphQLInputObjectType({
3319 ...type.toConfig(),
3320 name: newTypeName,
3321 astNode: type.astNode == null
3322 ? type.astNode
3323 : {
3324 ...type.astNode,
3325 name: {
3326 ...type.astNode.name,
3327 value: newTypeName,
3328 },
3329 },
3330 extensionASTNodes: type.extensionASTNodes == null
3331 ? type.extensionASTNodes
3332 : type.extensionASTNodes.map(node => ({
3333 ...node,
3334 name: {
3335 ...node.name,
3336 value: newTypeName,
3337 },
3338 })),
3339 });
3340 }
3341 else if (isEnumType(type)) {
3342 return new GraphQLEnumType({
3343 ...type.toConfig(),
3344 name: newTypeName,
3345 astNode: type.astNode == null
3346 ? type.astNode
3347 : {
3348 ...type.astNode,
3349 name: {
3350 ...type.astNode.name,
3351 value: newTypeName,
3352 },
3353 },
3354 extensionASTNodes: type.extensionASTNodes == null
3355 ? type.extensionASTNodes
3356 : type.extensionASTNodes.map(node => ({
3357 ...node,
3358 name: {
3359 ...node.name,
3360 value: newTypeName,
3361 },
3362 })),
3363 });
3364 }
3365 else if (isScalarType(type)) {
3366 return new GraphQLScalarType({
3367 ...type.toConfig(),
3368 name: newTypeName,
3369 astNode: type.astNode == null
3370 ? type.astNode
3371 : {
3372 ...type.astNode,
3373 name: {
3374 ...type.astNode.name,
3375 value: newTypeName,
3376 },
3377 },
3378 extensionASTNodes: type.extensionASTNodes == null
3379 ? type.extensionASTNodes
3380 : type.extensionASTNodes.map(node => ({
3381 ...node,
3382 name: {
3383 ...node.name,
3384 value: newTypeName,
3385 },
3386 })),
3387 });
3388 }
3389 throw new Error(`Unknown type ${type}.`);
3390}
3391
3392/**
3393 * Given a selectionSet, adds all of the fields in that selection to
3394 * the passed in map of fields, and returns it at the end.
3395 *
3396 * CollectFields requires the "runtime type" of an object. For a field which
3397 * returns an Interface or Union type, the "runtime type" will be the actual
3398 * Object type returned by that field.
3399 *
3400 * @internal
3401 */
3402function collectFields$1(exeContext, runtimeType, selectionSet, fields, visitedFragmentNames) {
3403 for (const selection of selectionSet.selections) {
3404 switch (selection.kind) {
3405 case Kind.FIELD: {
3406 if (!shouldIncludeNode(exeContext, selection)) {
3407 continue;
3408 }
3409 const name = getFieldEntryKey(selection);
3410 if (!(name in fields)) {
3411 fields[name] = [];
3412 }
3413 fields[name].push(selection);
3414 break;
3415 }
3416 case Kind.INLINE_FRAGMENT: {
3417 if (!shouldIncludeNode(exeContext, selection) ||
3418 !doesFragmentConditionMatch(exeContext, selection, runtimeType)) {
3419 continue;
3420 }
3421 collectFields$1(exeContext, runtimeType, selection.selectionSet, fields, visitedFragmentNames);
3422 break;
3423 }
3424 case Kind.FRAGMENT_SPREAD: {
3425 const fragName = selection.name.value;
3426 if (visitedFragmentNames[fragName] || !shouldIncludeNode(exeContext, selection)) {
3427 continue;
3428 }
3429 visitedFragmentNames[fragName] = true;
3430 const fragment = exeContext.fragments[fragName];
3431 if (!fragment || !doesFragmentConditionMatch(exeContext, fragment, runtimeType)) {
3432 continue;
3433 }
3434 collectFields$1(exeContext, runtimeType, fragment.selectionSet, fields, visitedFragmentNames);
3435 break;
3436 }
3437 }
3438 }
3439 return fields;
3440}
3441/**
3442 * Determines if a field should be included based on the @include and @skip
3443 * directives, where @skip has higher precedence than @include.
3444 */
3445function shouldIncludeNode(exeContext, node) {
3446 const skip = getDirectiveValues$1(GraphQLSkipDirective, node, exeContext.variableValues);
3447 if ((skip === null || skip === void 0 ? void 0 : skip.if) === true) {
3448 return false;
3449 }
3450 const include = getDirectiveValues$1(GraphQLIncludeDirective, node, exeContext.variableValues);
3451 if ((include === null || include === void 0 ? void 0 : include.if) === false) {
3452 return false;
3453 }
3454 return true;
3455}
3456/**
3457 * Determines if a fragment is applicable to the given type.
3458 */
3459function doesFragmentConditionMatch(exeContext, fragment, type) {
3460 const typeConditionNode = fragment.typeCondition;
3461 if (!typeConditionNode) {
3462 return true;
3463 }
3464 const conditionalType = typeFromAST(exeContext.schema, typeConditionNode);
3465 if (conditionalType === type) {
3466 return true;
3467 }
3468 if (isAbstractType(conditionalType)) {
3469 return exeContext.schema.isPossibleType(conditionalType, type);
3470 }
3471 return false;
3472}
3473/**
3474 * Implements the logic to compute the key of a given field's entry
3475 */
3476function getFieldEntryKey(node) {
3477 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
3478 return node.alias ? node.alias.value : node.name.value;
3479}
3480
3481/**
3482 * Given an AsyncIterable and a callback function, return an AsyncIterator
3483 * which produces values mapped via calling the callback function.
3484 */
3485function mapAsyncIterator(iterator, callback, rejectCallback) {
3486 let $return;
3487 let abruptClose;
3488 if (typeof iterator.return === 'function') {
3489 $return = iterator.return;
3490 abruptClose = (error) => {
3491 const rethrow = () => Promise.reject(error);
3492 return $return.call(iterator).then(rethrow, rethrow);
3493 };
3494 }
3495 function mapResult(result) {
3496 return result.done ? result : asyncMapValue(result.value, callback).then(iteratorResult, abruptClose);
3497 }
3498 let mapReject;
3499 if (rejectCallback) {
3500 // Capture rejectCallback to ensure it cannot be null.
3501 const reject = rejectCallback;
3502 mapReject = (error) => asyncMapValue(error, reject).then(iteratorResult, abruptClose);
3503 }
3504 return {
3505 next() {
3506 return iterator.next().then(mapResult, mapReject);
3507 },
3508 return() {
3509 return $return
3510 ? $return.call(iterator).then(mapResult, mapReject)
3511 : Promise.resolve({ value: undefined, done: true });
3512 },
3513 throw(error) {
3514 if (typeof iterator.throw === 'function') {
3515 return iterator.throw(error).then(mapResult, mapReject);
3516 }
3517 return Promise.reject(error).catch(abruptClose);
3518 },
3519 [Symbol.asyncIterator]() {
3520 return this;
3521 },
3522 };
3523}
3524function asyncMapValue(value, callback) {
3525 return new Promise(resolve => resolve(callback(value)));
3526}
3527function iteratorResult(value) {
3528 return { value, done: false };
3529}
3530
3531function astFromType(type) {
3532 if (isNonNullType(type)) {
3533 const innerType = astFromType(type.ofType);
3534 if (innerType.kind === Kind.NON_NULL_TYPE) {
3535 throw new Error(`Invalid type node ${JSON.stringify(type)}. Inner type of non-null type cannot be a non-null type.`);
3536 }
3537 return {
3538 kind: Kind.NON_NULL_TYPE,
3539 type: innerType,
3540 };
3541 }
3542 else if (isListType(type)) {
3543 return {
3544 kind: Kind.LIST_TYPE,
3545 type: astFromType(type.ofType),
3546 };
3547 }
3548 return {
3549 kind: Kind.NAMED_TYPE,
3550 name: {
3551 kind: Kind.NAME,
3552 value: type.name,
3553 },
3554 };
3555}
3556
3557function updateArgument(argName, argType, argumentNodes, variableDefinitionsMap, variableValues, newArg) {
3558 let varName;
3559 let numGeneratedVariables = 0;
3560 do {
3561 varName = `_v${(numGeneratedVariables++).toString()}_${argName}`;
3562 } while (varName in variableDefinitionsMap);
3563 argumentNodes[argName] = {
3564 kind: Kind.ARGUMENT,
3565 name: {
3566 kind: Kind.NAME,
3567 value: argName,
3568 },
3569 value: {
3570 kind: Kind.VARIABLE,
3571 name: {
3572 kind: Kind.NAME,
3573 value: varName,
3574 },
3575 },
3576 };
3577 variableDefinitionsMap[varName] = {
3578 kind: Kind.VARIABLE_DEFINITION,
3579 variable: {
3580 kind: Kind.VARIABLE,
3581 name: {
3582 kind: Kind.NAME,
3583 value: varName,
3584 },
3585 },
3586 type: astFromType(argType),
3587 };
3588 if (newArg === undefined) {
3589 delete variableValues[varName];
3590 }
3591 else {
3592 variableValues[varName] = newArg;
3593 }
3594}
3595
3596function implementsAbstractType(schema, typeA, typeB) {
3597 if (typeA === typeB) {
3598 return true;
3599 }
3600 else if (isCompositeType(typeA) && isCompositeType(typeB)) {
3601 return doTypesOverlap(schema, typeA, typeB);
3602 }
3603 return false;
3604}
3605
3606const ERROR_SYMBOL = Symbol('subschemaErrors');
3607function relocatedError(originalError, path) {
3608 return new GraphQLError(originalError.message, originalError.nodes, originalError.source, originalError.positions, path === null ? undefined : path === undefined ? originalError.path : path, originalError.originalError, originalError.extensions);
3609}
3610function slicedError(originalError) {
3611 return relocatedError(originalError, originalError.path != null ? originalError.path.slice(1) : undefined);
3612}
3613function getErrorsByPathSegment(errors) {
3614 const record = Object.create(null);
3615 errors.forEach(error => {
3616 if (!error.path || error.path.length < 2) {
3617 return;
3618 }
3619 const pathSegment = error.path[1];
3620 const current = pathSegment in record ? record[pathSegment] : [];
3621 current.push(slicedError(error));
3622 record[pathSegment] = current;
3623 });
3624 return record;
3625}
3626function setErrors(result, errors) {
3627 result[ERROR_SYMBOL] = errors;
3628}
3629function getErrors(result, pathSegment) {
3630 const errors = result != null ? result[ERROR_SYMBOL] : result;
3631 if (!Array.isArray(errors)) {
3632 return null;
3633 }
3634 const fieldErrors = [];
3635 for (const error of errors) {
3636 if (!error.path || error.path[0] === pathSegment) {
3637 fieldErrors.push(error);
3638 }
3639 }
3640 return fieldErrors;
3641}
3642
3643function inputFieldToFieldConfig(field) {
3644 return {
3645 description: field.description,
3646 type: field.type,
3647 defaultValue: field.defaultValue,
3648 extensions: field.extensions,
3649 astNode: field.astNode,
3650 };
3651}
3652function fieldToFieldConfig(field) {
3653 return {
3654 description: field.description,
3655 type: field.type,
3656 args: argsToFieldConfigArgumentMap(field.args),
3657 resolve: field.resolve,
3658 subscribe: field.subscribe,
3659 deprecationReason: field.deprecationReason,
3660 extensions: field.extensions,
3661 astNode: field.astNode,
3662 };
3663}
3664function argsToFieldConfigArgumentMap(args) {
3665 const newArguments = {};
3666 args.forEach(arg => {
3667 newArguments[arg.name] = argumentToArgumentConfig(arg);
3668 });
3669 return newArguments;
3670}
3671function argumentToArgumentConfig(arg) {
3672 return {
3673 description: arg.description,
3674 type: arg.type,
3675 defaultValue: arg.defaultValue,
3676 extensions: arg.extensions,
3677 astNode: arg.astNode,
3678 };
3679}
3680
3681function observableToAsyncIterable(observable) {
3682 const pullQueue = [];
3683 const pushQueue = [];
3684 let listening = true;
3685 const pushValue = (value) => {
3686 if (pullQueue.length !== 0) {
3687 pullQueue.shift()({ value, done: false });
3688 }
3689 else {
3690 pushQueue.push({ value });
3691 }
3692 };
3693 const pushError = (error) => {
3694 if (pullQueue.length !== 0) {
3695 pullQueue.shift()({ value: { errors: [error] }, done: false });
3696 }
3697 else {
3698 pushQueue.push({ value: { errors: [error] } });
3699 }
3700 };
3701 const pullValue = () => new Promise(resolve => {
3702 if (pushQueue.length !== 0) {
3703 const element = pushQueue.shift();
3704 // either {value: {errors: [...]}} or {value: ...}
3705 resolve({
3706 ...element,
3707 done: false,
3708 });
3709 }
3710 else {
3711 pullQueue.push(resolve);
3712 }
3713 });
3714 const subscription = observable.subscribe({
3715 next(value) {
3716 pushValue(value);
3717 },
3718 error(err) {
3719 pushError(err);
3720 },
3721 });
3722 const emptyQueue = () => {
3723 if (listening) {
3724 listening = false;
3725 subscription.unsubscribe();
3726 pullQueue.forEach(resolve => resolve({ value: undefined, done: true }));
3727 pullQueue.length = 0;
3728 pushQueue.length = 0;
3729 }
3730 };
3731 return {
3732 next() {
3733 return listening ? pullValue() : this.return();
3734 },
3735 return() {
3736 emptyQueue();
3737 return Promise.resolve({ value: undefined, done: true });
3738 },
3739 throw(error) {
3740 emptyQueue();
3741 return Promise.reject(error);
3742 },
3743 [Symbol.asyncIterator]() {
3744 return this;
3745 },
3746 };
3747}
3748
3749function visitData(data, enter, leave) {
3750 if (Array.isArray(data)) {
3751 return data.map(value => visitData(value, enter, leave));
3752 }
3753 else if (typeof data === 'object') {
3754 const newData = enter != null ? enter(data) : data;
3755 if (newData != null) {
3756 Object.keys(newData).forEach(key => {
3757 const value = newData[key];
3758 newData[key] = visitData(value, enter, leave);
3759 });
3760 }
3761 return leave != null ? leave(newData) : newData;
3762 }
3763 return data;
3764}
3765function visitErrors(errors, visitor) {
3766 return errors.map(error => visitor(error));
3767}
3768function visitResult(result, request, schema, resultVisitorMap, errorVisitorMap) {
3769 const partialExecutionContext = {
3770 schema,
3771 fragments: request.document.definitions.reduce((acc, def) => {
3772 if (def.kind === Kind.FRAGMENT_DEFINITION) {
3773 acc[def.name.value] = def;
3774 }
3775 return acc;
3776 }, {}),
3777 variableValues: request.variables,
3778 };
3779 const errorInfo = {
3780 segmentInfoMap: new Map(),
3781 unpathedErrors: [],
3782 };
3783 const data = result.data;
3784 const errors = result.errors;
3785 const visitingErrors = errors != null && errorVisitorMap != null;
3786 if (data != null) {
3787 result.data = visitRoot(data, getOperationAST(request.document, undefined), partialExecutionContext, resultVisitorMap, visitingErrors ? errors : undefined, errorInfo);
3788 }
3789 if (visitingErrors) {
3790 result.errors = visitErrorsByType(errors, errorVisitorMap, errorInfo);
3791 }
3792 return result;
3793}
3794function visitErrorsByType(errors, errorVisitorMap, errorInfo) {
3795 return errors.map(error => {
3796 const pathSegmentsInfo = errorInfo.segmentInfoMap.get(error);
3797 if (pathSegmentsInfo == null) {
3798 return error;
3799 }
3800 return pathSegmentsInfo.reduceRight((acc, segmentInfo) => {
3801 const typeName = segmentInfo.type.name;
3802 const typeVisitorMap = errorVisitorMap[typeName];
3803 if (typeVisitorMap == null) {
3804 return acc;
3805 }
3806 const errorVisitor = typeVisitorMap[segmentInfo.fieldName];
3807 return errorVisitor == null ? acc : errorVisitor(acc, segmentInfo.pathIndex);
3808 }, error);
3809 });
3810}
3811function visitRoot(root, operation, exeContext, resultVisitorMap, errors, errorInfo) {
3812 const operationRootType = getOperationRootType(exeContext.schema, operation);
3813 const collectedFields = collectFields$1(exeContext, operationRootType, operation.selectionSet, Object.create(null), Object.create(null));
3814 return visitObjectValue(root, operationRootType, collectedFields, exeContext, resultVisitorMap, 0, errors, errorInfo);
3815}
3816function visitObjectValue(object, type, fieldNodeMap, exeContext, resultVisitorMap, pathIndex, errors, errorInfo) {
3817 const fieldMap = type.getFields();
3818 const typeVisitorMap = resultVisitorMap === null || resultVisitorMap === void 0 ? void 0 : resultVisitorMap[type.name];
3819 const enterObject = typeVisitorMap === null || typeVisitorMap === void 0 ? void 0 : typeVisitorMap.__enter;
3820 const newObject = enterObject != null ? enterObject(object) : object;
3821 let sortedErrors;
3822 let errorMap;
3823 if (errors != null) {
3824 sortedErrors = sortErrorsByPathSegment(errors, pathIndex);
3825 errorMap = sortedErrors.errorMap;
3826 errorInfo.unpathedErrors = errorInfo.unpathedErrors.concat(sortedErrors.unpathedErrors);
3827 }
3828 Object.keys(fieldNodeMap).forEach(responseKey => {
3829 const subFieldNodes = fieldNodeMap[responseKey];
3830 const fieldName = subFieldNodes[0].name.value;
3831 const fieldType = fieldMap[fieldName].type;
3832 const newPathIndex = pathIndex + 1;
3833 let fieldErrors;
3834 if (errors != null) {
3835 fieldErrors = errorMap[responseKey];
3836 if (fieldErrors != null) {
3837 delete errorMap[responseKey];
3838 }
3839 addPathSegmentInfo(type, fieldName, newPathIndex, fieldErrors, errorInfo);
3840 }
3841 const newValue = visitFieldValue(object[responseKey], fieldType, subFieldNodes, exeContext, resultVisitorMap, newPathIndex, fieldErrors, errorInfo);
3842 updateObject(newObject, responseKey, newValue, typeVisitorMap, fieldName);
3843 });
3844 const oldTypename = newObject.__typename;
3845 if (oldTypename != null) {
3846 updateObject(newObject, '__typename', oldTypename, typeVisitorMap, '__typename');
3847 }
3848 if (errors != null) {
3849 Object.keys(errorMap).forEach(unknownResponseKey => {
3850 errorInfo.unpathedErrors = errorInfo.unpathedErrors.concat(errorMap[unknownResponseKey]);
3851 });
3852 }
3853 const leaveObject = typeVisitorMap === null || typeVisitorMap === void 0 ? void 0 : typeVisitorMap.__leave;
3854 return leaveObject != null ? leaveObject(newObject) : newObject;
3855}
3856function updateObject(object, responseKey, newValue, typeVisitorMap, fieldName) {
3857 if (typeVisitorMap == null) {
3858 object[responseKey] = newValue;
3859 return;
3860 }
3861 const fieldVisitor = typeVisitorMap[fieldName];
3862 if (fieldVisitor == null) {
3863 object[responseKey] = newValue;
3864 return;
3865 }
3866 const visitedValue = fieldVisitor(newValue);
3867 if (visitedValue === undefined) {
3868 delete object[responseKey];
3869 return;
3870 }
3871 object[responseKey] = visitedValue;
3872}
3873function visitListValue(list, returnType, fieldNodes, exeContext, resultVisitorMap, pathIndex, errors, errorInfo) {
3874 return list.map(listMember => visitFieldValue(listMember, returnType, fieldNodes, exeContext, resultVisitorMap, pathIndex + 1, errors, errorInfo));
3875}
3876function visitFieldValue(value, returnType, fieldNodes, exeContext, resultVisitorMap, pathIndex, errors = [], errorInfo) {
3877 if (value == null) {
3878 return value;
3879 }
3880 const nullableType = getNullableType(returnType);
3881 if (isListType(nullableType)) {
3882 return visitListValue(value, nullableType.ofType, fieldNodes, exeContext, resultVisitorMap, pathIndex, errors, errorInfo);
3883 }
3884 else if (isAbstractType(nullableType)) {
3885 const finalType = exeContext.schema.getType(value.__typename);
3886 const collectedFields = collectSubFields(exeContext, finalType, fieldNodes);
3887 return visitObjectValue(value, finalType, collectedFields, exeContext, resultVisitorMap, pathIndex, errors, errorInfo);
3888 }
3889 else if (isObjectType(nullableType)) {
3890 const collectedFields = collectSubFields(exeContext, nullableType, fieldNodes);
3891 return visitObjectValue(value, nullableType, collectedFields, exeContext, resultVisitorMap, pathIndex, errors, errorInfo);
3892 }
3893 const typeVisitorMap = resultVisitorMap === null || resultVisitorMap === void 0 ? void 0 : resultVisitorMap[nullableType.name];
3894 if (typeVisitorMap == null) {
3895 return value;
3896 }
3897 const visitedValue = typeVisitorMap(value);
3898 return visitedValue === undefined ? value : visitedValue;
3899}
3900function sortErrorsByPathSegment(errors, pathIndex) {
3901 const errorMap = Object.create(null);
3902 const unpathedErrors = [];
3903 errors.forEach(error => {
3904 var _a;
3905 const pathSegment = (_a = error.path) === null || _a === void 0 ? void 0 : _a[pathIndex];
3906 if (pathSegment == null) {
3907 unpathedErrors.push(error);
3908 return;
3909 }
3910 if (pathSegment in errorMap) {
3911 errorMap[pathSegment].push(error);
3912 }
3913 else {
3914 errorMap[pathSegment] = [error];
3915 }
3916 });
3917 return {
3918 errorMap,
3919 unpathedErrors,
3920 };
3921}
3922function addPathSegmentInfo(type, fieldName, pathIndex, errors = [], errorInfo) {
3923 errors.forEach(error => {
3924 const segmentInfo = {
3925 type,
3926 fieldName,
3927 pathIndex,
3928 };
3929 const pathSegmentsInfo = errorInfo.segmentInfoMap.get(error);
3930 if (pathSegmentsInfo == null) {
3931 errorInfo.segmentInfoMap.set(error, [segmentInfo]);
3932 }
3933 else {
3934 pathSegmentsInfo.push(segmentInfo);
3935 }
3936 });
3937}
3938function collectSubFields(exeContext, type, fieldNodes) {
3939 let subFieldNodes = Object.create(null);
3940 const visitedFragmentNames = Object.create(null);
3941 fieldNodes.forEach(fieldNode => {
3942 subFieldNodes = collectFields$1(exeContext, type, fieldNode.selectionSet, subFieldNodes, visitedFragmentNames);
3943 });
3944 return subFieldNodes;
3945}
3946
3947export { ERROR_SYMBOL, MapperKind, SchemaDirectiveVisitor, SchemaVisitor, VisitSchemaKind, addTypes, appendObjectFields, applyRequestTransforms, applyResultTransforms, applySchemaTransforms, argsToFieldConfigArgumentMap, argumentToArgumentConfig, asArray, buildOperationNodeForField, checkValidationErrors, cloneDirective, cloneSchema, cloneType, collectFields$1 as collectFields, compareNodes, compareStrings, concatInlineFragments, correctASTNodes, createNamedStub, createSchemaDefinition, createStub, debugLog, fieldToFieldConfig, filterSchema, fixSchemaAst, fixWindowsPath, flattenArray, forEachDefaultValue, forEachField, getBuiltInForStub, getDirectives, getErrors, getErrorsByPathSegment, getFieldsWithDirectives, getImplementingTypes, getResolversFromSchema, getResponseKeyFromInfo, getUserTypesFromSchema, healSchema, healTypes, hoistFieldNodes, implementsAbstractType, inputFieldToFieldConfig, isDocumentString, isEqual, isNamedStub, isNotEqual, isValidPath, mapAsyncIterator, mapSchema, mergeDeep, modifyObjectFields, nodeToString, observableToAsyncIterable, parseFragmentToInlineFragment, parseGraphQLJSON, parseGraphQLSDL, parseInputValue, parseInputValueLiteral, parseSelectionSet, preAliasFieldNode, printSchemaWithDirectives, pruneSchema, relocatedError, removeObjectFields, renameFieldNode, renameType, rewireTypes, selectObjectFields, serializeInputValue, setErrors, slicedError, transformInputValue, typeContainsSelectionSet, updateArgument, validateGraphQlDocuments, visitData, visitErrors, visitResult, visitSchema, wrapFieldNode };
3948//# sourceMappingURL=index.esm.js.map