UNPKG

graphql

Version:

A Query Language and Runtime which can target any service.

1 lines 5.91 kB
{"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"]}