{"version":3,"sources":["../src/resolve-info.ts"],"sourcesContent":["import { genFn } from \"./generate\";\nimport {\n  doTypesOverlap,\n  type FieldNode,\n  type GraphQLCompositeType,\n  GraphQLError,\n  GraphQLInterfaceType,\n  type GraphQLNamedType,\n  GraphQLObjectType,\n  type GraphQLOutputType,\n  type GraphQLResolveInfo,\n  GraphQLSchema,\n  isAbstractType,\n  isCompositeType,\n  isListType,\n  isNonNullType,\n  isObjectType,\n  isUnionType,\n  Kind,\n  type SelectionSetNode\n} from \"graphql\";\nimport memoize from \"lodash.memoize\";\nimport mergeWith from \"lodash.mergewith\";\nimport { memoize2, memoize4 } from \"./memoize.js\";\n\n// TODO(boopathi): Use negated types to express\n// Enrichments<T> = { [key in (string & not keyof GraphQLResolveInfo)]: T[key] }\n// in TypeScript 3.5\n// https://github.com/Microsoft/TypeScript/pull/29317\nexport type GraphQLJitResolveInfo<Enrichments> = GraphQLResolveInfo &\n  Enrichments;\n\nexport interface ResolveInfoEnricherInput {\n  schema: GraphQLResolveInfo[\"schema\"];\n  fragments: GraphQLResolveInfo[\"fragments\"];\n  operation: GraphQLResolveInfo[\"operation\"];\n  parentType: GraphQLObjectType;\n  returnType: GraphQLOutputType;\n  fieldName: string;\n  fieldNodes: FieldNode[];\n}\n\nexport interface FieldExpansion {\n  // The possible return types that the field can return\n  // It includes all the types in the Schema that intersect with the actual return type\n  [returnType: string]: TypeExpansion;\n}\n\nconst LeafFieldSymbol = Symbol(\"LeafFieldSymbol\");\n\nexport interface LeafField {\n  [LeafFieldSymbol]: true;\n}\n\nexport interface TypeExpansion {\n  // The fields that are requested in the Query for a particular type\n  // `true` indicates a leaf node\n  [fieldName: string]: FieldExpansion | LeafField;\n}\n\nfunction createLeafField<T extends object>(props: T): T & LeafField {\n  return {\n    [LeafFieldSymbol]: true,\n    ...props\n  };\n}\n\nexport function isLeafField(obj: LeafField | FieldExpansion): obj is LeafField {\n  return (\n    obj != null && Object.prototype.hasOwnProperty.call(obj, LeafFieldSymbol)\n  );\n}\n\n/**\n * Compute the GraphQLJitResolveInfo's `fieldExpansion` and return a function\n * that returns the computed resolveInfo. This thunk is registered in\n * context.dependencies for the field's resolveInfoName\n */\nexport function createResolveInfoThunk<T>(\n  {\n    schema,\n    fragments,\n    operation,\n    parentType,\n    fieldName,\n    fieldType,\n    fieldNodes\n  }: {\n    schema: GraphQLResolveInfo[\"schema\"];\n    fragments: GraphQLResolveInfo[\"fragments\"];\n    operation: GraphQLResolveInfo[\"operation\"];\n    parentType: GraphQLObjectType;\n    fieldType: GraphQLOutputType;\n    fieldName: string;\n    fieldNodes: FieldNode[];\n  },\n  enricher?: (inp: ResolveInfoEnricherInput) => T\n) {\n  let enrichedInfo = {};\n  if (typeof enricher === \"function\") {\n    enrichedInfo =\n      enricher({\n        fieldName,\n        fieldNodes,\n        returnType: fieldType,\n        parentType,\n        schema,\n        fragments,\n        operation\n      }) || {};\n    if (typeof enrichedInfo !== \"object\" || Array.isArray(enrichedInfo)) {\n      enrichedInfo = {};\n    }\n  }\n  const gen = genFn();\n  gen(`return function getGraphQLResolveInfo(rootValue, variableValues, path) {\n      return {\n          fieldName,\n          fieldNodes,\n          returnType: fieldType,\n          parentType,\n          path,\n          schema,\n          fragments,\n          rootValue,\n          operation,\n          variableValues,`);\n  Object.keys(enrichedInfo).forEach((key) => {\n    gen(`${key}: enrichedInfo[\"${key}\"],\\n`);\n  });\n  gen(`};};`);\n  // eslint-disable-next-line\n  return new Function(\n    \"fieldName\",\n    \"fieldNodes\",\n    \"fieldType\",\n    \"parentType\",\n    \"schema\",\n    \"fragments\",\n    \"operation\",\n    \"enrichedInfo\",\n    gen.toString()\n  ).call(\n    null,\n    fieldName,\n    fieldNodes,\n    fieldType,\n    parentType,\n    schema,\n    fragments,\n    operation,\n    enrichedInfo\n  );\n}\n\nexport function fieldExpansionEnricher(input: ResolveInfoEnricherInput) {\n  const { schema, fragments, returnType, fieldNodes } = input;\n  const fieldExpansion: FieldExpansion | LeafField = {};\n\n  for (const fieldNode of fieldNodes) {\n    deepMerge(\n      fieldExpansion,\n      memoizedExpandFieldNode(schema, fragments, fieldNode, returnType)\n    );\n  }\n\n  return {\n    fieldExpansion\n  };\n}\n\ntype FragmentsType = GraphQLResolveInfo[\"fragments\"];\ntype GraphQLNamedOutputType = GraphQLNamedType & GraphQLOutputType;\ntype GraphQLObjectLike = GraphQLInterfaceType | GraphQLObjectType;\n\nconst MEMOIZATION = true;\n\nconst memoizedGetReturnType = MEMOIZATION\n  ? memoize2(getReturnType)\n  : getReturnType;\nconst memoizedHasField = MEMOIZATION ? memoize2(hasField) : hasField;\nconst memoizedResolveEndType = MEMOIZATION\n  ? memoize(resolveEndType)\n  : resolveEndType;\nconst memoizedGetPossibleTypes = MEMOIZATION\n  ? memoize2(getPossibleTypes)\n  : getPossibleTypes;\nconst memoizedExpandFieldNodeType = MEMOIZATION\n  ? memoize4(expandFieldNodeType)\n  : expandFieldNodeType;\nconst memoizedExpandFieldNode = MEMOIZATION\n  ? memoize4(expandFieldNode)\n  : expandFieldNode;\n\nfunction expandFieldNode(\n  schema: GraphQLSchema,\n  fragments: FragmentsType,\n  node: FieldNode,\n  fieldType: GraphQLOutputType\n): FieldExpansion | LeafField {\n  if (node.selectionSet == null) {\n    return createLeafField({});\n  }\n\n  // there is a selectionSet which makes the fieldType a CompositeType\n  const typ = memoizedResolveEndType(fieldType) as GraphQLCompositeType;\n  const possibleTypes = memoizedGetPossibleTypes(schema, typ);\n\n  const fieldExpansion: FieldExpansion = {};\n  for (const possibleType of possibleTypes) {\n    if (!isUnionType(possibleType)) {\n      fieldExpansion[possibleType.name] = memoizedExpandFieldNodeType(\n        schema,\n        fragments,\n        possibleType,\n        node.selectionSet\n      );\n    }\n  }\n\n  return fieldExpansion;\n}\n\nfunction expandFieldNodeType(\n  schema: GraphQLSchema,\n  fragments: FragmentsType,\n  parentType: GraphQLCompositeType,\n  selectionSet: SelectionSetNode\n): TypeExpansion {\n  const typeExpansion: TypeExpansion = {};\n\n  for (const selection of selectionSet.selections) {\n    if (selection.kind === Kind.FIELD) {\n      if (\n        !isUnionType(parentType) &&\n        memoizedHasField(parentType, selection.name.value)\n      ) {\n        typeExpansion[selection.name.value] = memoizedExpandFieldNode(\n          schema,\n          fragments,\n          selection,\n          memoizedGetReturnType(parentType, selection.name.value)\n        );\n      }\n    } else {\n      const selectionSet =\n        selection.kind === Kind.INLINE_FRAGMENT\n          ? selection.selectionSet\n          : fragments[selection.name.value].selectionSet;\n\n      const nextType =\n        selection.kind === Kind.INLINE_FRAGMENT\n          ? selection.typeCondition\n            ? (schema.getType(\n                selection.typeCondition.name.value\n              ) as GraphQLCompositeType)\n            : parentType\n          : (schema.getType(\n              fragments[selection.name.value].typeCondition.name.value\n            ) as GraphQLCompositeType);\n\n      /**\n       * nextType (comes from query) is the type extracted from the fragment\n       * parentType (comes from schema) is the possibleType for which we are filling fields\n       *\n       * if the type from query (nextType) is the same as the type we are filling (parentType)\n       * or\n       * if the type from query (nextType) is an abstract type - this case is when we jump\n       * to a super type or sub type. Here we maintain the context (parentType) for which\n       * we are filling the fields. The super type / sub type will be filled in its own\n       * pass.\n       */\n      if (nextType === parentType || isAbstractType(nextType)) {\n        deepMerge(\n          typeExpansion,\n          memoizedExpandFieldNodeType(\n            schema,\n            fragments,\n            parentType,\n            selectionSet\n          )\n        );\n      }\n    }\n  }\n\n  return typeExpansion;\n}\n\n/**\n * Returns a list of Possible types that one can get to from the\n * resolvedType. As an analogy, these are the same types that one\n * can use in a fragment's typeCondition.\n *\n * Note: This is different from schema.getPossibleTypes() that this\n * returns all possible types and not just the ones from the type definition.\n *\n * Example:\n * interface Node {\n *   id: ID!\n * }\n * type User implements Node {\n *   id: ID!\n *   name: String\n * }\n * type Article implements Node {\n *   id: ID!\n *   title: String\n * }\n * union Card = User | Article\n *\n * - schema.getPossibleTypes(Card) would give [User, Article]\n * - This function getPossibleTypes(schema, Card) would give [User, Article, Node]\n *\n */\nfunction getPossibleTypes(\n  schema: GraphQLSchema,\n  compositeType: GraphQLCompositeType\n) {\n  if (isObjectType(compositeType)) {\n    return [compositeType];\n  }\n\n  const possibleTypes: GraphQLCompositeType[] = [];\n  const types = schema.getTypeMap();\n  for (const typeName in types) {\n    if (Object.prototype.hasOwnProperty.call(types, typeName)) {\n      const typ = types[typeName];\n      if (isCompositeType(typ) && doTypesOverlap(schema, typ, compositeType)) {\n        possibleTypes.push(typ);\n      }\n    }\n  }\n\n  return possibleTypes;\n}\n\n/**\n * Given an (Object|Interface)Type, and a fieldName, find the\n * appropriate `end` return type for the field in the Composite Type.\n *\n * Note: The `end` return type is the type by unwrapping non-null types\n * and list types. Check `resolveEndType`\n */\nfunction getReturnType(\n  parentType: GraphQLObjectLike,\n  fieldName: string\n): GraphQLNamedOutputType {\n  const fields = parentType.getFields();\n  if (!Object.prototype.hasOwnProperty.call(fields, fieldName)) {\n    throw new GraphQLError(\n      `Field \"${fieldName}\" does not exist in \"${parentType.name}\"`\n    );\n  }\n\n  const outputType = fields[fieldName].type;\n  return memoizedResolveEndType(outputType);\n}\n\n/**\n * Resolve to the end type of the Output type unwrapping non-null types and lists\n */\nfunction resolveEndType(typ: GraphQLOutputType): GraphQLNamedOutputType {\n  if (isListType(typ) || isNonNullType(typ)) {\n    return memoizedResolveEndType(typ.ofType);\n  }\n  return typ;\n}\n\nfunction hasField(typ: GraphQLObjectLike, fieldName: string) {\n  return Object.prototype.hasOwnProperty.call(typ.getFields(), fieldName);\n}\n\n// This is because lodash does not support merging keys\n// which are symbols. We require them for leaf fields\nfunction deepMerge<TObject, TSource>(obj: TObject, src: TSource) {\n  mergeWith(obj, src, (objValue, srcValue): LeafField | undefined => {\n    if (isLeafField(objValue)) {\n      if (isLeafField(srcValue)) {\n        return {\n          ...objValue,\n          ...srcValue\n        };\n      }\n\n      return objValue;\n    } else if (isLeafField(srcValue)) {\n      return srcValue;\n    }\n\n    return undefined;\n  });\n}\n"],"mappings":"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","names":["selectionSet"]}