parse-graphql-sdl.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import { Kind, parse, Source as GraphQLSource, visit, isTypeSystemDefinitionNode, print, } from 'graphql';
  2. import { dedentBlockStringValue, getLeadingCommentBlock } from './comments.js';
  3. export function parseGraphQLSDL(location, rawSDL, options = {}) {
  4. let document;
  5. try {
  6. if (options.commentDescriptions && rawSDL.includes('#')) {
  7. document = transformCommentsToDescriptions(rawSDL, options);
  8. // If noLocation=true, we need to make sure to print and parse it again, to remove locations,
  9. // since `transformCommentsToDescriptions` must have locations set in order to transform the comments
  10. // into descriptions.
  11. if (options.noLocation) {
  12. document = parse(print(document), options);
  13. }
  14. }
  15. else {
  16. document = parse(new GraphQLSource(rawSDL, location), options);
  17. }
  18. }
  19. catch (e) {
  20. if (e.message.includes('EOF') && rawSDL.replace(/(\#[^*]*)/g, '').trim() === '') {
  21. document = {
  22. kind: Kind.DOCUMENT,
  23. definitions: [],
  24. };
  25. }
  26. else {
  27. throw e;
  28. }
  29. }
  30. return {
  31. location,
  32. document,
  33. };
  34. }
  35. export function transformCommentsToDescriptions(sourceSdl, options = {}) {
  36. const parsedDoc = parse(sourceSdl, {
  37. ...options,
  38. noLocation: false,
  39. });
  40. const modifiedDoc = visit(parsedDoc, {
  41. leave: (node) => {
  42. if (isDescribable(node)) {
  43. const rawValue = getLeadingCommentBlock(node);
  44. if (rawValue !== undefined) {
  45. const commentsBlock = dedentBlockStringValue('\n' + rawValue);
  46. const isBlock = commentsBlock.includes('\n');
  47. if (!node.description) {
  48. return {
  49. ...node,
  50. description: {
  51. kind: Kind.STRING,
  52. value: commentsBlock,
  53. block: isBlock,
  54. },
  55. };
  56. }
  57. else {
  58. return {
  59. ...node,
  60. description: {
  61. ...node.description,
  62. value: node.description.value + '\n' + commentsBlock,
  63. block: true,
  64. },
  65. };
  66. }
  67. }
  68. }
  69. },
  70. });
  71. return modifiedDoc;
  72. }
  73. export function isDescribable(node) {
  74. return (isTypeSystemDefinitionNode(node) ||
  75. node.kind === Kind.FIELD_DEFINITION ||
  76. node.kind === Kind.INPUT_VALUE_DEFINITION ||
  77. node.kind === Kind.ENUM_VALUE_DEFINITION);
  78. }