text: "use strict";
  
  var _pagination = require("./types/pagination");
  
  var _sort = require("./types/sort");
  
  var _filter = require("./types/filter");
  
  var _typeBuilders = require("./types/type-builders");
  
  const _ = require(`lodash`);
  
  const invariant = require(`invariant`);
  
  const {
    isSpecifiedScalarType,
    isIntrospectionType,
    assertValidName,
    GraphQLNonNull,
    GraphQLList,
    GraphQLObjectType,
    GraphQLInterfaceType,
    GraphQLUnionType
  } = require(`graphql`);
  
  const {
    ObjectTypeComposer,
    InterfaceTypeComposer,
    UnionTypeComposer,
    InputTypeComposer,
    ScalarTypeComposer,
    EnumTypeComposer
  } = require(`graphql-compose`);
  
  const {
    getDataStore,
    getNode,
    getNodesByType
  } = require(`../datastore`);
  
  const apiRunner = require(`../utils/api-runner-node`);
  
  const report = require(`gatsby-cli/lib/reporter`);
  
  const {
    addNodeInterfaceFields
  } = require(`./types/node-interface`);
  
  const {
    overridableBuiltInTypeNames
  } = require(`./types/built-in-types`);
  
  const {
    addInferredTypes
  } = require(`./infer`);
  
  const {
    findOne,
    findManyPaginated,
    wrappingResolver,
    defaultResolver
  } = require(`./resolvers`);
  
  const {
    processFieldExtensions,
    internalExtensionNames
  } = require(`./extensions`);
  
  const {
    isASTDocument,
    parseTypeDef,
    reportParsingError
  } = require(`./types/type-defs`);
  
  const {
    printTypeDefinitions
  } = require(`./print`);
  
  const buildSchema = async ({
    schemaComposer,
    types,
    typeMapping,
    fieldExtensions,
    thirdPartySchemas,
    printConfig,
    enginePrintConfig,
    typeConflictReporter,
    inferenceMetadata,
    parentSpan
  }) => {
    // FIXME: consider removing .ready here - it is needed for various tests to pass (although probably harmless)
    await getDataStore().ready();
    await updateSchemaComposer({
      schemaComposer,
      types,
      typeMapping,
      fieldExtensions,
      thirdPartySchemas,
      printConfig,
      enginePrintConfig,
      typeConflictReporter,
      inferenceMetadata,
      parentSpan
    }); // const { printSchema } = require(`graphql`)
  
    const schema = schemaComposer.buildSchema();
    freezeTypeComposers(schemaComposer); // console.log(printSchema(schema))
  
    return schema;
  };
  
  module.exports = {
    buildSchema
  }; // Workaround for https://github.com/graphql-compose/graphql-compose/issues/319
  //  FIXME: remove this when fixed in graphql-compose
  
  const freezeTypeComposers = (schemaComposer, excluded = new Set()) => {
    Array.from(schemaComposer.values()).forEach(tc => {
      const isCompositeTC = tc instanceof ObjectTypeComposer || tc instanceof InterfaceTypeComposer;
  
      if (isCompositeTC && !excluded.has(tc.getTypeName())) {
        // typeComposer.getType() actually mutates the underlying GraphQL type
        //   and always re-assigns type._fields with a thunk.
        //   It causes continuous redundant field re-definitions when running queries
        //   (affects performance significantly).
        //   Prevent the mutation and "freeze" the type:
        const type = tc.getType();
  
        tc.getType = () => type;
      }
    });
  };
  
  const updateSchemaComposer = async ({
    schemaComposer,
    types,
    typeMapping,
    fieldExtensions,
    thirdPartySchemas,
    printConfig,
    enginePrintConfig,
    typeConflictReporter,
    inferenceMetadata,
    parentSpan
  }) => {
    let activity = report.phantomActivity(`Add explicit types`, {
      parentSpan: parentSpan
    });
    activity.start();
    await addTypes({
      schemaComposer,
      parentSpan: activity.span,
      types
    });
    activity.end();
    activity = report.phantomActivity(`Add inferred types`, {
      parentSpan: parentSpan
    });
    activity.start();
    await addInferredTypes({
      schemaComposer,
      typeConflictReporter,
      typeMapping,
      inferenceMetadata,
      parentSpan: activity.span
    });
    addInferredChildOfExtensions({
      schemaComposer
    });
    activity.end();
    activity = report.phantomActivity(`Processing types`, {
      parentSpan: parentSpan
    });
    activity.start();
  
    if (!process.env.GATSBY_SKIP_WRITING_SCHEMA_TO_FILE) {
      await printTypeDefinitions({
        config: printConfig,
        schemaComposer,
        parentSpan: activity.span
      });
  
      if (enginePrintConfig) {
        // make sure to print schema that will be used when bundling graphql-engine
        await printTypeDefinitions({
          config: enginePrintConfig,
          schemaComposer,
          parentSpan: activity.span
        });
      }
    }
  
    await addSetFieldsOnGraphQLNodeTypeFields({
      schemaComposer,
      parentSpan: activity.span
    });
    await addConvenienceChildrenFields({
      schemaComposer,
      parentSpan: activity.span
    });
    await Promise.all(Array.from(new Set(schemaComposer.values())).map(typeComposer => processTypeComposer({
      schemaComposer,
      typeComposer,
      fieldExtensions,
      parentSpan: activity.span
    })));
    checkQueryableInterfaces({
      schemaComposer,
      parentSpan: activity.span
    });
    await addThirdPartySchemas({
      schemaComposer,
      thirdPartySchemas,
      parentSpan: activity.span
    });
    await addCustomResolveFunctions({
      schemaComposer,
      parentSpan: activity.span
    });
    attachTracingResolver({
      schemaComposer,
      parentSpan: activity.span
    });
    activity.end();
  };
  
  const processTypeComposer = async ({
    schemaComposer,
    typeComposer,
    fieldExtensions,
    parentSpan
  }) => {
    if (typeComposer instanceof ObjectTypeComposer) {
      await processFieldExtensions({
        schemaComposer,
        typeComposer,
        fieldExtensions,
        parentSpan
      });
  
      if (typeComposer.hasInterface(`Node`)) {
        await addNodeInterfaceFields({
          schemaComposer,
          typeComposer,
          parentSpan
        });
      }
  
      await determineSearchableFields({
        schemaComposer,
        typeComposer,
        parentSpan
      });
  
      if (typeComposer.hasInterface(`Node`)) {
        await addTypeToRootQuery({
          schemaComposer,
          typeComposer,
          parentSpan
        });
      }
    } else if (typeComposer instanceof InterfaceTypeComposer) {
      if (isNodeInterface(typeComposer)) {
        await addNodeInterfaceFields({
          schemaComposer,
          typeComposer,
          parentSpan
        }); // We only process field extensions for queryable Node interfaces, so we get
        // the input args on the root query type, e.g. `formatString` etc. for `dateformat`
  
        await processFieldExtensions({
          schemaComposer,
          typeComposer,
          fieldExtensions,
          parentSpan
        });
        await determineSearchableFields({
          schemaComposer,
          typeComposer,
          parentSpan
        });
        await addTypeToRootQuery({
          schemaComposer,
          typeComposer,
          parentSpan
        });
      }
    }
  };
  
  const fieldNames = {
    query: typeName => _.camelCase(typeName),
    queryAll: typeName => _.camelCase(`all ${typeName}`),
    convenienceChild: typeName => _.camelCase(`child ${typeName}`),
    convenienceChildren: typeName => _.camelCase(`children ${typeName}`)
  };
  
  const addTypes = ({
    schemaComposer,
    types,
    parentSpan
  }) => {
    types.forEach(({
      typeOrTypeDef,
      plugin
    }) => {
      if (typeof typeOrTypeDef === `string`) {
        typeOrTypeDef = parseTypeDef(typeOrTypeDef);
      }
  
      if (isASTDocument(typeOrTypeDef)) {
        let parsedTypes;
        const createdFrom = `sdl`;
  
        try {
          parsedTypes = parseTypes({
            doc: typeOrTypeDef,
            plugin,
            createdFrom,
            schemaComposer,
            parentSpan
          });
        } catch (error) {
          reportParsingError(error);
          return;
        }
  
        parsedTypes.forEach(type => {
          processAddedType({
            schemaComposer,
            type,
            parentSpan,
            createdFrom,
            plugin
          });
        });
      } else if ((0, _typeBuilders.isGatsbyType)(typeOrTypeDef)) {
        const type = createTypeComposerFromGatsbyType({
          schemaComposer,
          type: typeOrTypeDef,
          parentSpan
        });
  
        if (type) {
          const typeName = type.getTypeName();
          const createdFrom = `typeBuilder`;
          checkIsAllowedTypeName(typeName);
  
          if (schemaComposer.has(typeName)) {
            const typeComposer = schemaComposer.get(typeName);
            mergeTypes({
              schemaComposer,
              typeComposer,
              type,
              plugin,
              createdFrom,
              parentSpan
            });
          } else {
            processAddedType({
              schemaComposer,
              type,
              parentSpan,
              createdFrom,
              plugin
            });
          }
        }
      } else {
        const typeName = typeOrTypeDef.name;
        const createdFrom = `graphql-js`;
        checkIsAllowedTypeName(typeName);
  
        if (schemaComposer.has(typeName)) {
          const typeComposer = schemaComposer.get(typeName);
          mergeTypes({
            schemaComposer,
            typeComposer,
            type: typeOrTypeDef,
            plugin,
            createdFrom,
            parentSpan
          });
        } else {
          processAddedType({
            schemaComposer,
            type: typeOrTypeDef,
            parentSpan,
            createdFrom,
            plugin
          });
        }
      }
    });
  };
  
  const mergeTypes = ({
    schemaComposer,
    typeComposer,
    type,
    plugin,
    createdFrom,
    parentSpan
  }) => {
    // The merge is considered safe when a user or a plugin owning the type extend this type
    // TODO: add proper conflicts detection and reporting (on the field level)
    const typeOwner = typeComposer.getExtension(`plugin`);
    const isOverridableBuiltInType = !typeOwner && overridableBuiltInTypeNames.has(typeComposer.getTypeName());
    const isSafeMerge = !plugin || plugin.name === `default-site-plugin` || plugin.name === typeOwner || typeComposer.hasExtension(`isPlaceholder`) || isOverridableBuiltInType;
  
    if (!isSafeMerge) {
      if (typeOwner) {
        report.warn(`Plugin \`${plugin.name}\` has customized the GraphQL type ` + `\`${typeComposer.getTypeName()}\`, which has already been defined ` + `by the plugin \`${typeOwner}\`. ` + `This could potentially cause conflicts.`);
      } else {
        report.warn(`Plugin \`${plugin.name}\` has customized the built-in Gatsby GraphQL type ` + `\`${typeComposer.getTypeName()}\`. ` + `This is allowed, but could potentially cause conflicts.`);
      }
    }
  
    if (type instanceof ObjectTypeComposer || type instanceof InterfaceTypeComposer || type instanceof GraphQLObjectType || type instanceof GraphQLInterfaceType) {
      mergeFields({
        typeComposer,
        fields: type.getFields()
      });
      type.getInterfaces().forEach(iface => typeComposer.addInterface(iface));
    }
  
    if (type instanceof GraphQLInterfaceType || type instanceof InterfaceTypeComposer || type instanceof GraphQLUnionType || type instanceof UnionTypeComposer) {
      mergeResolveType({
        typeComposer,
        type
      });
    }
  
    let extensions = {};
  
    if (isNamedTypeComposer(type)) {
      if (createdFrom === `sdl`) {
        extensions = convertDirectivesToExtensions(type, type.getDirectives());
      } else {
        typeComposer.extendExtensions(type.getExtensions());
      }
    }
  
    addExtensions({
      schemaComposer,
      typeComposer,
      extensions,
      plugin,
      createdFrom
    });
    return true;
  };
  
  const processAddedType = ({
    schemaComposer,
    type,
    parentSpan,
    createdFrom,
    plugin
  }) => {
    const typeName = schemaComposer.add(type);
    const typeComposer = schemaComposer.get(typeName);
  
    if (typeComposer instanceof InterfaceTypeComposer || typeComposer instanceof UnionTypeComposer) {
      if (!typeComposer.getResolveType()) {
        typeComposer.setResolveType(node => node.internal.type);
      }
    }
  
    schemaComposer.addSchemaMustHaveType(typeComposer);
    let extensions = {};
  
    if (createdFrom === `sdl`) {
      extensions = convertDirectivesToExtensions(typeComposer, typeComposer.getDirectives());
    }
  
    addExtensions({
      schemaComposer,
      typeComposer,
      extensions,
      plugin,
      createdFrom
    });
    return typeComposer;
  };
  /**
   * @param {import("graphql-compose").AnyTypeComposer} typeComposer
   * @param {Array<import("graphql-compose").Directive>} directives
   * @return {{infer?: boolean, mimeTypes?: { types: Array<string> }, childOf?: { types: Array<string> }, nodeInterface?: boolean}}
   */
  
  
  const convertDirectivesToExtensions = (typeComposer, directives) => {
    const extensions = {};
    directives.forEach(({
      name,
      args
    }) => {
      switch (name) {
        case `infer`:
        case `dontInfer`:
          {
            extensions[`infer`] = name === `infer`;
            break;
          }
  
        case `mimeTypes`:
          extensions[`mimeTypes`] = args;
          break;
  
        case `childOf`:
          extensions[`childOf`] = args;
          break;
  
        case `nodeInterface`:
          if (typeComposer instanceof InterfaceTypeComposer) {
            extensions[`nodeInterface`] = true;
          }
  
          break;
  
        default:
      }
    });
    return extensions;
  };
  
  const addExtensions = ({
    schemaComposer,
    typeComposer,
    extensions = {},
    plugin,
    createdFrom
  }) => {
    typeComposer.setExtension(`createdFrom`, createdFrom);
    typeComposer.setExtension(`plugin`, plugin ? plugin.name : null);
    typeComposer.extendExtensions(extensions);
  
    if (typeComposer instanceof InterfaceTypeComposer && isNodeInterface(typeComposer)) {
      const hasCorrectIdField = typeComposer.hasField(`id`) && typeComposer.getFieldType(`id`).toString() === `ID!`;
  
      if (!hasCorrectIdField) {
        report.panic(`Interfaces with the \`nodeInterface\` extension must have a field ` + `\`id\` of type \`ID!\`. Check the type definition of ` + `\`${typeComposer.getTypeName()}\`.`);
      }
    }
  
    if (typeComposer instanceof ObjectTypeComposer || typeComposer instanceof InterfaceTypeComposer || typeComposer instanceof InputTypeComposer) {
      typeComposer.getFieldNames().forEach(fieldName => {
        typeComposer.setFieldExtension(fieldName, `createdFrom`, createdFrom);
        typeComposer.setFieldExtension(fieldName, `plugin`, plugin ? plugin.name : null);
  
        if (createdFrom === `sdl`) {
          const directives = typeComposer.getFieldDirectives(fieldName);
          directives.forEach(({
            name,
            args
          }) => {
            typeComposer.setFieldExtension(fieldName, name, args);
          });
        } // Validate field extension args. `graphql-compose` already checks the
        // type of directive args in `parseDirectives`, but we want to check
        // extensions provided with type builders as well. Also, we warn if an
        // extension option was provided which does not exist in the field
        // extension definition.
  
  
        const fieldExtensions = typeComposer.getFieldExtensions(fieldName);
        const typeName = typeComposer.getTypeName();
        Object.keys(fieldExtensions).filter(name => !internalExtensionNames.includes(name)).forEach(name => {
          const args = fieldExtensions[name];
  
          if (!args || typeof args !== `object`) {
            report.error(`Field extension arguments must be provided as an object. ` + `Received "${args}" on \`${typeName}.${fieldName}\`.`);
            return;
          }
  
          try {
            const definition = schemaComposer.getDirective(name); // Handle `defaultValue` when not provided as directive
  
            definition.args.forEach(({
              name,
              defaultValue
            }) => {
              if (args[name] === undefined && defaultValue !== undefined) {
                args[name] = defaultValue;
              }
            });
            Object.keys(args).forEach(arg => {
              const argumentDef = definition.args.find(({
                name
              }) => name === arg);
  
              if (!argumentDef) {
                report.error(`Field extension \`${name}\` on \`${typeName}.${fieldName}\` ` + `has invalid argument \`${arg}\`.`);
                return;
              }
  
              const value = args[arg];
  
              try {
                validate(argumentDef.type, value);
              } catch (error) {
                report.error(`Field extension \`${name}\` on \`${typeName}.${fieldName}\` ` + `has argument \`${arg}\` with invalid value "${value}". ` + error.message);
              }
            });
          } catch (error) {
            report.error(`Field extension \`${name}\` on \`${typeName}.${fieldName}\` ` + `is not available.`);
          }
        });
      });
    }
  
    return typeComposer;
  };
  
  const checkIsAllowedTypeName = name => {
    invariant(name !== `Node`, `The GraphQL type \`Node\` is reserved for internal use.`);
    invariant(!name.endsWith(`FilterInput`) && !name.endsWith(`SortInput`), `GraphQL type names ending with "FilterInput" or "SortInput" are ` + `reserved for internal use. Please rename \`${name}\`.`);
    invariant(![`Boolean`, `Date`, `Float`, `ID`, `Int`, `JSON`, `String`].includes(name), `The GraphQL type \`${name}\` is reserved for internal use by ` + `built-in scalar types.`);
    assertValidName(name);
  };
  
  const createTypeComposerFromGatsbyType = ({
    schemaComposer,
    type,
    parentSpan
  }) => {
    let typeComposer;
  
    switch (type.kind) {
      case _typeBuilders.GatsbyGraphQLTypeKind.OBJECT:
        {
          typeComposer = ObjectTypeComposer.createTemp({ ...type.config,
            fields: () => schemaComposer.typeMapper.convertOutputFieldConfigMap(type.config.fields),
            interfaces: () => {
              if (type.config.interfaces) {
                return type.config.interfaces.map(iface => {
                  if (typeof iface === `string`) {
                    // Sadly, graphql-compose runs this function too early - before we have
                    // all of those interfaces actually created in the schema, so have to create
                    // a temporary placeholder composer :/
                    if (!schemaComposer.has(iface)) {
                      const tmpComposer = schemaComposer.createInterfaceTC(iface);
                      tmpComposer.setExtension(`isPlaceholder`, true);
                      return tmpComposer;
                    }
  
                    return schemaComposer.getIFTC(iface);
                  } else {
                    return iface;
                  }
                });
              } else {
                return [];
              }
            }
          });
          break;
        }
  
      case _typeBuilders.GatsbyGraphQLTypeKind.INPUT_OBJECT:
        {
          typeComposer = InputTypeComposer.createTemp({ ...type.config,
            fields: schemaComposer.typeMapper.convertInputFieldConfigMap(type.config.fields)
          });
          break;
        }
  
      case _typeBuilders.GatsbyGraphQLTypeKind.UNION:
        {
          typeComposer = UnionTypeComposer.createTemp({ ...type.config,
            types: () => {
              if (type.config.types) {
                return type.config.types.map(typeName => {
                  if (!schemaComposer.has(typeName)) {
                    // Sadly, graphql-compose runs this function too early - before we have
                    // all of those types actually created in the schema, so have to create
                    // a temporary placeholder composer :/
                    const tmpComposer = schemaComposer.createObjectTC(typeName);
                    tmpComposer.setExtension(`isPlaceholder`, true);
                    return tmpComposer;
                  }
  
                  return schemaComposer.getOTC(typeName);
                });
              } else {
                return [];
              }
            }
          });
          break;
        }
  
      case _typeBuilders.GatsbyGraphQLTypeKind.INTERFACE:
        {
          typeComposer = InterfaceTypeComposer.createTemp({ ...type.config,
            fields: () => schemaComposer.typeMapper.convertOutputFieldConfigMap(type.config.fields),
            interfaces: () => {
              if (type.config.interfaces) {
                return type.config.interfaces.map(iface => {
                  if (typeof iface === `string`) {
                    // Sadly, graphql-compose runs this function too early - before we have
                    // all of those interfaces actually created in the schema, so have to create
                    // a temporary placeholder composer :/
                    if (!schemaComposer.has(iface)) {
                      const tmpComposer = schemaComposer.createInterfaceTC(iface);
                      tmpComposer.setExtension(`isPlaceholder`, true);
                      return tmpComposer;
                    }
  
                    return schemaComposer.getIFTC(iface);
                  } else {
                    return iface;
                  }
                });
              } else {
                return [];
              }
            }
          });
          break;
        }
  
      case _typeBuilders.GatsbyGraphQLTypeKind.ENUM:
        {
          typeComposer = EnumTypeComposer.createTemp(type.config);
          break;
        }
  
      case _typeBuilders.GatsbyGraphQLTypeKind.SCALAR:
        {
          typeComposer = ScalarTypeComposer.createTemp(type.config);
          break;
        }
  
      default:
        {
          report.warn(`Illegal type definition: ${JSON.stringify(type.config)}`);
          typeComposer = null;
        }
    }
  
    if (typeComposer) {
      // Workaround for https://github.com/graphql-compose/graphql-compose/issues/311
      typeComposer.schemaComposer = schemaComposer;
    }
  
    return typeComposer;
  };
  
  const addSetFieldsOnGraphQLNodeTypeFields = ({
    schemaComposer,
    parentSpan
  }) => Promise.all(Array.from(schemaComposer.values()).map(async tc => {
    if (tc instanceof ObjectTypeComposer && tc.hasInterface(`Node`)) {
      const typeName = tc.getTypeName();
      const result = await apiRunner(`setFieldsOnGraphQLNodeType`, {
        type: {
          name: typeName,
  
          get nodes() {
            // TODO STRICT_MODE: return iterator instead of array
            return getNodesByType(typeName);
          }
  
        },
        traceId: `initial-setFieldsOnGraphQLNodeType`,
        parentSpan
      });
  
      if (result) {
        // NOTE: `setFieldsOnGraphQLNodeType` only allows setting
        // nested fields with a path as property name, i.e.
        // `{ 'frontmatter.published': 'Boolean' }`, but not in the form
        // `{ frontmatter: { published: 'Boolean' }}`
        result.forEach(fields => tc.addNestedFields(fields));
      }
    }
  }));
  
  const addThirdPartySchemas = ({
    schemaComposer,
    thirdPartySchemas,
    parentSpan
  }) => {
    thirdPartySchemas.forEach(schema => {
      const schemaQueryType = schema.getQueryType();
      const queryTC = schemaComposer.createTempTC(schemaQueryType);
      processThirdPartyTypeFields({
        typeComposer: queryTC,
        type: schemaQueryType,
        schemaQueryType
      });
      schemaComposer.Query.addFields(queryTC.getFields()); // Explicitly add the third-party schema's types, so they can be targeted
      // in `createResolvers` API.
  
      const types = schema.getTypeMap();
      Object.keys(types).forEach(typeName => {
        const type = types[typeName];
  
        if (type !== schemaQueryType && !isSpecifiedScalarType(type) && !isIntrospectionType(type) && type.name !== `Date` && type.name !== `JSON`) {
          const typeHasFields = type instanceof GraphQLObjectType || type instanceof GraphQLInterfaceType; // Workaround for an edge case typical for Relay Classic-compatible schemas.
          // For example, GitHub API contains this piece:
          //   type Query { relay: Query }
          // And gatsby-source-graphql transforms it to:
          //   type Query { github: GitHub }
          //   type GitHub { relay: Query }
          // The problem:
          //   schemaComposer.createTC(type) for type `GitHub` will eagerly create type composers
          //   for all fields (including `relay` and it's type: `Query` of the third-party schema)
          //   This unexpected `Query` composer messes up with our own Query type composer and produces duplicate types.
          //   The workaround is to make sure fields of the GitHub type are lazy and are evaluated only when
          //   this Query type is already replaced with our own root `Query` type (see processThirdPartyTypeFields):
  
          if (typeHasFields && typeof type._fields === `object`) {
            const fields = type._fields;
  
            type._fields = () => fields;
          } // ^^^ workaround done
  
  
          const typeComposer = schemaComposer.createTC(type);
  
          if (typeHasFields) {
            processThirdPartyTypeFields({
              typeComposer,
              type,
              schemaQueryType
            });
          }
  
          typeComposer.setExtension(`createdFrom`, `thirdPartySchema`);
          schemaComposer.addSchemaMustHaveType(typeComposer);
        }
      });
    });
  };
  
  const resetOverriddenThirdPartyTypeFields = ({
    typeComposer
  }) => {
    // The problem: createResolvers API mutates third party schema instance.
    //   For example it can add a new field referencing a type from our main schema
    //   Then if we rebuild the schema this old type instance will sneak into
    //   the new schema and produce the famous error:
    //   "Schema must contain uniquely named types but contains multiple types named X"
    // This function only affects schema rebuilding pathway.
    //   It cleans up artifacts created by the `createResolvers` API of the previous build
    //   so that we return the third party schema to its initial state (hence can safely re-add)
    // TODO: the right way to fix this would be not to mutate the third party schema in
    //   the first place. But unfortunately mutation happens in the `graphql-compose`
    //   and we don't have an easy way to avoid it without major rework
    typeComposer.getFieldNames().forEach(fieldName => {
      const createdFrom = typeComposer.getFieldExtension(fieldName, `createdFrom`);
  
      if (createdFrom === `createResolvers`) {
        typeComposer.removeField(fieldName);
        return;
      }
  
      const config = typeComposer.getFieldExtension(fieldName, `originalFieldConfig`);
  
      if (config) {
        typeComposer.removeField(fieldName);
        typeComposer.addFields({
          [fieldName]: config
        });
      }
    });
  };
  
  const processThirdPartyTypeFields = ({
    typeComposer,
    type,
    schemaQueryType
  }) => {
    // Fix for types that refer to Query. Thanks Relay Classic!
    const fields = type.getFields();
    Object.keys(fields).forEach(fieldName => {
      // Remove customization that we could have added via `createResolvers`
      // to make it work with schema rebuilding
      const fieldType = String(fields[fieldName].type);
  
      if (fieldType.replace(/[[\]!]/g, ``) === schemaQueryType.name) {
        typeComposer.extendField(fieldName, {
          type: fieldType.replace(schemaQueryType.name, `Query`)
        });
      }
    });
    resetOverriddenThirdPartyTypeFields({
      typeComposer
    });
  };
  
  const addCustomResolveFunctions = async ({
    schemaComposer,
    parentSpan
  }) => {
    const intermediateSchema = schemaComposer.buildSchema();
  
    const createResolvers = (resolvers, {
      ignoreNonexistentTypes = false
    } = {}) => {
      Object.keys(resolvers).forEach(typeName => {
        const fields = resolvers[typeName];
  
        if (schemaComposer.has(typeName)) {
          const tc = schemaComposer.getOTC(typeName);
          Object.keys(fields).forEach(fieldName => {
            const fieldConfig = fields[fieldName];
  
            if (tc.hasField(fieldName)) {
              const originalFieldConfig = tc.getFieldConfig(fieldName);
              const originalTypeName = originalFieldConfig.type.toString();
              const originalResolver = originalFieldConfig.resolve;
              let fieldTypeName;
  
              if (fieldConfig.type) {
                fieldTypeName = Array.isArray(fieldConfig.type) ? stringifyArray(fieldConfig.type) : fieldConfig.type.toString();
              }
  
              if (!fieldTypeName || fieldTypeName.replace(/!/g, ``) === originalTypeName.replace(/!/g, ``) || tc.getExtension(`createdFrom`) === `thirdPartySchema`) {
                const newConfig = {};
  
                if (fieldConfig.type) {
                  newConfig.type = fieldConfig.type;
                }
  
                if (fieldConfig.args) {
                  newConfig.args = fieldConfig.args;
                }
  
                if (fieldConfig.resolve) {
                  newConfig.resolve = (source, args, context, info) => fieldConfig.resolve(source, args, context, { ...info,
                    originalResolver: originalResolver || context.defaultFieldResolver
                  });
  
                  tc.extendFieldExtensions(fieldName, {
                    needsResolve: true
                  });
                }
  
                tc.extendField(fieldName, newConfig); // See resetOverriddenThirdPartyTypeFields for explanation
  
                if (tc.getExtension(`createdFrom`) === `thirdPartySchema`) {
                  tc.setFieldExtension(fieldName, `originalFieldConfig`, originalFieldConfig);
                }
              } else if (fieldTypeName) {
                report.warn(`\`createResolvers\` passed resolvers for field ` + `\`${typeName}.${fieldName}\` with type \`${fieldTypeName}\`. ` + `Such a field with type \`${originalTypeName}\` already exists ` + `on the type. Use \`createTypes\` to override type fields.`);
              }
            } else {
              tc.addFields({
                [fieldName]: fieldConfig
              }); // See resetOverriddenThirdPartyTypeFields for explanation
  
              tc.setFieldExtension(fieldName, `createdFrom`, `createResolvers`);
            }
          });
        } else if (!ignoreNonexistentTypes) {
          report.warn(`\`createResolvers\` passed resolvers for type \`${typeName}\` that ` + `doesn't exist in the schema. Use \`createTypes\` to add the type ` + `before adding resolvers.`);
        }
      });
    };
  
    await apiRunner(`createResolvers`, {
      intermediateSchema,
      createResolvers,
      traceId: `initial-createResolvers`,
      parentSpan
    });
  };
  
  function attachTracingResolver({
    schemaComposer
  }) {
    schemaComposer.forEach(typeComposer => {
      if (typeComposer instanceof ObjectTypeComposer || typeComposer instanceof InterfaceTypeComposer) {
        typeComposer.getFieldNames().forEach(fieldName => {
          const field = typeComposer.getField(fieldName);
          const resolver = wrappingResolver(field.resolve || defaultResolver);
          typeComposer.extendField(fieldName, {
            resolve: resolver
          });
        });
      }
    });
  }
  
  const determineSearchableFields = ({
    schemaComposer,
    typeComposer
  }) => {
    typeComposer.getFieldNames().forEach(fieldName => {
      const field = typeComposer.getField(fieldName);
      const extensions = typeComposer.getFieldExtensions(fieldName);
  
      if (field.resolve) {
        if (extensions.dateformat) {
          typeComposer.extendFieldExtensions(fieldName, {
            searchable: _filter.SEARCHABLE_ENUM.SEARCHABLE,
            sortable: _sort.SORTABLE_ENUM.SORTABLE,
            needsResolve: extensions.proxy ? true : false
          });
        } else if (!_.isEmpty(field.args)) {
          typeComposer.extendFieldExtensions(fieldName, {
            searchable: _filter.SEARCHABLE_ENUM.DEPRECATED_SEARCHABLE,
            sortable: _sort.SORTABLE_ENUM.DEPRECATED_SORTABLE,
            needsResolve: true
          });
        } else {
          typeComposer.extendFieldExtensions(fieldName, {
            searchable: _filter.SEARCHABLE_ENUM.SEARCHABLE,
            sortable: _sort.SORTABLE_ENUM.SORTABLE,
            needsResolve: true
          });
        }
      } else {
        typeComposer.extendFieldExtensions(fieldName, {
          searchable: _filter.SEARCHABLE_ENUM.SEARCHABLE,
          sortable: _sort.SORTABLE_ENUM.SORTABLE,
          needsResolve: false
        });
      }
    });
  };
  
  const addConvenienceChildrenFields = ({
    schemaComposer
  }) => {
    const parentTypesToChildren = new Map();
    const mimeTypesToChildren = new Map();
    const typesHandlingMimeTypes = new Map();
    schemaComposer.forEach(type => {
      if ((type instanceof ObjectTypeComposer || type instanceof InterfaceTypeComposer) && type.hasExtension(`mimeTypes`)) {
        const {
          types
        } = type.getExtension(`mimeTypes`);
        new Set(types).forEach(mimeType => {
          if (!typesHandlingMimeTypes.has(mimeType)) {
            typesHandlingMimeTypes.set(mimeType, new Set());
          }
  
          typesHandlingMimeTypes.get(mimeType).add(type);
        });
      }
  
      if ((type instanceof ObjectTypeComposer || type instanceof InterfaceTypeComposer) && type.hasExtension(`childOf`)) {
        if (type instanceof ObjectTypeComposer && !type.hasInterface(`Node`)) {
          report.error(`The \`childOf\` extension can only be used on types that implement the \`Node\` interface.\n` + `Check the type definition of \`${type.getTypeName()}\`.`);
          return;
        }
  
        if (type instanceof InterfaceTypeComposer && !isNodeInterface(type)) {
          report.error(`The \`childOf\` extension can only be used on types that implement the \`Node\` interface.\n` + `Check the type definition of \`${type.getTypeName()}\`.`);
          return;
        }
  
        const {
          types,
          mimeTypes
        } = type.getExtension(`childOf`);
        new Set(types).forEach(parentType => {
          if (!parentTypesToChildren.has(parentType)) {
            parentTypesToChildren.set(parentType, new Set());
          }
  
          parentTypesToChildren.get(parentType).add(type);
        });
        new Set(mimeTypes).forEach(mimeType => {
          if (!mimeTypesToChildren.has(mimeType)) {
            mimeTypesToChildren.set(mimeType, new Set());
          }
  
          mimeTypesToChildren.get(mimeType).add(type);
        });
      }
    });
    parentTypesToChildren.forEach((children, parent) => {
      if (!schemaComposer.has(parent)) return;
      const typeComposer = schemaComposer.getAnyTC(parent);
  
      if (typeComposer instanceof InterfaceTypeComposer && !isNodeInterface(typeComposer)) {
        report.error(`With the \`childOf\` extension, children fields can only be added to ` + `interfaces which implement the \`Node\` interface.\n` + `Check the type definition of \`${typeComposer.getTypeName()}\`.`);
        return;
      }
  
      children.forEach(child => {
        typeComposer.addFields(createChildrenField(child.getTypeName()));
        typeComposer.addFields(createChildField(child.getTypeName()));
      });
    });
    mimeTypesToChildren.forEach((children, mimeType) => {
      const parentTypes = typesHandlingMimeTypes.get(mimeType);
  
      if (parentTypes) {
        parentTypes.forEach(typeComposer => {
          if (typeComposer instanceof InterfaceTypeComposer && !isNodeInterface(typeComposer)) {
            report.error(`With the \`childOf\` extension, children fields can only be added to ` + `interfaces which implement the \`Node\` interface.\n` + `Check the type definition of \`${typeComposer.getTypeName()}\`.`);
            return;
          }
  
          children.forEach(child => {
            typeComposer.addFields(createChildrenField(child.getTypeName()));
            typeComposer.addFields(createChildField(child.getTypeName()));
          });
        });
      }
    });
  };
  
  const isExplicitChild = ({
    typeComposer,
    childTypeComposer
  }) => {
    var _typeComposer$getExte, _childOfExtension$typ, _childOfExtension$mim;
  
    if (!childTypeComposer.hasExtension(`childOf`)) {
      return false;
    }
  
    const childOfExtension = childTypeComposer.getExtension(`childOf`);
    const {
      types: parentMimeTypes = []
    } = (_typeComposer$getExte = typeComposer.getExtension(`mimeTypes`)) !== null && _typeComposer$getExte !== void 0 ? _typeComposer$getExte : {};
    return (childOfExtension === null || childOfExtension === void 0 ? void 0 : (_childOfExtension$typ = childOfExtension.types) === null || _childOfExtension$typ === void 0 ? void 0 : _childOfExtension$typ.includes(typeComposer.getTypeName())) || (childOfExtension === null || childOfExtension === void 0 ? void 0 : (_childOfExtension$mim = childOfExtension.mimeTypes) === null || _childOfExtension$mim === void 0 ? void 0 : _childOfExtension$mim.some(mimeType => parentMimeTypes.includes(mimeType)));
  };
  
  const addInferredChildOfExtensions = ({
    schemaComposer
  }) => {
    schemaComposer.forEach(typeComposer => {
      if (typeComposer instanceof ObjectTypeComposer && typeComposer.hasInterface(`Node`)) {
        addInferredChildOfExtension({
          schemaComposer,
          typeComposer
        });
      }
    });
  };
  
  const addInferredChildOfExtension = ({
    schemaComposer,
    typeComposer
  }) => {
    const shouldInfer = typeComposer.getExtension(`infer`); // With `@dontInfer`, only parent-child
    // relations explicitly set with the `@childOf` extension are added.
  
    if (shouldInfer === false) return;
    const parentTypeName = typeComposer.getTypeName(); // This is expensive.
    // TODO: We should probably collect this info during inference metadata pass
  
    const childNodeTypes = new Set();
  
    for (const node of getDataStore().iterateNodesByType(parentTypeName)) {
      const children = (node.children || []).map(getNode);
  
      for (const childNode of children) {
        var _childNode$internal;
  
        if (childNode !== null && childNode !== void 0 && (_childNode$internal = childNode.internal) !== null && _childNode$internal !== void 0 && _childNode$internal.type) {
          childNodeTypes.add(childNode.internal.type);
        }
      }
    }
  
    childNodeTypes.forEach(typeName => {
      const childTypeComposer = schemaComposer.getAnyTC(typeName);
      let childOfExtension = childTypeComposer.getExtension(`childOf`);
  
      if (isExplicitChild({
        typeComposer,
        childTypeComposer
      })) {
        return;
      } // Set `@childOf` extension automatically
      // This will cause convenience children fields like `childImageSharp`
      // to be added in `addConvenienceChildrenFields` method.
      // Also required for proper printing of the `@childOf` directive in the snapshot plugin
  
  
      if (!childOfExtension) {
        childOfExtension = {};
      }
  
      if (!childOfExtension.types) {
        childOfExtension.types = [];
      }
  
      childOfExtension.types.push(parentTypeName);
      childTypeComposer.setExtension(`childOf`, childOfExtension);
    });
  };
  
  const createChildrenField = typeName => {
    return {
      [fieldNames.convenienceChildren(typeName)]: {
        type: () => [typeName],
        description: `Returns all children nodes filtered by type ${typeName}`,
  
        resolve(source, args, context) {
          const {
            path
          } = context;
          return context.nodeModel.getNodesByIds({
            ids: source.children,
            type: typeName
          }, {
            path
          });
        }
  
      }
    };
  };
  
  const createChildField = typeName => {
    return {
      [fieldNames.convenienceChild(typeName)]: {
        type: () => typeName,
        description: `Returns the first child node of type ${typeName} ` + `or null if there are no children of given type on this node`,
  
        resolve(source, args, context) {
          const {
            path
          } = context;
          const result = context.nodeModel.getNodesByIds({
            ids: source.children,
            type: typeName
          }, {
            path
          });
  
          if (result && result.length > 0) {
            return result[0];
          } else {
            return null;
          }
        }
  
      }
    };
  };
  
  const addTypeToRootQuery = ({
    schemaComposer,
    typeComposer
  }) => {
    const sortInputTC = (0, _sort.getSortInput)({
      schemaComposer,
      typeComposer
    });
    const filterInputTC = (0, _filter.getFilterInput)({
      schemaComposer,
      typeComposer
    });
    const paginationTC = (0, _pagination.getPagination)({
      schemaComposer,
      typeComposer
    });
    const typeName = typeComposer.getTypeName(); // not strictly correctly, result is `npmPackage` and `allNpmPackage` from type `NPMPackage`
  
    const queryName = fieldNames.query(typeName);
    const queryNamePlural = fieldNames.queryAll(typeName);
    schemaComposer.Query.addFields({
      [queryName]: {
        type: typeComposer,
        args: { ...filterInputTC.getFields()
        },
        resolve: findOne(typeName)
      },
      [queryNamePlural]: {
        type: paginationTC,
        args: {
          filter: filterInputTC,
          sort: sortInputTC,
          skip: `Int`,
          limit: `Int`
        },
        resolve: findManyPaginated(typeName)
      }
    }).makeFieldNonNull(queryNamePlural);
  };
  
  const parseTypes = ({
    doc,
    plugin,
    createdFrom,
    schemaComposer,
    parentSpan
  }) => {
    const types = [];
    doc.definitions.forEach(def => {
      const name = def.name.value;
      checkIsAllowedTypeName(name);
  
      if (schemaComposer.has(name)) {
        // We don't check if ast.kind matches composer type, but rely
        // that this will throw when something is wrong and get
        // reported by `reportParsingError`.
        // Keep the original type composer around
        const typeComposer = schemaComposer.get(name); // After this, the parsed type composer will be registered as the composer
        // handling the type name (requires cleanup after merging, see below)
  
        const parsedType = schemaComposer.typeMapper.makeSchemaDef(def); // Merging types require implemented interfaces to already exist.
        // Depending on type creation order, interface might have not been
        // processed yet. We check if interface already exist and create
        // placeholder for it, if it doesn't exist yet.
  
        if (parsedType.getInterfaces) {
          parsedType.getInterfaces().forEach(iface => {
            const ifaceName = iface.getTypeName();
  
            if (!schemaComposer.has(ifaceName)) {
              const tmpComposer = schemaComposer.createInterfaceTC(ifaceName);
              tmpComposer.setExtension(`isPlaceholder`, true);
            }
          });
        } // Merge the parsed type with the original
  
  
        mergeTypes({
          schemaComposer,
          typeComposer,
          type: parsedType,
          plugin,
          createdFrom,
          parentSpan
        }); // Cleanup:
        // Set the original type composer (with the merged fields added)
        // as the correct composer for the type name and remove the temporary one
        // `graphql-compose` doesn't make that easy 🤯
        // TODO: clean this up when this issue is fixed:
        //  https://github.com/graphql-compose/graphql-compose/issues/311
  
        schemaComposer.set(typeComposer.getTypeName(), typeComposer);
        schemaComposer.set(typeComposer._gqType, typeComposer);
        schemaComposer.delete(parsedType._gqType);
        schemaComposer.delete(parsedType);
      } else {
        const parsedType = schemaComposer.typeMapper.makeSchemaDef(def);
        types.push(parsedType);
      }
    });
    return types;
  };
  
  const stringifyArray = arr => `[${arr.map(item => Array.isArray(item) ? stringifyArray(item) : item.toString())}]`; // TODO: Import this directly from graphql-compose once we update to v7
  
  
  const isNamedTypeComposer = type => type instanceof ObjectTypeComposer || type instanceof InputTypeComposer || type instanceof ScalarTypeComposer || type instanceof EnumTypeComposer || type instanceof InterfaceTypeComposer || type instanceof UnionTypeComposer;
  
  const validate = (type, value) => {
    if (type instanceof GraphQLNonNull) {
      if (value == null) {
        throw new Error(`Expected non-null field value.`);
      }
  
      return validate(type.ofType, value);
    } else if (type instanceof GraphQLList) {
      if (!Array.isArray(value)) {
        throw new Error(`Expected array field value.`);
      }
  
      return value.map(v => validate(type.ofType, v));
    } else {
      return type.parseValue(value);
    }
  };
  
  const isNodeInterface = interfaceTypeComposer => interfaceTypeComposer.hasInterface(`Node`);
  
  const checkQueryableInterfaces = ({
    schemaComposer
  }) => {
    const queryableInterfaces = new Set();
    schemaComposer.forEach(type => {
      if (type instanceof InterfaceTypeComposer && isNodeInterface(type)) {
        queryableInterfaces.add(type.getTypeName());
      }
    });
    const incorrectTypes = new Set();
    schemaComposer.forEach(type => {
      if (type instanceof ObjectTypeComposer) {
        const interfaces = type.getInterfaces();
  
        if (interfaces.some(iface => queryableInterfaces.has(iface.getTypeName())) && !type.hasInterface(`Node`)) {
          incorrectTypes.add(type.getTypeName());
        }
      }
    });
  
    if (incorrectTypes.size) {
      report.panic(`Types implementing queryable interfaces must also implement the \`Node\` ` + `interface. Check the type definition of ` + `${Array.from(incorrectTypes).map(t => `\`${t}\``).join(`, `)}.`);
    }
  };
  
  const mergeFields = ({
    typeComposer,
    fields
  }) => Object.entries(fields).forEach(([fieldName, fieldConfig]) => {
    if (typeComposer.hasField(fieldName)) {
      typeComposer.extendField(fieldName, fieldConfig);
    } else {
      typeComposer.setField(fieldName, fieldConfig);
    }
  });
  
  const mergeResolveType = ({
    typeComposer,
    type
  }) => {
    if ((type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType) && type.resolveType) {
      typeComposer.setResolveType(type.resolveType);
    }
  
    if ((type instanceof InterfaceTypeComposer || type instanceof UnionTypeComposer) && type.getResolveType()) {
      typeComposer.setResolveType(type.getResolveType());
    }
  
    if (!typeComposer.getResolveType()) {
      typeComposer.setResolveType(node => {
        var _node$internal;
  
        return node === null || node === void 0 ? void 0 : (_node$internal = node.internal) === null || _node$internal === void 0 ? void 0 : _node$internal.type;
      });
    }
  };
  //# sourceMappingURL=schema.js.map