{"version":3,"file":"separateOperations.js","sourceRoot":"","sources":["../../src/utilities/separateOperations.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,IAAI,EAAE,8BAA6B;AAC5C,OAAO,EAAE,KAAK,EAAE,gCAA+B;AAqC/C,MAAM,UAAU,kBAAkB,CAChC,WAAyB;IAEzB,MAAM,UAAU,GAAmC,EAAE,CAAC;IACtD,MAAM,QAAQ,GAAa,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAG/C,KAAK,MAAM,cAAc,IAAI,WAAW,CAAC,WAAW,EAAE,CAAC;QACrD,QAAQ,cAAc,CAAC,IAAI,EAAE,CAAC;YAC5B,KAAK,IAAI,CAAC,oBAAoB;gBAC5B,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBAChC,MAAM;YACR,KAAK,IAAI,CAAC,mBAAmB;gBAC3B,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,mBAAmB,CACvD,cAAc,CAAC,YAAY,CAC5B,CAAC;gBACF,MAAM;YACR,QAAQ;QAEV,CAAC;IACH,CAAC;IAID,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAClD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;QAEvC,KAAK,MAAM,YAAY,IAAI,mBAAmB,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC;YACvE,6BAA6B,CAAC,YAAY,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;QACtE,CAAC;QAGD,MAAM,aAAa,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAIjE,qBAAqB,CAAC,aAAa,CAAC,GAAG;YACrC,IAAI,EAAE,IAAI,CAAC,QAAQ;YACnB,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,MAAM,CACzC,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,KAAK,SAAS;gBAClB,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,mBAAmB;oBACrC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CACvC;SACF,CAAC;IACJ,CAAC;IAED,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAMD,SAAS,6BAA6B,CACpC,SAAsB,EACtB,QAAkB,EAClB,QAAgB;IAEhB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAExB,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;gBACnC,6BAA6B,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,YAA8B;IACzD,MAAM,YAAY,GAAkB,EAAE,CAAC;IAEvC,KAAK,CAAC,YAAY,EAAE;QAClB,cAAc,CAAC,IAAI;YACjB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC;KACF,CAAC,CAAC;IACH,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["/** @category AST Utilities */\n\nimport type { ObjMap } from '../jsutils/ObjMap.ts';\n\nimport type {\n  DocumentNode,\n  OperationDefinitionNode,\n  SelectionSetNode,\n} from '../language/ast.ts';\nimport { Kind } from '../language/kinds.ts';\nimport { visit } from '../language/visitor.ts';\n\n/**\n * separateOperations accepts a single AST document which may contain many\n * operations and fragments and returns a collection of AST documents each of\n * which contains a single operation as well the fragment definitions it\n * refers to.\n * @param documentAST - The parsed GraphQL document AST.\n * @returns A map of operation names to documents containing each operation and its referenced fragments.\n * @example\n * ```ts\n * import { parse, print } from 'graphql/language';\n * import { separateOperations } from 'graphql/utilities';\n *\n * const document = parse(`\n *   query GetUser {\n *     viewer {\n *       ...UserFields\n *     }\n *   }\n *\n *   query GetStatus {\n *     status\n *   }\n *\n *   fragment UserFields on User {\n *     id\n *   }\n * `);\n *\n * const separated = separateOperations(document);\n *\n * Object.keys(separated); // => ['GetUser', 'GetStatus']\n * print(separated.GetUser); // matches /fragment UserFields/\n * print(separated.GetStatus); // does not match /fragment UserFields/\n * ```\n */\nexport function separateOperations(\n  documentAST: DocumentNode,\n): ObjMap<DocumentNode> {\n  const operations: Array<OperationDefinitionNode> = [];\n  const depGraph: DepGraph = Object.create(null);\n\n  // Populate metadata and build a dependency graph.\n  for (const definitionNode of documentAST.definitions) {\n    switch (definitionNode.kind) {\n      case Kind.OPERATION_DEFINITION:\n        operations.push(definitionNode);\n        break;\n      case Kind.FRAGMENT_DEFINITION:\n        depGraph[definitionNode.name.value] = collectDependencies(\n          definitionNode.selectionSet,\n        );\n        break;\n      default:\n      // ignore non-executable definitions\n    }\n  }\n\n  // For each operation, produce a new synthesized AST which includes only what\n  // is necessary for completing that operation.\n  const separatedDocumentASTs = Object.create(null);\n  for (const operation of operations) {\n    const dependencies = new Set<string>();\n\n    for (const fragmentName of collectDependencies(operation.selectionSet)) {\n      collectTransitiveDependencies(dependencies, depGraph, fragmentName);\n    }\n\n    // Provides the empty string for anonymous operations.\n    const operationName = operation.name ? operation.name.value : '';\n\n    // The list of definition nodes to be included for this operation, sorted\n    // to retain the same order as the original document.\n    separatedDocumentASTs[operationName] = {\n      kind: Kind.DOCUMENT,\n      definitions: documentAST.definitions.filter(\n        (node) =>\n          node === operation ||\n          (node.kind === Kind.FRAGMENT_DEFINITION &&\n            dependencies.has(node.name.value)),\n      ),\n    };\n  }\n\n  return separatedDocumentASTs;\n}\n\ntype DepGraph = ObjMap<ReadonlyArray<string>>;\n\n// From a dependency graph, collects a list of transitive dependencies by\n// recursing through a dependency graph.\nfunction collectTransitiveDependencies(\n  collected: Set<string>,\n  depGraph: DepGraph,\n  fromName: string,\n): void {\n  if (!collected.has(fromName)) {\n    collected.add(fromName);\n\n    const immediateDeps = depGraph[fromName];\n    if (immediateDeps !== undefined) {\n      for (const toName of immediateDeps) {\n        collectTransitiveDependencies(collected, depGraph, toName);\n      }\n    }\n  }\n}\n\nfunction collectDependencies(selectionSet: SelectionSetNode): Array<string> {\n  const dependencies: Array<string> = [];\n\n  visit(selectionSet, {\n    FragmentSpread(node) {\n      dependencies.push(node.name.value);\n    },\n  });\n  return dependencies;\n}\n"]}