UNPKG

graphql

Version:

A Query Language and Runtime which can target any service.

211 lines (190 loc) 7.29 kB
/* @flow */ /** * Copyright (c) 2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ 'use strict'; var _createClass = require('babel-runtime/helpers/create-class')['default']; var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default']; var _Object$defineProperty = require('babel-runtime/core-js/object/define-property')['default']; var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default']; _Object$defineProperty(exports, '__esModule', { value: true }); var _language = require('../language'); var _typeDefinition = require('../type/definition'); var _typeIntrospection = require('../type/introspection'); var _utilsTypeFromAST = require('../utils/typeFromAST'); var _utilsTypeFromAST2 = _interopRequireDefault(_utilsTypeFromAST); var _find = require('./find'); var _find2 = _interopRequireDefault(_find); /** * FieldInfo is a utility class which, given a GraphQL schema, can keep track * of the current field and type definitions at any point in a GraphQL document * AST during a recursive descent by calling `enter(node)` and `leave(node)`. */ var TypeInfo = (function () { function TypeInfo(schema) { _classCallCheck(this, TypeInfo); this._schema = schema; this._typeStack = []; this._parentTypeStack = []; this._inputTypeStack = []; this._fieldDefStack = []; } _createClass(TypeInfo, [{ key: 'getType', value: function getType() { if (this._typeStack.length > 0) { return this._typeStack[this._typeStack.length - 1]; } } }, { key: 'getParentType', value: function getParentType() { if (this._parentTypeStack.length > 0) { return this._parentTypeStack[this._parentTypeStack.length - 1]; } } }, { key: 'getInputType', value: function getInputType() { if (this._inputTypeStack.length > 0) { return this._inputTypeStack[this._inputTypeStack.length - 1]; } } }, { key: 'getFieldDef', value: function getFieldDef() { if (this._fieldDefStack.length > 0) { return this._fieldDefStack[this._fieldDefStack.length - 1]; } } }, { key: 'enter', // Flow does not yet handle this case. value: function enter(node) { var schema = this._schema; var type; switch (node.kind) { case _language.Kind.SELECTION_SET: var compositeType; var rawType = (0, _typeDefinition.getUnmodifiedType)(this.getType()); if ((0, _typeDefinition.isCompositeType)(rawType)) { // isCompositeType is a type refining predicate, so this is safe. compositeType = rawType; } this._parentTypeStack.push(compositeType); break; case _language.Kind.FIELD: var parentType = this.getParentType(); var fieldDef; if (parentType) { fieldDef = getFieldDef(schema, parentType, node); } this._fieldDefStack.push(fieldDef); this._typeStack.push(fieldDef && fieldDef.type); break; case _language.Kind.OPERATION_DEFINITION: if (node.operation === 'query') { type = schema.getQueryType(); } else if (node.operation === 'mutation') { type = schema.getMutationType(); } this._typeStack.push(type); break; case _language.Kind.INLINE_FRAGMENT: case _language.Kind.FRAGMENT_DEFINITION: type = schema.getType(node.typeCondition.value); this._typeStack.push(type); break; case _language.Kind.VARIABLE_DEFINITION: this._inputTypeStack.push((0, _utilsTypeFromAST2['default'])(schema, node.type)); break; case _language.Kind.ARGUMENT: var field = this.getFieldDef(); var argType; if (field) { var argDef = (0, _find2['default'])(field.args, function (arg) { return arg.name === node.name.value; }); if (argDef) { argType = argDef.type; } } this._inputTypeStack.push(argType); break; case _language.Kind.DIRECTIVE: var directive = schema.getDirective(node.name.value); this._inputTypeStack.push(directive ? directive.type : undefined); break; case _language.Kind.ARRAY: var arrayType = (0, _typeDefinition.getNullableType)(this.getInputType()); this._inputTypeStack.push(arrayType instanceof _typeDefinition.GraphQLList ? arrayType.ofType : undefined); break; case _language.Kind.OBJECT_FIELD: var objectType = (0, _typeDefinition.getUnmodifiedType)(this.getInputType()); var fieldType; if (objectType instanceof _typeDefinition.GraphQLInputObjectType) { var inputField = objectType.getFields()[node.name.value]; fieldType = inputField ? inputField.type : undefined; } this._inputTypeStack.push(fieldType); break; } } }, { key: 'leave', value: function leave(node) { switch (node.kind) { case _language.Kind.SELECTION_SET: this._parentTypeStack.pop(); break; case _language.Kind.FIELD: this._fieldDefStack.pop(); this._typeStack.pop(); break; case _language.Kind.OPERATION_DEFINITION: case _language.Kind.INLINE_FRAGMENT: case _language.Kind.FRAGMENT_DEFINITION: this._typeStack.pop(); break; case _language.Kind.VARIABLE_DEFINITION: case _language.Kind.ARGUMENT: case _language.Kind.DIRECTIVE: case _language.Kind.ARRAY: case _language.Kind.OBJECT_FIELD: this._inputTypeStack.pop(); break; } } }]); return TypeInfo; })(); exports['default'] = TypeInfo; /** * Not exactly the same as the executor's definition of getFieldDef, in this * statically evaluated environment we do not always have an Object type, * and need to handle Interface and Union types. */ function getFieldDef(schema, parentType, fieldAST) { var name = fieldAST.name.value; if (name === _typeIntrospection.SchemaMetaFieldDef.name && schema.getQueryType() === parentType) { return _typeIntrospection.SchemaMetaFieldDef; } if (name === _typeIntrospection.TypeMetaFieldDef.name && schema.getQueryType() === parentType) { return _typeIntrospection.TypeMetaFieldDef; } if (name === _typeIntrospection.TypeNameMetaFieldDef.name && (parentType instanceof _typeDefinition.GraphQLObjectType || parentType instanceof _typeDefinition.GraphQLInterfaceType || parentType instanceof _typeDefinition.GraphQLUnionType)) { return _typeIntrospection.TypeNameMetaFieldDef; } if (parentType instanceof _typeDefinition.GraphQLObjectType || parentType instanceof _typeDefinition.GraphQLInterfaceType) { return parentType.getFields()[name]; } } module.exports = exports['default']; /*Node*/