'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; }