Guest User

Untitled

a guest
Sep 20th, 2018
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.67 KB | None | 0 0
  1. const invariant = require('invariant');
  2. const { Kind } = require('graphql');
  3.  
  4. const byKindGetInfo = {
  5. // SchemaDefinition
  6. [Kind.SCHEMA_DEFINITION]: def => ({
  7. isExtension: false,
  8. type: 'schema',
  9. typeName: 'schema',
  10. }),
  11. // ScalarTypeDefinition
  12. [Kind.SCALAR_TYPE_DEFINITION]: def => ({
  13. isExtension: false,
  14. type: 'scalar',
  15. typeName: `scalar ${def.name.value}`,
  16. }),
  17. // ObjectTypeDefinition
  18. [Kind.OBJECT_TYPE_DEFINITION]: def => ({
  19. isExtension: false,
  20. type: 'type',
  21. typeName: `type ${def.name.value}`,
  22. }),
  23. // InterfaceTypeDefinition
  24. [Kind.INTERFACE_TYPE_DEFINITION]: def => ({
  25. isExtension: false,
  26. type: 'interface',
  27. typeName: `interface ${def.name.value}`,
  28. }),
  29. // UnionTypeDefinition
  30. [Kind.UNION_TYPE_DEFINITION]: def => ({
  31. isExtension: false,
  32. type: 'union',
  33. typeName: `union ${def.name.value}`,
  34. }),
  35. // EnumTypeDefinition
  36. [Kind.ENUM_TYPE_DEFINITION]: def => ({
  37. isExtension: false,
  38. type: 'enum',
  39. typeName: `enum ${def.name.value}`,
  40. }),
  41. // InputObjectTypeDefinition
  42. [Kind.INPUT_OBJECT_TYPE_DEFINITION]: def => ({
  43. isExtension: false,
  44. type: 'input',
  45. typeName: `input ${def.name.value}`,
  46. }),
  47. // DirectiveDefinition
  48. [Kind.DIRECTIVE_DEFINITION]: def => ({
  49. isExtension: false,
  50. type: 'directive',
  51. typeName: `directive ${def.name.value}`,
  52. }),
  53.  
  54. // SchemaExtension
  55. [Kind.SCHEMA_EXTENSION]: def => ({
  56. isExtension: true,
  57. type: 'schema',
  58. typeName: 'schema',
  59. }),
  60. // ScalarTypeExtension
  61. [Kind.SCALAR_TYPE_EXTENSION]: def => ({
  62. isExtension: true,
  63. type: 'scalar',
  64. typeName: `scalar ${def.name.value}`,
  65. }),
  66. // ObjectTypeExtension
  67. [Kind.OBJECT_TYPE_EXTENSION]: def => ({
  68. isExtension: true,
  69. type: 'type',
  70. typeName: `type ${def.name.value}`,
  71. }),
  72. // InterfaceTypeExtension
  73. [Kind.INTERFACE_TYPE_EXTENSION]: def => ({
  74. isExtension: true,
  75. type: 'interface',
  76. typeName: `interface ${def.name.value}`,
  77. }),
  78. // UnionTypeExtension
  79. [Kind.UNION_TYPE_EXTENSION]: def => ({
  80. isExtension: true,
  81. type: 'union',
  82. typeName: `union ${def.name.value}`,
  83. }),
  84. // EnumTypeExtension
  85. [Kind.ENUM_TYPE_EXTENSION]: def => ({
  86. isExtension: true,
  87. type: 'enum',
  88. typeName: `enum ${def.name.value}`,
  89. }),
  90. // InputObjectTypeExtension
  91. [Kind.INPUT_OBJECT_TYPE_EXTENSION]: def => ({
  92. isExtension: true,
  93. type: 'input',
  94. typeName: `input ${def.name.value}`,
  95. }),
  96. };
  97.  
  98. function extendDefinition(def, ext) {
  99. const defInfo = byKindGetInfo[def.kind](def);
  100. const extInfo = byKindGetInfo[ext.kind](ext);
  101. invariant(
  102. defInfo.type === extInfo.type,
  103. 'Types must be same: %s != %s',
  104. defInfo.type,
  105. extInfo.type,
  106. );
  107. invariant(!defInfo.isExtension, 'Extended type must be definition type');
  108. invariant(extInfo.isExtension, 'Extending type must be extension type');
  109.  
  110. const extendLocation = (loc, loc2) => ({
  111. ...loc,
  112. ext: loc.ext ? [...loc.ext, loc2] : [loc2],
  113. });
  114.  
  115. switch (defInfo.type) {
  116. case 'schema': {
  117. return {
  118. ...def,
  119. directives: [...def.directives, ...ext.directives],
  120. operationTypes: [...def.operationTypes, ...ext.operationTypes],
  121. loc: extendLocation(def.loc, ext.loc),
  122. };
  123. }
  124. case 'scalar': {
  125. return {
  126. ...def,
  127. directives: [...def.directives, ...ext.directives],
  128. loc: extendLocation(def.loc, ext.loc),
  129. };
  130. }
  131. case 'type': {
  132. return {
  133. ...def,
  134. interfaces: [...def.interfaces, ...ext.interfaces],
  135. directives: [...def.directives, ...ext.directives],
  136. fields: [...def.fields, ...ext.fields],
  137. loc: extendLocation(def.loc, ext.loc),
  138. };
  139. }
  140. case 'interface': {
  141. return {
  142. ...def,
  143. directives: [...def.directives, ...ext.directives],
  144. fields: [...def.fields, ...ext.fields],
  145. loc: extendLocation(def.loc, ext.loc),
  146. };
  147. }
  148. case 'union': {
  149. return {
  150. ...def,
  151. directives: [...def.directives, ...ext.directives],
  152. types: [...def.types, ...ext.types],
  153. loc: extendLocation(def.loc, ext.loc),
  154. };
  155. }
  156. case 'enum': {
  157. return {
  158. ...def,
  159. directives: [...def.directives, ...ext.directives],
  160. values: [...def.values, ...ext.values],
  161. loc: extendLocation(def.loc, ext.loc),
  162. };
  163. }
  164. case 'input': {
  165. return {
  166. ...def,
  167. directives: [...def.directives, ...ext.directives],
  168. fields: [...def.fields, ...ext.fields],
  169. loc: extendLocation(def.loc, ext.loc),
  170. };
  171. }
  172. default: {
  173. invariant(false, 'Unhandled type for merge: %s', defInfo.type);
  174. return def;
  175. }
  176. }
  177. }
  178.  
  179. function mergeExtensionsIntoAST(inAst) {
  180. invariant(inAst.kind === 'Document', 'Document node required');
  181. const definitions = new Map();
  182. const extensions = new Map();
  183.  
  184. // collect definitions and extensions
  185. inAst.definitions.forEach(def => {
  186. invariant(def, 'Definition expected');
  187.  
  188. const getKey = byKindGetInfo[def.kind];
  189. invariant(getKey, 'Cannot retrieve key for %s', def.kind);
  190. const { isExtension, typeName } = getKey(def);
  191. if (isExtension) {
  192. if (extensions.has(typeName)) {
  193. extensions.get(typeName).push(def);
  194. } else {
  195. extensions.set(typeName, [def]);
  196. }
  197. } else {
  198. invariant(
  199. !definitions.has(typeName),
  200. 'Schema cannot contain multiple definitions: "%s"',
  201. typeName,
  202. );
  203. definitions.set(typeName, def);
  204. }
  205. });
  206.  
  207. for (const [key, extDefs] of extensions) {
  208. const def = definitions.get(key);
  209. definitions.set(key, extDefs.reduce(extendDefinition, def));
  210. }
  211.  
  212. return {
  213. ...inAst,
  214. definitions: [...definitions.values()],
  215. };
  216. }
  217.  
  218. module.exports = {
  219. mergeExtensionsIntoAST,
  220. };
Add Comment
Please, Sign In to add comment