mirror of
https://github.com/JamesIves/github-pages-deploy-action.git
synced 2023-12-15 20:03:39 +08:00
749 lines
23 KiB
Plaintext
749 lines
23 KiB
Plaintext
// @flow strict
|
|
|
|
import objectValues from '../polyfills/objectValues';
|
|
|
|
import keyMap from '../jsutils/keyMap';
|
|
import inspect from '../jsutils/inspect';
|
|
import mapValue from '../jsutils/mapValue';
|
|
import invariant from '../jsutils/invariant';
|
|
import devAssert from '../jsutils/devAssert';
|
|
|
|
import { Kind } from '../language/kinds';
|
|
import { TokenKind } from '../language/tokenKind';
|
|
import { dedentBlockStringValue } from '../language/blockString';
|
|
import { type DirectiveLocationEnum } from '../language/directiveLocation';
|
|
import {
|
|
isTypeDefinitionNode,
|
|
isTypeExtensionNode,
|
|
} from '../language/predicates';
|
|
import {
|
|
type Location,
|
|
type DocumentNode,
|
|
type StringValueNode,
|
|
type TypeNode,
|
|
type NamedTypeNode,
|
|
type SchemaDefinitionNode,
|
|
type SchemaExtensionNode,
|
|
type TypeDefinitionNode,
|
|
type InterfaceTypeDefinitionNode,
|
|
type InterfaceTypeExtensionNode,
|
|
type ObjectTypeDefinitionNode,
|
|
type ObjectTypeExtensionNode,
|
|
type UnionTypeDefinitionNode,
|
|
type UnionTypeExtensionNode,
|
|
type FieldDefinitionNode,
|
|
type InputObjectTypeDefinitionNode,
|
|
type InputObjectTypeExtensionNode,
|
|
type InputValueDefinitionNode,
|
|
type EnumTypeDefinitionNode,
|
|
type EnumTypeExtensionNode,
|
|
type EnumValueDefinitionNode,
|
|
type DirectiveDefinitionNode,
|
|
} from '../language/ast';
|
|
|
|
import { assertValidSDLExtension } from '../validation/validate';
|
|
|
|
import { getDirectiveValues } from '../execution/values';
|
|
|
|
import { specifiedScalarTypes, isSpecifiedScalarType } from '../type/scalars';
|
|
import { introspectionTypes, isIntrospectionType } from '../type/introspection';
|
|
import {
|
|
GraphQLDirective,
|
|
GraphQLDeprecatedDirective,
|
|
} from '../type/directives';
|
|
import {
|
|
type GraphQLSchemaValidationOptions,
|
|
assertSchema,
|
|
GraphQLSchema,
|
|
type GraphQLSchemaNormalizedConfig,
|
|
} from '../type/schema';
|
|
import {
|
|
type GraphQLType,
|
|
type GraphQLNamedType,
|
|
type GraphQLFieldConfigMap,
|
|
type GraphQLEnumValueConfigMap,
|
|
type GraphQLInputFieldConfigMap,
|
|
type GraphQLFieldConfigArgumentMap,
|
|
isScalarType,
|
|
isObjectType,
|
|
isInterfaceType,
|
|
isUnionType,
|
|
isListType,
|
|
isNonNullType,
|
|
isEnumType,
|
|
isInputObjectType,
|
|
GraphQLList,
|
|
GraphQLNonNull,
|
|
GraphQLScalarType,
|
|
GraphQLObjectType,
|
|
GraphQLInterfaceType,
|
|
GraphQLUnionType,
|
|
GraphQLEnumType,
|
|
GraphQLInputObjectType,
|
|
} from '../type/definition';
|
|
|
|
import { valueFromAST } from './valueFromAST';
|
|
|
|
type Options = {|
|
|
...GraphQLSchemaValidationOptions,
|
|
|
|
/**
|
|
* Descriptions are defined as preceding string literals, however an older
|
|
* experimental version of the SDL supported preceding comments as
|
|
* descriptions. Set to true to enable this deprecated behavior.
|
|
* This option is provided to ease adoption and will be removed in v16.
|
|
*
|
|
* Default: false
|
|
*/
|
|
commentDescriptions?: boolean,
|
|
|
|
/**
|
|
* Set to true to assume the SDL is valid.
|
|
*
|
|
* Default: false
|
|
*/
|
|
assumeValidSDL?: boolean,
|
|
|};
|
|
|
|
/**
|
|
* Produces a new schema given an existing schema and a document which may
|
|
* contain GraphQL type extensions and definitions. The original schema will
|
|
* remain unaltered.
|
|
*
|
|
* Because a schema represents a graph of references, a schema cannot be
|
|
* extended without effectively making an entire copy. We do not know until it's
|
|
* too late if subgraphs remain unchanged.
|
|
*
|
|
* This algorithm copies the provided schema, applying extensions while
|
|
* producing the copy. The original schema remains unaltered.
|
|
*
|
|
* Accepts options as a third argument:
|
|
*
|
|
* - commentDescriptions:
|
|
* Provide true to use preceding comments as the description.
|
|
*
|
|
*/
|
|
export function extendSchema(
|
|
schema: GraphQLSchema,
|
|
documentAST: DocumentNode,
|
|
options?: Options,
|
|
): GraphQLSchema {
|
|
assertSchema(schema);
|
|
|
|
devAssert(
|
|
documentAST != null && documentAST.kind === Kind.DOCUMENT,
|
|
'Must provide valid Document AST.',
|
|
);
|
|
|
|
if (options?.assumeValid !== true && options?.assumeValidSDL !== true) {
|
|
assertValidSDLExtension(documentAST, schema);
|
|
}
|
|
|
|
const schemaConfig = schema.toConfig();
|
|
const extendedConfig = extendSchemaImpl(schemaConfig, documentAST, options);
|
|
return schemaConfig === extendedConfig
|
|
? schema
|
|
: new GraphQLSchema(extendedConfig);
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
export function extendSchemaImpl(
|
|
schemaConfig: GraphQLSchemaNormalizedConfig,
|
|
documentAST: DocumentNode,
|
|
options?: Options,
|
|
): GraphQLSchemaNormalizedConfig {
|
|
// Collect the type definitions and extensions found in the document.
|
|
const typeDefs: Array<TypeDefinitionNode> = [];
|
|
const typeExtensionsMap = Object.create(null);
|
|
|
|
// New directives and types are separate because a directives and types can
|
|
// have the same name. For example, a type named "skip".
|
|
const directiveDefs: Array<DirectiveDefinitionNode> = [];
|
|
|
|
let schemaDef: ?SchemaDefinitionNode;
|
|
// Schema extensions are collected which may add additional operation types.
|
|
const schemaExtensions: Array<SchemaExtensionNode> = [];
|
|
|
|
for (const def of documentAST.definitions) {
|
|
if (def.kind === Kind.SCHEMA_DEFINITION) {
|
|
schemaDef = def;
|
|
} else if (def.kind === Kind.SCHEMA_EXTENSION) {
|
|
schemaExtensions.push(def);
|
|
} else if (isTypeDefinitionNode(def)) {
|
|
typeDefs.push(def);
|
|
} else if (isTypeExtensionNode(def)) {
|
|
const extendedTypeName = def.name.value;
|
|
const existingTypeExtensions = typeExtensionsMap[extendedTypeName];
|
|
typeExtensionsMap[extendedTypeName] = existingTypeExtensions
|
|
? existingTypeExtensions.concat([def])
|
|
: [def];
|
|
} else if (def.kind === Kind.DIRECTIVE_DEFINITION) {
|
|
directiveDefs.push(def);
|
|
}
|
|
}
|
|
|
|
// If this document contains no new types, extensions, or directives then
|
|
// return the same unmodified GraphQLSchema instance.
|
|
if (
|
|
Object.keys(typeExtensionsMap).length === 0 &&
|
|
typeDefs.length === 0 &&
|
|
directiveDefs.length === 0 &&
|
|
schemaExtensions.length === 0 &&
|
|
schemaDef == null
|
|
) {
|
|
return schemaConfig;
|
|
}
|
|
|
|
const typeMap = Object.create(null);
|
|
for (const existingType of schemaConfig.types) {
|
|
typeMap[existingType.name] = extendNamedType(existingType);
|
|
}
|
|
|
|
for (const typeNode of typeDefs) {
|
|
const name = typeNode.name.value;
|
|
typeMap[name] = stdTypeMap[name] ?? buildType(typeNode);
|
|
}
|
|
|
|
const operationTypes = {
|
|
// Get the extended root operation types.
|
|
query: schemaConfig.query && replaceNamedType(schemaConfig.query),
|
|
mutation: schemaConfig.mutation && replaceNamedType(schemaConfig.mutation),
|
|
subscription:
|
|
schemaConfig.subscription && replaceNamedType(schemaConfig.subscription),
|
|
// Then, incorporate schema definition and all schema extensions.
|
|
...(schemaDef && getOperationTypes([schemaDef])),
|
|
...getOperationTypes(schemaExtensions),
|
|
};
|
|
|
|
// Then produce and return a Schema config with these types.
|
|
return {
|
|
description: schemaDef?.description?.value,
|
|
...operationTypes,
|
|
types: objectValues(typeMap),
|
|
directives: [
|
|
...schemaConfig.directives.map(replaceDirective),
|
|
...directiveDefs.map(buildDirective),
|
|
],
|
|
extensions: undefined,
|
|
astNode: schemaDef ?? schemaConfig.astNode,
|
|
extensionASTNodes: schemaConfig.extensionASTNodes.concat(schemaExtensions),
|
|
assumeValid: options?.assumeValid ?? false,
|
|
};
|
|
|
|
// Below are functions used for producing this schema that have closed over
|
|
// this scope and have access to the schema, cache, and newly defined types.
|
|
|
|
function replaceType(type) {
|
|
if (isListType(type)) {
|
|
return new GraphQLList(replaceType(type.ofType));
|
|
} else if (isNonNullType(type)) {
|
|
return new GraphQLNonNull(replaceType(type.ofType));
|
|
}
|
|
return replaceNamedType(type);
|
|
}
|
|
|
|
function replaceNamedType<T: GraphQLNamedType>(type: T): T {
|
|
// Note: While this could make early assertions to get the correctly
|
|
// typed values, that would throw immediately while type system
|
|
// validation with validateSchema() will produce more actionable results.
|
|
return ((typeMap[type.name]: any): T);
|
|
}
|
|
|
|
function replaceDirective(directive: GraphQLDirective): GraphQLDirective {
|
|
const config = directive.toConfig();
|
|
return new GraphQLDirective({
|
|
...config,
|
|
args: mapValue(config.args, extendArg),
|
|
});
|
|
}
|
|
|
|
function extendNamedType(type: GraphQLNamedType): GraphQLNamedType {
|
|
if (isIntrospectionType(type) || isSpecifiedScalarType(type)) {
|
|
// Builtin types are not extended.
|
|
return type;
|
|
}
|
|
if (isScalarType(type)) {
|
|
return extendScalarType(type);
|
|
}
|
|
if (isObjectType(type)) {
|
|
return extendObjectType(type);
|
|
}
|
|
if (isInterfaceType(type)) {
|
|
return extendInterfaceType(type);
|
|
}
|
|
if (isUnionType(type)) {
|
|
return extendUnionType(type);
|
|
}
|
|
if (isEnumType(type)) {
|
|
return extendEnumType(type);
|
|
}
|
|
if (isInputObjectType(type)) {
|
|
return extendInputObjectType(type);
|
|
}
|
|
|
|
// Not reachable. All possible types have been considered.
|
|
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
|
|
}
|
|
|
|
function extendInputObjectType(
|
|
type: GraphQLInputObjectType,
|
|
): GraphQLInputObjectType {
|
|
const config = type.toConfig();
|
|
const extensions = typeExtensionsMap[config.name] ?? [];
|
|
|
|
return new GraphQLInputObjectType({
|
|
...config,
|
|
fields: () => ({
|
|
...mapValue(config.fields, field => ({
|
|
...field,
|
|
type: replaceType(field.type),
|
|
})),
|
|
...buildInputFieldMap(extensions),
|
|
}),
|
|
extensionASTNodes: config.extensionASTNodes.concat(extensions),
|
|
});
|
|
}
|
|
|
|
function extendEnumType(type: GraphQLEnumType): GraphQLEnumType {
|
|
const config = type.toConfig();
|
|
const extensions = typeExtensionsMap[type.name] ?? [];
|
|
|
|
return new GraphQLEnumType({
|
|
...config,
|
|
values: {
|
|
...config.values,
|
|
...buildEnumValueMap(extensions),
|
|
},
|
|
extensionASTNodes: config.extensionASTNodes.concat(extensions),
|
|
});
|
|
}
|
|
|
|
function extendScalarType(type: GraphQLScalarType): GraphQLScalarType {
|
|
const config = type.toConfig();
|
|
const extensions = typeExtensionsMap[config.name] ?? [];
|
|
|
|
return new GraphQLScalarType({
|
|
...config,
|
|
extensionASTNodes: config.extensionASTNodes.concat(extensions),
|
|
});
|
|
}
|
|
|
|
function extendObjectType(type: GraphQLObjectType): GraphQLObjectType {
|
|
const config = type.toConfig();
|
|
const extensions = typeExtensionsMap[config.name] ?? [];
|
|
|
|
return new GraphQLObjectType({
|
|
...config,
|
|
interfaces: () => [
|
|
...type.getInterfaces().map(replaceNamedType),
|
|
...buildInterfaces(extensions),
|
|
],
|
|
fields: () => ({
|
|
...mapValue(config.fields, extendField),
|
|
...buildFieldMap(extensions),
|
|
}),
|
|
extensionASTNodes: config.extensionASTNodes.concat(extensions),
|
|
});
|
|
}
|
|
|
|
function extendInterfaceType(
|
|
type: GraphQLInterfaceType,
|
|
): GraphQLInterfaceType {
|
|
const config = type.toConfig();
|
|
const extensions = typeExtensionsMap[config.name] ?? [];
|
|
|
|
return new GraphQLInterfaceType({
|
|
...config,
|
|
interfaces: () => [
|
|
...type.getInterfaces().map(replaceNamedType),
|
|
...buildInterfaces(extensions),
|
|
],
|
|
fields: () => ({
|
|
...mapValue(config.fields, extendField),
|
|
...buildFieldMap(extensions),
|
|
}),
|
|
extensionASTNodes: config.extensionASTNodes.concat(extensions),
|
|
});
|
|
}
|
|
|
|
function extendUnionType(type: GraphQLUnionType): GraphQLUnionType {
|
|
const config = type.toConfig();
|
|
const extensions = typeExtensionsMap[config.name] ?? [];
|
|
|
|
return new GraphQLUnionType({
|
|
...config,
|
|
types: () => [
|
|
...type.getTypes().map(replaceNamedType),
|
|
...buildUnionTypes(extensions),
|
|
],
|
|
extensionASTNodes: config.extensionASTNodes.concat(extensions),
|
|
});
|
|
}
|
|
|
|
function extendField(field) {
|
|
return {
|
|
...field,
|
|
type: replaceType(field.type),
|
|
args: mapValue(field.args, extendArg),
|
|
};
|
|
}
|
|
|
|
function extendArg(arg) {
|
|
return {
|
|
...arg,
|
|
type: replaceType(arg.type),
|
|
};
|
|
}
|
|
|
|
function getOperationTypes(
|
|
nodes: $ReadOnlyArray<SchemaDefinitionNode | SchemaExtensionNode>,
|
|
): {|
|
|
query: ?GraphQLObjectType,
|
|
mutation: ?GraphQLObjectType,
|
|
subscription: ?GraphQLObjectType,
|
|
|} {
|
|
const opTypes = {};
|
|
for (const node of nodes) {
|
|
/* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */
|
|
const operationTypesNodes = node.operationTypes ?? [];
|
|
|
|
for (const operationType of operationTypesNodes) {
|
|
opTypes[operationType.operation] = getNamedType(operationType.type);
|
|
}
|
|
}
|
|
|
|
// Note: While this could make early assertions to get the correctly
|
|
// typed values below, that would throw immediately while type system
|
|
// validation with validateSchema() will produce more actionable results.
|
|
return (opTypes: any);
|
|
}
|
|
|
|
function getNamedType(node: NamedTypeNode): GraphQLNamedType {
|
|
const name = node.name.value;
|
|
const type = stdTypeMap[name] ?? typeMap[name];
|
|
|
|
if (type === undefined) {
|
|
throw new Error(`Unknown type: "${name}".`);
|
|
}
|
|
return type;
|
|
}
|
|
|
|
function getWrappedType(node: TypeNode): GraphQLType {
|
|
if (node.kind === Kind.LIST_TYPE) {
|
|
return new GraphQLList(getWrappedType(node.type));
|
|
}
|
|
if (node.kind === Kind.NON_NULL_TYPE) {
|
|
return new GraphQLNonNull(getWrappedType(node.type));
|
|
}
|
|
return getNamedType(node);
|
|
}
|
|
|
|
function buildDirective(node: DirectiveDefinitionNode): GraphQLDirective {
|
|
const locations = node.locations.map(
|
|
({ value }) => ((value: any): DirectiveLocationEnum),
|
|
);
|
|
|
|
return new GraphQLDirective({
|
|
name: node.name.value,
|
|
description: getDescription(node, options),
|
|
locations,
|
|
isRepeatable: node.repeatable,
|
|
args: buildArgumentMap(node.arguments),
|
|
astNode: node,
|
|
});
|
|
}
|
|
|
|
function buildFieldMap(
|
|
nodes: $ReadOnlyArray<
|
|
| InterfaceTypeDefinitionNode
|
|
| InterfaceTypeExtensionNode
|
|
| ObjectTypeDefinitionNode
|
|
| ObjectTypeExtensionNode,
|
|
>,
|
|
): GraphQLFieldConfigMap<mixed, mixed> {
|
|
const fieldConfigMap = Object.create(null);
|
|
for (const node of nodes) {
|
|
/* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */
|
|
const nodeFields = node.fields ?? [];
|
|
|
|
for (const field of nodeFields) {
|
|
fieldConfigMap[field.name.value] = {
|
|
// Note: While this could make assertions to get the correctly typed
|
|
// value, that would throw immediately while type system validation
|
|
// with validateSchema() will produce more actionable results.
|
|
type: (getWrappedType(field.type): any),
|
|
description: getDescription(field, options),
|
|
args: buildArgumentMap(field.arguments),
|
|
deprecationReason: getDeprecationReason(field),
|
|
astNode: field,
|
|
};
|
|
}
|
|
}
|
|
return fieldConfigMap;
|
|
}
|
|
|
|
function buildArgumentMap(
|
|
args: ?$ReadOnlyArray<InputValueDefinitionNode>,
|
|
): GraphQLFieldConfigArgumentMap {
|
|
/* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */
|
|
const argsNodes = args ?? [];
|
|
|
|
const argConfigMap = Object.create(null);
|
|
for (const arg of argsNodes) {
|
|
// Note: While this could make assertions to get the correctly typed
|
|
// value, that would throw immediately while type system validation
|
|
// with validateSchema() will produce more actionable results.
|
|
const type: any = getWrappedType(arg.type);
|
|
|
|
argConfigMap[arg.name.value] = {
|
|
type,
|
|
description: getDescription(arg, options),
|
|
defaultValue: valueFromAST(arg.defaultValue, type),
|
|
astNode: arg,
|
|
};
|
|
}
|
|
return argConfigMap;
|
|
}
|
|
|
|
function buildInputFieldMap(
|
|
nodes: $ReadOnlyArray<
|
|
InputObjectTypeDefinitionNode | InputObjectTypeExtensionNode,
|
|
>,
|
|
): GraphQLInputFieldConfigMap {
|
|
const inputFieldMap = Object.create(null);
|
|
for (const node of nodes) {
|
|
/* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */
|
|
const fieldsNodes = node.fields ?? [];
|
|
|
|
for (const field of fieldsNodes) {
|
|
// Note: While this could make assertions to get the correctly typed
|
|
// value, that would throw immediately while type system validation
|
|
// with validateSchema() will produce more actionable results.
|
|
const type: any = getWrappedType(field.type);
|
|
|
|
inputFieldMap[field.name.value] = {
|
|
type,
|
|
description: getDescription(field, options),
|
|
defaultValue: valueFromAST(field.defaultValue, type),
|
|
astNode: field,
|
|
};
|
|
}
|
|
}
|
|
return inputFieldMap;
|
|
}
|
|
|
|
function buildEnumValueMap(
|
|
nodes: $ReadOnlyArray<EnumTypeDefinitionNode | EnumTypeExtensionNode>,
|
|
): GraphQLEnumValueConfigMap {
|
|
const enumValueMap = Object.create(null);
|
|
for (const node of nodes) {
|
|
/* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */
|
|
const valuesNodes = node.values ?? [];
|
|
|
|
for (const value of valuesNodes) {
|
|
enumValueMap[value.name.value] = {
|
|
description: getDescription(value, options),
|
|
deprecationReason: getDeprecationReason(value),
|
|
astNode: value,
|
|
};
|
|
}
|
|
}
|
|
return enumValueMap;
|
|
}
|
|
|
|
function buildInterfaces(
|
|
nodes: $ReadOnlyArray<
|
|
| InterfaceTypeDefinitionNode
|
|
| InterfaceTypeExtensionNode
|
|
| ObjectTypeDefinitionNode
|
|
| ObjectTypeExtensionNode,
|
|
>,
|
|
): Array<GraphQLInterfaceType> {
|
|
const interfaces = [];
|
|
for (const node of nodes) {
|
|
/* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */
|
|
const interfacesNodes = node.interfaces ?? [];
|
|
|
|
for (const type of interfacesNodes) {
|
|
// Note: While this could make assertions to get the correctly typed
|
|
// values below, that would throw immediately while type system
|
|
// validation with validateSchema() will produce more actionable
|
|
// results.
|
|
interfaces.push((getNamedType(type): any));
|
|
}
|
|
}
|
|
return interfaces;
|
|
}
|
|
|
|
function buildUnionTypes(
|
|
nodes: $ReadOnlyArray<UnionTypeDefinitionNode | UnionTypeExtensionNode>,
|
|
): Array<GraphQLObjectType> {
|
|
const types = [];
|
|
for (const node of nodes) {
|
|
/* istanbul ignore next (See https://github.com/graphql/graphql-js/issues/2203) */
|
|
const typeNodes = node.types ?? [];
|
|
|
|
for (const type of typeNodes) {
|
|
// Note: While this could make assertions to get the correctly typed
|
|
// values below, that would throw immediately while type system
|
|
// validation with validateSchema() will produce more actionable
|
|
// results.
|
|
types.push((getNamedType(type): any));
|
|
}
|
|
}
|
|
return types;
|
|
}
|
|
|
|
function buildType(astNode: TypeDefinitionNode): GraphQLNamedType {
|
|
const name = astNode.name.value;
|
|
const description = getDescription(astNode, options);
|
|
const extensionNodes = typeExtensionsMap[name] ?? [];
|
|
|
|
switch (astNode.kind) {
|
|
case Kind.OBJECT_TYPE_DEFINITION: {
|
|
const extensionASTNodes = (extensionNodes: any);
|
|
const allNodes = [astNode, ...extensionASTNodes];
|
|
|
|
return new GraphQLObjectType({
|
|
name,
|
|
description,
|
|
interfaces: () => buildInterfaces(allNodes),
|
|
fields: () => buildFieldMap(allNodes),
|
|
astNode,
|
|
extensionASTNodes,
|
|
});
|
|
}
|
|
case Kind.INTERFACE_TYPE_DEFINITION: {
|
|
const extensionASTNodes = (extensionNodes: any);
|
|
const allNodes = [astNode, ...extensionASTNodes];
|
|
|
|
return new GraphQLInterfaceType({
|
|
name,
|
|
description,
|
|
interfaces: () => buildInterfaces(allNodes),
|
|
fields: () => buildFieldMap(allNodes),
|
|
astNode,
|
|
extensionASTNodes,
|
|
});
|
|
}
|
|
case Kind.ENUM_TYPE_DEFINITION: {
|
|
const extensionASTNodes = (extensionNodes: any);
|
|
const allNodes = [astNode, ...extensionASTNodes];
|
|
|
|
return new GraphQLEnumType({
|
|
name,
|
|
description,
|
|
values: buildEnumValueMap(allNodes),
|
|
astNode,
|
|
extensionASTNodes,
|
|
});
|
|
}
|
|
case Kind.UNION_TYPE_DEFINITION: {
|
|
const extensionASTNodes = (extensionNodes: any);
|
|
const allNodes = [astNode, ...extensionASTNodes];
|
|
|
|
return new GraphQLUnionType({
|
|
name,
|
|
description,
|
|
types: () => buildUnionTypes(allNodes),
|
|
astNode,
|
|
extensionASTNodes,
|
|
});
|
|
}
|
|
case Kind.SCALAR_TYPE_DEFINITION: {
|
|
const extensionASTNodes = (extensionNodes: any);
|
|
|
|
return new GraphQLScalarType({
|
|
name,
|
|
description,
|
|
astNode,
|
|
extensionASTNodes,
|
|
});
|
|
}
|
|
case Kind.INPUT_OBJECT_TYPE_DEFINITION: {
|
|
const extensionASTNodes = (extensionNodes: any);
|
|
const allNodes = [astNode, ...extensionASTNodes];
|
|
|
|
return new GraphQLInputObjectType({
|
|
name,
|
|
description,
|
|
fields: () => buildInputFieldMap(allNodes),
|
|
astNode,
|
|
extensionASTNodes,
|
|
});
|
|
}
|
|
}
|
|
|
|
// Not reachable. All possible type definition nodes have been considered.
|
|
invariant(
|
|
false,
|
|
'Unexpected type definition node: ' + inspect((astNode: empty)),
|
|
);
|
|
}
|
|
}
|
|
|
|
const stdTypeMap = keyMap(
|
|
specifiedScalarTypes.concat(introspectionTypes),
|
|
type => type.name,
|
|
);
|
|
|
|
/**
|
|
* Given a field or enum value node, returns the string value for the
|
|
* deprecation reason.
|
|
*/
|
|
function getDeprecationReason(
|
|
node: EnumValueDefinitionNode | FieldDefinitionNode,
|
|
): ?string {
|
|
const deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node);
|
|
return (deprecated?.reason: any);
|
|
}
|
|
|
|
/**
|
|
* Given an ast node, returns its string description.
|
|
* @deprecated: provided to ease adoption and will be removed in v16.
|
|
*
|
|
* Accepts options as a second argument:
|
|
*
|
|
* - commentDescriptions:
|
|
* Provide true to use preceding comments as the description.
|
|
*
|
|
*/
|
|
export function getDescription(
|
|
node: { +description?: StringValueNode, +loc?: Location, ... },
|
|
options: ?{ commentDescriptions?: boolean, ... },
|
|
): void | string {
|
|
if (node.description) {
|
|
return node.description.value;
|
|
}
|
|
if (options?.commentDescriptions === true) {
|
|
const rawValue = getLeadingCommentBlock(node);
|
|
if (rawValue !== undefined) {
|
|
return dedentBlockStringValue('\n' + rawValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getLeadingCommentBlock(node): void | string {
|
|
const loc = node.loc;
|
|
if (!loc) {
|
|
return;
|
|
}
|
|
const comments = [];
|
|
let token = loc.startToken.prev;
|
|
while (
|
|
token != null &&
|
|
token.kind === TokenKind.COMMENT &&
|
|
token.next &&
|
|
token.prev &&
|
|
token.line + 1 === token.next.line &&
|
|
token.line !== token.prev.line
|
|
) {
|
|
const value = String(token.value);
|
|
comments.push(value);
|
|
token = token.prev;
|
|
}
|
|
return comments.length > 0 ? comments.reverse().join('\n') : undefined;
|
|
}
|