function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /* eslint-disable no-use-before-define */ import keyMap from 'graphql/jsutils/keyMap'; import { GraphQLEnumType, GraphQLList, GraphQLNonNull } from './graphql'; import { isObject, isString } from './utils/is'; import { inspect } from './utils/misc'; import { defineEnumValues, defineEnumValuesToConfig } from './utils/configToDefine'; import { graphqlVersion } from './utils/graphqlVersion'; import { SchemaComposer } from './SchemaComposer'; export class EnumTypeComposer { static create(typeDef, schemaComposer) { if (!(schemaComposer instanceof SchemaComposer)) { throw new Error('You must provide SchemaComposer instance as a second argument for `EnumTypeComposer.create(typeDef, schemaComposer)`'); } const etc = this.createTemp(typeDef, schemaComposer); if (schemaComposer) schemaComposer.add(etc); return etc; } static createTemp(typeDef, schemaComposer) { const sc = schemaComposer || new SchemaComposer(); let ETC; if (isString(typeDef)) { const typeName = typeDef; const NAME_RX = /^[_a-zA-Z][_a-zA-Z0-9]*$/; if (NAME_RX.test(typeName)) { ETC = new EnumTypeComposer(new GraphQLEnumType({ name: typeName, values: graphqlVersion < 13 ? { _OldGraphqlStubValue_: {} } : {} }), sc); } else { ETC = sc.typeMapper.createType(typeName); if (!(ETC instanceof EnumTypeComposer)) { throw new Error('You should provide correct GraphQLEnumType type definition.' + 'Eg. `enum MyType { KEY1 KEY2 KEY3 }`'); } } } else if (typeDef instanceof GraphQLEnumType) { ETC = new EnumTypeComposer(typeDef, sc); } else if (isObject(typeDef)) { const type = new GraphQLEnumType(_objectSpread({}, typeDef)); ETC = new EnumTypeComposer(type, sc); ETC.setFields(typeDef.values || {}); ETC.gqType._gqcExtensions = typeDef.extensions || {}; } else { throw new Error(`You should provide GraphQLEnumTypeConfig or string with enum name or SDL. Provided:\n${inspect(typeDef)}`); } return ETC; } constructor(gqType, schemaComposer) { if (!(schemaComposer instanceof SchemaComposer)) { throw new Error('You must provide SchemaComposer instance as a second argument for `new EnumTypeComposer(GraphQLEnumType, SchemaComposer)`'); } this.schemaComposer = schemaComposer; if (!(gqType instanceof GraphQLEnumType)) { throw new Error('EnumTypeComposer accept only GraphQLEnumType in constructor'); } this.gqType = gqType; // alive proper Flow type casting in autosuggestions for class with Generics /* :: return this; */ } // ----------------------------------------------- // Value methods // ----------------------------------------------- hasField(name) { const values = this.getFields(); return !!values[name]; } _fixEnumBelowV13() { if (graphqlVersion < 13) { if (!this.gqType._values) { // $FlowFixMe Support for graphql@0.11 and below this.gqType._values = defineEnumValues(this.gqType, this.gqType._enumConfig.values); } this.gqType._values = this.gqType._values.filter(o => o.name !== '_OldGraphqlStubValue_'); } } getFields() { if (!this.gqType._gqcFields) { if (graphqlVersion >= 14) { this.gqType._gqcFields = defineEnumValuesToConfig(this.gqType._values); } else { this._fixEnumBelowV13(); this.gqType._gqcFields = this.gqType._getNameLookup(); } } return this.gqType._gqcFields; } getField(name) { const values = this.getFields(); if (!values[name]) { throw new Error(`Cannot get value '${name}' from enum type '${this.getTypeName()}'. Value with such name does not exist.`); } return values[name]; } getFieldNames() { return Object.keys(this.getFields()); } /** * Completely replace all values in GraphQL enum type * WARNING: this method rewrite an internal GraphQL instance properties. */ setFields(values) { const preparedValues = {}; Object.keys(values).forEach(valueName => { const value = values[valueName]; preparedValues[valueName] = { value: value.hasOwnProperty('value') ? value.value : valueName, description: value.description, deprecationReason: value.deprecationReason, extensions: value.extensions || {}, astNode: value.astNode }; }); this.gqType._gqcFields = preparedValues; if (graphqlVersion >= 14) { this.gqType._values = defineEnumValues(this.gqType, values); this.gqType._valueLookup = new Map(this.gqType._values.map(enumValue => [enumValue.value, enumValue])); this.gqType._nameLookup = keyMap(this.gqType._values, value => value.name); } else { // cleanup isDepricated Object.keys(values).forEach(key => { // $FlowFixMe delete values[key].isDeprecated; // eslint-disable-line }); // $FlowFixMe this.gqType._enumConfig.values = values; // clear builded fields in type delete this.gqType._values; delete this.gqType._valueLookup; delete this.gqType._nameLookup; this._fixEnumBelowV13(); } return this; } setField(name, valueConfig) { this.addFields({ [name]: _objectSpread({ value: name }, valueConfig) }); return this; } /** * Add new fields or replace existed in a GraphQL type */ addFields(newValues) { this.setFields(_objectSpread({}, this.getFields(), newValues)); return this; } removeField(nameOrArray) { const valueNames = Array.isArray(nameOrArray) ? nameOrArray : [nameOrArray]; const values = this.getFields(); valueNames.forEach(valueName => delete values[valueName]); this.setFields(_objectSpread({}, values)); return this; } removeOtherFields(fieldNameOrArray) { const keepFieldNames = Array.isArray(fieldNameOrArray) ? fieldNameOrArray : [fieldNameOrArray]; const fields = this.getFields(); Object.keys(fields).forEach(fieldName => { if (keepFieldNames.indexOf(fieldName) === -1) { delete fields[fieldName]; } }); this.setFields(fields); return this; } reorderFields(names) { const orderedFields = {}; const fields = this.getFields(); names.forEach(name => { if (fields[name]) { orderedFields[name] = fields[name]; delete fields[name]; } }); this.setFields(_objectSpread({}, orderedFields, fields)); return this; } extendField(name, partialValueConfig) { let prevValueConfig; try { prevValueConfig = this.getField(name); } catch (e) { throw new Error(`Cannot extend value '${name}' from enum '${this.getTypeName()}'. Value does not exist.`); } const valueConfig = _objectSpread({}, prevValueConfig, partialValueConfig); this.setField(name, valueConfig); return this; } deprecateFields(fields) { const existedFieldNames = this.getFieldNames(); if (typeof fields === 'string') { if (existedFieldNames.indexOf(fields) === -1) { throw new Error(`Cannot deprecate unexisted value '${fields}' from enum '${this.getTypeName()}'`); } this.extendField(fields, { deprecationReason: 'deprecated' }); } else if (Array.isArray(fields)) { fields.forEach(field => { if (existedFieldNames.indexOf(field) === -1) { throw new Error(`Cannot deprecate unexisted value '${field}' from enum '${this.getTypeName()}'`); } this.extendField(field, { deprecationReason: 'deprecated' }); }); } else { const fieldMap = fields; Object.keys(fieldMap).forEach(field => { if (existedFieldNames.indexOf(field) === -1) { throw new Error(`Cannot deprecate unexisted value '${field}' from enum '${this.getTypeName()}'`); } const deprecationReason = fieldMap[field]; this.extendField(field, { deprecationReason }); }); } return this; } // ----------------------------------------------- // Type methods // ----------------------------------------------- getType() { return this.gqType; } getTypePlural() { return new GraphQLList(this.gqType); } getTypeNonNull() { return new GraphQLNonNull(this.gqType); } getTypeName() { return this.gqType.name; } setTypeName(name) { this.gqType.name = name; this.schemaComposer.add(this); return this; } getDescription() { return this.gqType.description || ''; } setDescription(description) { this.gqType.description = description; return this; } clone(newTypeName) { if (!newTypeName) { throw new Error('You should provide newTypeName:string for EnumTypeComposer.clone()'); } const values = this.getFields(); const newValues = {}; Object.keys(values).forEach(fieldName => { newValues[fieldName] = _objectSpread({}, values[fieldName]); delete newValues[fieldName].isDeprecated; }); const cloned = new EnumTypeComposer(new GraphQLEnumType({ name: newTypeName, values: newValues }), this.schemaComposer); cloned.setDescription(this.getDescription()); return cloned; } merge(type) { if (type instanceof GraphQLEnumType) { const fields = defineEnumValuesToConfig(type._values); this.addFields(fields); } else if (type instanceof EnumTypeComposer) { this.addFields(type.getFields()); } else { throw new Error(`Cannot merge ${inspect(type)} with EnumType(${this.getTypeName()}). Provided type should be GraphQLEnumType or EnumTypeComposer.`); } return this; } // ----------------------------------------------- // Extensions methods // ----------------------------------------------- getExtensions() { if (!this.gqType._gqcExtensions) { return {}; } else { return this.gqType._gqcExtensions; } } setExtensions(extensions) { this.gqType._gqcExtensions = extensions; return this; } extendExtensions(extensions) { const current = this.getExtensions(); this.setExtensions(_objectSpread({}, current, extensions)); return this; } clearExtensions() { this.setExtensions({}); return this; } getExtension(extensionName) { const extensions = this.getExtensions(); return extensions[extensionName]; } hasExtension(extensionName) { const extensions = this.getExtensions(); return extensionName in extensions; } setExtension(extensionName, value) { this.extendExtensions({ [extensionName]: value }); return this; } removeExtension(extensionName) { const extensions = _objectSpread({}, this.getExtensions()); delete extensions[extensionName]; this.setExtensions(extensions); return this; } getFieldExtensions(fieldName) { const field = this.getField(fieldName); return field.extensions || {}; } setFieldExtensions(fieldName, extensions) { const field = this.getField(fieldName); this.setField(fieldName, _objectSpread({}, field, { extensions })); return this; } extendFieldExtensions(fieldName, extensions) { const current = this.getFieldExtensions(fieldName); this.setFieldExtensions(fieldName, _objectSpread({}, current, extensions)); return this; } clearFieldExtensions(fieldName) { this.setFieldExtensions(fieldName, {}); return this; } getFieldExtension(fieldName, extensionName) { const extensions = this.getFieldExtensions(fieldName); return extensions[extensionName]; } hasFieldExtension(fieldName, extensionName) { const extensions = this.getFieldExtensions(fieldName); return extensionName in extensions; } setFieldExtension(fieldName, extensionName, value) { this.extendFieldExtensions(fieldName, { [extensionName]: value }); return this; } removeFieldExtension(fieldName, extensionName) { const extensions = _objectSpread({}, this.getFieldExtensions(fieldName)); delete extensions[extensionName]; this.setFieldExtensions(fieldName, extensions); return this; } // ----------------------------------------------- // Directive methods // ----------------------------------------------- getDirectives() { const directives = this.getExtension('directives'); if (Array.isArray(directives)) { return directives; } return []; } getDirectiveNames() { return this.getDirectives().map(d => d.name); } getDirectiveByName(directiveName) { const directive = this.getDirectives().find(d => d.name === directiveName); if (!directive) return undefined; return directive.args; } getDirectiveById(idx) { const directive = this.getDirectives()[idx]; if (!directive) return undefined; return directive.args; } getFieldDirectives(fieldName) { const directives = this.getFieldExtension(fieldName, 'directives'); if (Array.isArray(directives)) { return directives; } return []; } getFieldDirectiveNames(fieldName) { return this.getFieldDirectives(fieldName).map(d => d.name); } getFieldDirectiveByName(fieldName, directiveName) { const directive = this.getFieldDirectives(fieldName).find(d => d.name === directiveName); if (!directive) return undefined; return directive.args; } getFieldDirectiveById(fieldName, idx) { const directive = this.getFieldDirectives(fieldName)[idx]; if (!directive) return undefined; return directive.args; } }