| 'use strict'; |
|
|
| Object.defineProperty(exports, '__esModule', { |
| value: true, |
| }); |
| exports.GraphQLSchema = void 0; |
| exports.assertSchema = assertSchema; |
| exports.isSchema = isSchema; |
|
|
| var _devAssert = require('../jsutils/devAssert.js'); |
|
|
| var _inspect = require('../jsutils/inspect.js'); |
|
|
| var _instanceOf = require('../jsutils/instanceOf.js'); |
|
|
| var _isObjectLike = require('../jsutils/isObjectLike.js'); |
|
|
| var _toObjMap = require('../jsutils/toObjMap.js'); |
|
|
| var _ast = require('../language/ast.js'); |
|
|
| var _definition = require('./definition.js'); |
|
|
| var _directives = require('./directives.js'); |
|
|
| var _introspection = require('./introspection.js'); |
|
|
| /** |
| * Test if the given value is a GraphQL schema. |
| */ |
| function isSchema(schema) { |
| return (0, _instanceOf.instanceOf)(schema, GraphQLSchema); |
| } |
|
|
| function assertSchema(schema) { |
| if (!isSchema(schema)) { |
| throw new Error( |
| `Expected ${(0, _inspect.inspect)(schema)} to be a GraphQL schema.`, |
| ); |
| } |
|
|
| return schema; |
| } |
| /** |
| * Custom extensions |
| * |
| * @remarks |
| * Use a unique identifier name for your extension, for example the name of |
| * your library or project. Do not use a shortened identifier as this increases |
| * the risk of conflicts. We recommend you add at most one extension field, |
| * an object which can contain all the values you need. |
| */ |
|
|
| /** |
| * Schema Definition |
| * |
| * A Schema is created by supplying the root types of each type of operation, |
| * query and mutation (optional). A schema definition is then supplied to the |
| * validator and executor. |
| * |
| * Example: |
| * |
| * ```ts |
| * const MyAppSchema = new GraphQLSchema({ |
| * query: MyAppQueryRootType, |
| * mutation: MyAppMutationRootType, |
| * }) |
| * ``` |
| * |
| * Note: When the schema is constructed, by default only the types that are |
| * reachable by traversing the root types are included, other types must be |
| * explicitly referenced. |
| * |
| * Example: |
| * |
| * ```ts |
| * const characterInterface = new GraphQLInterfaceType({ |
| * name: 'Character', |
| * ... |
| * }); |
| * |
| * const humanType = new GraphQLObjectType({ |
| * name: 'Human', |
| * interfaces: [characterInterface], |
| * ... |
| * }); |
| * |
| * const droidType = new GraphQLObjectType({ |
| * name: 'Droid', |
| * interfaces: [characterInterface], |
| * ... |
| * }); |
| * |
| * const schema = new GraphQLSchema({ |
| * query: new GraphQLObjectType({ |
| * name: 'Query', |
| * fields: { |
| * hero: { type: characterInterface, ... }, |
| * } |
| * }), |
| * ... |
| * // Since this schema references only the `Character` interface it's |
| * // necessary to explicitly list the types that implement it if |
| * // you want them to be included in the final schema. |
| * types: [humanType, droidType], |
| * }) |
| * ``` |
| * |
| * Note: If an array of `directives` are provided to GraphQLSchema, that will be |
| * the exact list of directives represented and allowed. If `directives` is not |
| * provided then a default set of the specified directives (e.g. `@include` and |
| * `@skip`) will be used. If you wish to provide *additional* directives to these |
| * specified directives, you must explicitly declare them. Example: |
| * |
| * ```ts |
| * const MyAppSchema = new GraphQLSchema({ |
| * ... |
| * directives: specifiedDirectives.concat([ myCustomDirective ]), |
| * }) |
| * ``` |
| */ |
| class GraphQLSchema { |
| // Used as a cache for validateSchema(). |
| constructor(config) { |
| var _config$extensionASTN, _config$directives; |
|
|
| // If this schema was built from a source known to be valid, then it may be |
| // marked with assumeValid to avoid an additional type system validation. |
| this.__validationErrors = config.assumeValid === true ? [] : undefined; // Check for common mistakes during construction to produce early errors. |
|
|
| (0, _isObjectLike.isObjectLike)(config) || |
| (0, _devAssert.devAssert)(false, 'Must provide configuration object.'); |
| !config.types || |
| Array.isArray(config.types) || |
| (0, _devAssert.devAssert)( |
| false, |
| `"types" must be Array if provided but got: ${(0, _inspect.inspect)( |
| config.types, |
| )}.`, |
| ); |
| !config.directives || |
| Array.isArray(config.directives) || |
| (0, _devAssert.devAssert)( |
| false, |
| '"directives" must be Array if provided but got: ' + |
| `${(0, _inspect.inspect)(config.directives)}.`, |
| ); |
| this.description = config.description; |
| this.extensions = (0, _toObjMap.toObjMap)(config.extensions); |
| this.astNode = config.astNode; |
| this.extensionASTNodes = |
| (_config$extensionASTN = config.extensionASTNodes) !== null && |
| _config$extensionASTN !== void 0 |
| ? _config$extensionASTN |
| : []; |
| this._queryType = config.query; |
| this._mutationType = config.mutation; |
| this._subscriptionType = config.subscription; // Provide specified directives (e.g. @include and @skip) by default. |
|
|
| this._directives = |
| (_config$directives = config.directives) !== null && |
| _config$directives !== void 0 |
| ? _config$directives |
| : _directives.specifiedDirectives; // To preserve order of user-provided types, we add first to add them to |
| // the set of "collected" types, so `collectReferencedTypes` ignore them. |
|
|
| const allReferencedTypes = new Set(config.types); |
|
|
| if (config.types != null) { |
| for (const type of config.types) { |
| // When we ready to process this type, we remove it from "collected" types |
| // and then add it together with all dependent types in the correct position. |
| allReferencedTypes.delete(type); |
| collectReferencedTypes(type, allReferencedTypes); |
| } |
| } |
|
|
| if (this._queryType != null) { |
| collectReferencedTypes(this._queryType, allReferencedTypes); |
| } |
|
|
| if (this._mutationType != null) { |
| collectReferencedTypes(this._mutationType, allReferencedTypes); |
| } |
|
|
| if (this._subscriptionType != null) { |
| collectReferencedTypes(this._subscriptionType, allReferencedTypes); |
| } |
|
|
| for (const directive of this._directives) { |
| // Directives are not validated until validateSchema() is called. |
| if ((0, _directives.isDirective)(directive)) { |
| for (const arg of directive.args) { |
| collectReferencedTypes(arg.type, allReferencedTypes); |
| } |
| } |
| } |
|
|
| collectReferencedTypes(_introspection.__Schema, allReferencedTypes); // Storing the resulting map for reference by the schema. |
|
|
| this._typeMap = Object.create(null); |
| this._subTypeMap = Object.create(null); // Keep track of all implementations by interface name. |
|
|
| this._implementationsMap = Object.create(null); |
|
|
| for (const namedType of allReferencedTypes) { |
| if (namedType == null) { |
| continue; |
| } |
|
|
| const typeName = namedType.name; |
| typeName || |
| (0, _devAssert.devAssert)( |
| false, |
| 'One of the provided types for building the Schema is missing a name.', |
| ); |
|
|
| if (this._typeMap[typeName] !== undefined) { |
| throw new Error( |
| `Schema must contain uniquely named types but contains multiple types named "${typeName}".`, |
| ); |
| } |
|
|
| this._typeMap[typeName] = namedType; |
|
|
| if ((0, _definition.isInterfaceType)(namedType)) { |
| // Store implementations by interface. |
| for (const iface of namedType.getInterfaces()) { |
| if ((0, _definition.isInterfaceType)(iface)) { |
| let implementations = this._implementationsMap[iface.name]; |
|
|
| if (implementations === undefined) { |
| implementations = this._implementationsMap[iface.name] = { |
| objects: [], |
| interfaces: [], |
| }; |
| } |
|
|
| implementations.interfaces.push(namedType); |
| } |
| } |
| } else if ((0, _definition.isObjectType)(namedType)) { |
| // Store implementations by objects. |
| for (const iface of namedType.getInterfaces()) { |
| if ((0, _definition.isInterfaceType)(iface)) { |
| let implementations = this._implementationsMap[iface.name]; |
|
|
| if (implementations === undefined) { |
| implementations = this._implementationsMap[iface.name] = { |
| objects: [], |
| interfaces: [], |
| }; |
| } |
|
|
| implementations.objects.push(namedType); |
| } |
| } |
| } |
| } |
| } |
|
|
| get [Symbol.toStringTag]() { |
| return 'GraphQLSchema'; |
| } |
|
|
| getQueryType() { |
| return this._queryType; |
| } |
|
|
| getMutationType() { |
| return this._mutationType; |
| } |
|
|
| getSubscriptionType() { |
| return this._subscriptionType; |
| } |
|
|
| getRootType(operation) { |
| switch (operation) { |
| case _ast.OperationTypeNode.QUERY: |
| return this.getQueryType(); |
|
|
| case _ast.OperationTypeNode.MUTATION: |
| return this.getMutationType(); |
|
|
| case _ast.OperationTypeNode.SUBSCRIPTION: |
| return this.getSubscriptionType(); |
| } |
| } |
|
|
| getTypeMap() { |
| return this._typeMap; |
| } |
|
|
| getType(name) { |
| return this.getTypeMap()[name]; |
| } |
|
|
| getPossibleTypes(abstractType) { |
| return (0, _definition.isUnionType)(abstractType) |
| ? abstractType.getTypes() |
| : this.getImplementations(abstractType).objects; |
| } |
|
|
| getImplementations(interfaceType) { |
| const implementations = this._implementationsMap[interfaceType.name]; |
| return implementations !== null && implementations !== void 0 |
| ? implementations |
| : { |
| objects: [], |
| interfaces: [], |
| }; |
| } |
|
|
| isSubType(abstractType, maybeSubType) { |
| let map = this._subTypeMap[abstractType.name]; |
|
|
| if (map === undefined) { |
| map = Object.create(null); |
|
|
| if ((0, _definition.isUnionType)(abstractType)) { |
| for (const type of abstractType.getTypes()) { |
| map[type.name] = true; |
| } |
| } else { |
| const implementations = this.getImplementations(abstractType); |
|
|
| for (const type of implementations.objects) { |
| map[type.name] = true; |
| } |
|
|
| for (const type of implementations.interfaces) { |
| map[type.name] = true; |
| } |
| } |
|
|
| this._subTypeMap[abstractType.name] = map; |
| } |
|
|
| return map[maybeSubType.name] !== undefined; |
| } |
|
|
| getDirectives() { |
| return this._directives; |
| } |
|
|
| getDirective(name) { |
| return this.getDirectives().find((directive) => directive.name === name); |
| } |
|
|
| toConfig() { |
| return { |
| description: this.description, |
| query: this.getQueryType(), |
| mutation: this.getMutationType(), |
| subscription: this.getSubscriptionType(), |
| types: Object.values(this.getTypeMap()), |
| directives: this.getDirectives(), |
| extensions: this.extensions, |
| astNode: this.astNode, |
| extensionASTNodes: this.extensionASTNodes, |
| assumeValid: this.__validationErrors !== undefined, |
| }; |
| } |
| } |
|
|
| exports.GraphQLSchema = GraphQLSchema; |
|
|
| function collectReferencedTypes(type, typeSet) { |
| const namedType = (0, _definition.getNamedType)(type); |
|
|
| if (!typeSet.has(namedType)) { |
| typeSet.add(namedType); |
|
|
| if ((0, _definition.isUnionType)(namedType)) { |
| for (const memberType of namedType.getTypes()) { |
| collectReferencedTypes(memberType, typeSet); |
| } |
| } else if ( |
| (0, _definition.isObjectType)(namedType) || |
| (0, _definition.isInterfaceType)(namedType) |
| ) { |
| for (const interfaceType of namedType.getInterfaces()) { |
| collectReferencedTypes(interfaceType, typeSet); |
| } |
|
|
| for (const field of Object.values(namedType.getFields())) { |
| collectReferencedTypes(field.type, typeSet); |
|
|
| for (const arg of field.args) { |
| collectReferencedTypes(arg.type, typeSet); |
| } |
| } |
| } else if ((0, _definition.isInputObjectType)(namedType)) { |
| for (const field of Object.values(namedType.getFields())) { |
| collectReferencedTypes(field.type, typeSet); |
| } |
| } |
| } |
|
|
| return typeSet; |
| } |