| 'use strict'; |
|
|
| Object.defineProperty(exports, '__esModule', { |
| value: true, |
| }); |
| exports.collectFields = collectFields; |
| exports.collectSubfields = collectSubfields; |
|
|
| var _kinds = require('../language/kinds.js'); |
|
|
| var _definition = require('../type/definition.js'); |
|
|
| var _directives = require('../type/directives.js'); |
|
|
| var _typeFromAST = require('../utilities/typeFromAST.js'); |
|
|
| var _values = require('./values.js'); |
|
|
| /** |
| * Given a selectionSet, collects all of the fields and returns them. |
| * |
| * CollectFields requires the "runtime type" of an object. For a field that |
| * returns an Interface or Union type, the "runtime type" will be the actual |
| * object type returned by that field. |
| * |
| * @internal |
| */ |
| function collectFields( |
| schema, |
| fragments, |
| variableValues, |
| runtimeType, |
| selectionSet, |
| ) { |
| const fields = new Map(); |
| collectFieldsImpl( |
| schema, |
| fragments, |
| variableValues, |
| runtimeType, |
| selectionSet, |
| fields, |
| new Set(), |
| ); |
| return fields; |
| } |
| /** |
| * Given an array of field nodes, collects all of the subfields of the passed |
| * in fields, and returns them at the end. |
| * |
| * CollectSubFields requires the "return type" of an object. For a field that |
| * returns an Interface or Union type, the "return type" will be the actual |
| * object type returned by that field. |
| * |
| * @internal |
| */ |
|
|
| function collectSubfields( |
| schema, |
| fragments, |
| variableValues, |
| returnType, |
| fieldNodes, |
| ) { |
| const subFieldNodes = new Map(); |
| const visitedFragmentNames = new Set(); |
|
|
| for (const node of fieldNodes) { |
| if (node.selectionSet) { |
| collectFieldsImpl( |
| schema, |
| fragments, |
| variableValues, |
| returnType, |
| node.selectionSet, |
| subFieldNodes, |
| visitedFragmentNames, |
| ); |
| } |
| } |
|
|
| return subFieldNodes; |
| } |
|
|
| function collectFieldsImpl( |
| schema, |
| fragments, |
| variableValues, |
| runtimeType, |
| selectionSet, |
| fields, |
| visitedFragmentNames, |
| ) { |
| for (const selection of selectionSet.selections) { |
| switch (selection.kind) { |
| case _kinds.Kind.FIELD: { |
| if (!shouldIncludeNode(variableValues, selection)) { |
| continue; |
| } |
|
|
| const name = getFieldEntryKey(selection); |
| const fieldList = fields.get(name); |
|
|
| if (fieldList !== undefined) { |
| fieldList.push(selection); |
| } else { |
| fields.set(name, [selection]); |
| } |
|
|
| break; |
| } |
|
|
| case _kinds.Kind.INLINE_FRAGMENT: { |
| if ( |
| !shouldIncludeNode(variableValues, selection) || |
| !doesFragmentConditionMatch(schema, selection, runtimeType) |
| ) { |
| continue; |
| } |
|
|
| collectFieldsImpl( |
| schema, |
| fragments, |
| variableValues, |
| runtimeType, |
| selection.selectionSet, |
| fields, |
| visitedFragmentNames, |
| ); |
| break; |
| } |
|
|
| case _kinds.Kind.FRAGMENT_SPREAD: { |
| const fragName = selection.name.value; |
|
|
| if ( |
| visitedFragmentNames.has(fragName) || |
| !shouldIncludeNode(variableValues, selection) |
| ) { |
| continue; |
| } |
|
|
| visitedFragmentNames.add(fragName); |
| const fragment = fragments[fragName]; |
|
|
| if ( |
| !fragment || |
| !doesFragmentConditionMatch(schema, fragment, runtimeType) |
| ) { |
| continue; |
| } |
|
|
| collectFieldsImpl( |
| schema, |
| fragments, |
| variableValues, |
| runtimeType, |
| fragment.selectionSet, |
| fields, |
| visitedFragmentNames, |
| ); |
| break; |
| } |
| } |
| } |
| } |
| /** |
| * Determines if a field should be included based on the `@include` and `@skip` |
| * directives, where `@skip` has higher precedence than `@include`. |
| */ |
|
|
| function shouldIncludeNode(variableValues, node) { |
| const skip = (0, _values.getDirectiveValues)( |
| _directives.GraphQLSkipDirective, |
| node, |
| variableValues, |
| ); |
|
|
| if ((skip === null || skip === void 0 ? void 0 : skip.if) === true) { |
| return false; |
| } |
|
|
| const include = (0, _values.getDirectiveValues)( |
| _directives.GraphQLIncludeDirective, |
| node, |
| variableValues, |
| ); |
|
|
| if ( |
| (include === null || include === void 0 ? void 0 : include.if) === false |
| ) { |
| return false; |
| } |
|
|
| return true; |
| } |
| /** |
| * Determines if a fragment is applicable to the given type. |
| */ |
|
|
| function doesFragmentConditionMatch(schema, fragment, type) { |
| const typeConditionNode = fragment.typeCondition; |
|
|
| if (!typeConditionNode) { |
| return true; |
| } |
|
|
| const conditionalType = (0, _typeFromAST.typeFromAST)( |
| schema, |
| typeConditionNode, |
| ); |
|
|
| if (conditionalType === type) { |
| return true; |
| } |
|
|
| if ((0, _definition.isAbstractType)(conditionalType)) { |
| return schema.isSubType(conditionalType, type); |
| } |
|
|
| return false; |
| } |
| /** |
| * Implements the logic to compute the key of a given field's entry |
| */ |
|
|
| function getFieldEntryKey(node) { |
| return node.alias ? node.alias.value : node.name.value; |
| } |