Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const invariant = require('invariant');
- const { Kind } = require('graphql');
- const byKindGetInfo = {
- // SchemaDefinition
- [Kind.SCHEMA_DEFINITION]: def => ({
- isExtension: false,
- type: 'schema',
- typeName: 'schema',
- }),
- // ScalarTypeDefinition
- [Kind.SCALAR_TYPE_DEFINITION]: def => ({
- isExtension: false,
- type: 'scalar',
- typeName: `scalar ${def.name.value}`,
- }),
- // ObjectTypeDefinition
- [Kind.OBJECT_TYPE_DEFINITION]: def => ({
- isExtension: false,
- type: 'type',
- typeName: `type ${def.name.value}`,
- }),
- // InterfaceTypeDefinition
- [Kind.INTERFACE_TYPE_DEFINITION]: def => ({
- isExtension: false,
- type: 'interface',
- typeName: `interface ${def.name.value}`,
- }),
- // UnionTypeDefinition
- [Kind.UNION_TYPE_DEFINITION]: def => ({
- isExtension: false,
- type: 'union',
- typeName: `union ${def.name.value}`,
- }),
- // EnumTypeDefinition
- [Kind.ENUM_TYPE_DEFINITION]: def => ({
- isExtension: false,
- type: 'enum',
- typeName: `enum ${def.name.value}`,
- }),
- // InputObjectTypeDefinition
- [Kind.INPUT_OBJECT_TYPE_DEFINITION]: def => ({
- isExtension: false,
- type: 'input',
- typeName: `input ${def.name.value}`,
- }),
- // DirectiveDefinition
- [Kind.DIRECTIVE_DEFINITION]: def => ({
- isExtension: false,
- type: 'directive',
- typeName: `directive ${def.name.value}`,
- }),
- // SchemaExtension
- [Kind.SCHEMA_EXTENSION]: def => ({
- isExtension: true,
- type: 'schema',
- typeName: 'schema',
- }),
- // ScalarTypeExtension
- [Kind.SCALAR_TYPE_EXTENSION]: def => ({
- isExtension: true,
- type: 'scalar',
- typeName: `scalar ${def.name.value}`,
- }),
- // ObjectTypeExtension
- [Kind.OBJECT_TYPE_EXTENSION]: def => ({
- isExtension: true,
- type: 'type',
- typeName: `type ${def.name.value}`,
- }),
- // InterfaceTypeExtension
- [Kind.INTERFACE_TYPE_EXTENSION]: def => ({
- isExtension: true,
- type: 'interface',
- typeName: `interface ${def.name.value}`,
- }),
- // UnionTypeExtension
- [Kind.UNION_TYPE_EXTENSION]: def => ({
- isExtension: true,
- type: 'union',
- typeName: `union ${def.name.value}`,
- }),
- // EnumTypeExtension
- [Kind.ENUM_TYPE_EXTENSION]: def => ({
- isExtension: true,
- type: 'enum',
- typeName: `enum ${def.name.value}`,
- }),
- // InputObjectTypeExtension
- [Kind.INPUT_OBJECT_TYPE_EXTENSION]: def => ({
- isExtension: true,
- type: 'input',
- typeName: `input ${def.name.value}`,
- }),
- };
- function extendDefinition(def, ext) {
- const defInfo = byKindGetInfo[def.kind](def);
- const extInfo = byKindGetInfo[ext.kind](ext);
- invariant(
- defInfo.type === extInfo.type,
- 'Types must be same: %s != %s',
- defInfo.type,
- extInfo.type,
- );
- invariant(!defInfo.isExtension, 'Extended type must be definition type');
- invariant(extInfo.isExtension, 'Extending type must be extension type');
- const extendLocation = (loc, loc2) => ({
- ...loc,
- ext: loc.ext ? [...loc.ext, loc2] : [loc2],
- });
- switch (defInfo.type) {
- case 'schema': {
- return {
- ...def,
- directives: [...def.directives, ...ext.directives],
- operationTypes: [...def.operationTypes, ...ext.operationTypes],
- loc: extendLocation(def.loc, ext.loc),
- };
- }
- case 'scalar': {
- return {
- ...def,
- directives: [...def.directives, ...ext.directives],
- loc: extendLocation(def.loc, ext.loc),
- };
- }
- case 'type': {
- return {
- ...def,
- interfaces: [...def.interfaces, ...ext.interfaces],
- directives: [...def.directives, ...ext.directives],
- fields: [...def.fields, ...ext.fields],
- loc: extendLocation(def.loc, ext.loc),
- };
- }
- case 'interface': {
- return {
- ...def,
- directives: [...def.directives, ...ext.directives],
- fields: [...def.fields, ...ext.fields],
- loc: extendLocation(def.loc, ext.loc),
- };
- }
- case 'union': {
- return {
- ...def,
- directives: [...def.directives, ...ext.directives],
- types: [...def.types, ...ext.types],
- loc: extendLocation(def.loc, ext.loc),
- };
- }
- case 'enum': {
- return {
- ...def,
- directives: [...def.directives, ...ext.directives],
- values: [...def.values, ...ext.values],
- loc: extendLocation(def.loc, ext.loc),
- };
- }
- case 'input': {
- return {
- ...def,
- directives: [...def.directives, ...ext.directives],
- fields: [...def.fields, ...ext.fields],
- loc: extendLocation(def.loc, ext.loc),
- };
- }
- default: {
- invariant(false, 'Unhandled type for merge: %s', defInfo.type);
- return def;
- }
- }
- }
- function mergeExtensionsIntoAST(inAst) {
- invariant(inAst.kind === 'Document', 'Document node required');
- const definitions = new Map();
- const extensions = new Map();
- // collect definitions and extensions
- inAst.definitions.forEach(def => {
- invariant(def, 'Definition expected');
- const getKey = byKindGetInfo[def.kind];
- invariant(getKey, 'Cannot retrieve key for %s', def.kind);
- const { isExtension, typeName } = getKey(def);
- if (isExtension) {
- if (extensions.has(typeName)) {
- extensions.get(typeName).push(def);
- } else {
- extensions.set(typeName, [def]);
- }
- } else {
- invariant(
- !definitions.has(typeName),
- 'Schema cannot contain multiple definitions: "%s"',
- typeName,
- );
- definitions.set(typeName, def);
- }
- });
- for (const [key, extDefs] of extensions) {
- const def = definitions.get(key);
- definitions.set(key, extDefs.reduce(extendDefinition, def));
- }
- return {
- ...inAst,
- definitions: [...definitions.values()],
- };
- }
- module.exports = {
- mergeExtensionsIntoAST,
- };
Add Comment
Please, Sign In to add comment