UNPKG

@graphql-tools/utils

Version:

Common package containing utils and types for GraphQL tools

110 lines (109 loc) • 4.31 kB
import { versionInfo } from 'graphql'; import { asArray } from './helpers.js'; import { MapperKind } from './Interfaces.js'; import { mapSchema } from './mapSchema.js'; function handleDirectiveExtensions(extensions, removeDirectives) { extensions = extensions || {}; const { directives: existingDirectives, ...rest } = extensions; const finalExtensions = { ...rest, }; // GraphQL.js v17+ may put symbol keys on extensions (toObjMapWithSymbols). Object // rest/spread already copies enumerable own symbols; this loop also picks up // non-enumerable ones (assignment makes them enumerable on the result). Gated to // v17+ to avoid surprising behavior on older runtimes. if (versionInfo?.major >= 17) { for (const sym of Object.getOwnPropertySymbols(extensions)) { finalExtensions[sym] = extensions[sym]; } } if (!removeDirectives) { if (existingDirectives != null) { const directives = {}; for (const directiveName in existingDirectives) { directives[directiveName] = [...asArray(existingDirectives[directiveName])]; } finalExtensions.directives = directives; } } return finalExtensions; } export function extractExtensionsFromSchema(schema, removeDirectives = false) { const result = { schemaExtensions: handleDirectiveExtensions(schema.extensions, removeDirectives), types: {}, }; mapSchema(schema, { [MapperKind.OBJECT_TYPE]: type => { result.types[type.name] = { fields: {}, type: 'object', extensions: handleDirectiveExtensions(type.extensions, removeDirectives), }; return type; }, [MapperKind.INTERFACE_TYPE]: type => { result.types[type.name] = { fields: {}, type: 'interface', extensions: handleDirectiveExtensions(type.extensions, removeDirectives), }; return type; }, [MapperKind.FIELD]: (field, fieldName, typeName) => { result.types[typeName].fields[fieldName] = { arguments: {}, extensions: handleDirectiveExtensions(field.extensions, removeDirectives), }; const args = field.args; if (args != null) { for (const argName in args) { result.types[typeName].fields[fieldName].arguments[argName] = handleDirectiveExtensions(args[argName].extensions, removeDirectives); } } return field; }, [MapperKind.ENUM_TYPE]: type => { result.types[type.name] = { values: {}, type: 'enum', extensions: handleDirectiveExtensions(type.extensions, removeDirectives), }; return type; }, [MapperKind.ENUM_VALUE]: (value, typeName, _schema, valueName) => { result.types[typeName].values[valueName] = handleDirectiveExtensions(value.extensions, removeDirectives); return value; }, [MapperKind.SCALAR_TYPE]: type => { result.types[type.name] = { type: 'scalar', extensions: handleDirectiveExtensions(type.extensions, removeDirectives), }; return type; }, [MapperKind.UNION_TYPE]: type => { result.types[type.name] = { type: 'union', extensions: handleDirectiveExtensions(type.extensions, removeDirectives), }; return type; }, [MapperKind.INPUT_OBJECT_TYPE]: type => { result.types[type.name] = { fields: {}, type: 'input', extensions: handleDirectiveExtensions(type.extensions, removeDirectives), }; return type; }, [MapperKind.INPUT_OBJECT_FIELD]: (field, fieldName, typeName) => { result.types[typeName].fields[fieldName] = { extensions: handleDirectiveExtensions(field.extensions, removeDirectives), }; return field; }, }); return result; }