buildASTSchema.js.flow 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // @flow strict
  2. import devAssert from '../jsutils/devAssert';
  3. import type { Source } from '../language/source';
  4. import type { DocumentNode } from '../language/ast';
  5. import type { ParseOptions } from '../language/parser';
  6. import { Kind } from '../language/kinds';
  7. import { parse } from '../language/parser';
  8. import { assertValidSDL } from '../validation/validate';
  9. import type { GraphQLSchemaValidationOptions } from '../type/schema';
  10. import { GraphQLSchema } from '../type/schema';
  11. import {
  12. GraphQLSkipDirective,
  13. GraphQLIncludeDirective,
  14. GraphQLDeprecatedDirective,
  15. GraphQLSpecifiedByDirective,
  16. } from '../type/directives';
  17. import { extendSchemaImpl } from './extendSchema';
  18. export type BuildSchemaOptions = {|
  19. ...GraphQLSchemaValidationOptions,
  20. /**
  21. * Descriptions are defined as preceding string literals, however an older
  22. * experimental version of the SDL supported preceding comments as
  23. * descriptions. Set to true to enable this deprecated behavior.
  24. * This option is provided to ease adoption and will be removed in v16.
  25. *
  26. * Default: false
  27. */
  28. commentDescriptions?: boolean,
  29. /**
  30. * Set to true to assume the SDL is valid.
  31. *
  32. * Default: false
  33. */
  34. assumeValidSDL?: boolean,
  35. |};
  36. /**
  37. * This takes the ast of a schema document produced by the parse function in
  38. * src/language/parser.js.
  39. *
  40. * If no schema definition is provided, then it will look for types named Query
  41. * and Mutation.
  42. *
  43. * Given that AST it constructs a GraphQLSchema. The resulting schema
  44. * has no resolve methods, so execution will use default resolvers.
  45. *
  46. * Accepts options as a second argument:
  47. *
  48. * - commentDescriptions:
  49. * Provide true to use preceding comments as the description.
  50. *
  51. */
  52. export function buildASTSchema(
  53. documentAST: DocumentNode,
  54. options?: BuildSchemaOptions,
  55. ): GraphQLSchema {
  56. devAssert(
  57. documentAST != null && documentAST.kind === Kind.DOCUMENT,
  58. 'Must provide valid Document AST.',
  59. );
  60. if (options?.assumeValid !== true && options?.assumeValidSDL !== true) {
  61. assertValidSDL(documentAST);
  62. }
  63. const emptySchemaConfig = {
  64. description: undefined,
  65. types: [],
  66. directives: [],
  67. extensions: undefined,
  68. extensionASTNodes: [],
  69. assumeValid: false,
  70. };
  71. const config = extendSchemaImpl(emptySchemaConfig, documentAST, options);
  72. if (config.astNode == null) {
  73. for (const type of config.types) {
  74. switch (type.name) {
  75. // Note: While this could make early assertions to get the correctly
  76. // typed values below, that would throw immediately while type system
  77. // validation with validateSchema() will produce more actionable results.
  78. case 'Query':
  79. config.query = (type: any);
  80. break;
  81. case 'Mutation':
  82. config.mutation = (type: any);
  83. break;
  84. case 'Subscription':
  85. config.subscription = (type: any);
  86. break;
  87. }
  88. }
  89. }
  90. const { directives } = config;
  91. // If specified directives were not explicitly declared, add them.
  92. if (!directives.some((directive) => directive.name === 'skip')) {
  93. directives.push(GraphQLSkipDirective);
  94. }
  95. if (!directives.some((directive) => directive.name === 'include')) {
  96. directives.push(GraphQLIncludeDirective);
  97. }
  98. if (!directives.some((directive) => directive.name === 'deprecated')) {
  99. directives.push(GraphQLDeprecatedDirective);
  100. }
  101. if (!directives.some((directive) => directive.name === 'specifiedBy')) {
  102. directives.push(GraphQLSpecifiedByDirective);
  103. }
  104. return new GraphQLSchema(config);
  105. }
  106. /**
  107. * A helper function to build a GraphQLSchema directly from a source
  108. * document.
  109. */
  110. export function buildSchema(
  111. source: string | Source,
  112. options?: {| ...BuildSchemaOptions, ...ParseOptions |},
  113. ): GraphQLSchema {
  114. const document = parse(source, {
  115. noLocation: options?.noLocation,
  116. allowLegacySDLEmptyFields: options?.allowLegacySDLEmptyFields,
  117. allowLegacySDLImplementsInterfaces:
  118. options?.allowLegacySDLImplementsInterfaces,
  119. experimentalFragmentVariables: options?.experimentalFragmentVariables,
  120. });
  121. return buildASTSchema(document, {
  122. commentDescriptions: options?.commentDescriptions,
  123. assumeValidSDL: options?.assumeValidSDL,
  124. assumeValid: options?.assumeValid,
  125. });
  126. }