UNPKG

@graphql-mesh/fusion-composition

Version:

Basic composition utility for Fusion spec

203 lines (202 loc) • 8.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addInaccessibleDirective = addInaccessibleDirective; exports.createFilterTransform = createFilterTransform; const graphql_1 = require("graphql"); const minimatch_1 = require("minimatch"); const utils_1 = require("@graphql-tools/utils"); function addInaccessibleDirective(directableObj) { const directives = (0, utils_1.getDirectiveExtensions)(directableObj); directives.inaccessible = [{}]; const extensions = (directableObj.extensions ||= {}); extensions.directives = directives; directableObj.astNode = undefined; } function compareAndAddInaccessibleDirective(originalSchema, filteredSchema) { return (0, utils_1.mapSchema)(originalSchema, { [utils_1.MapperKind.TYPE]: type => { const typeInFiltered = filteredSchema.getType(type.name); if (!typeInFiltered) { addInaccessibleDirective(type); } else if ('getFields' in type) { if (!('getFields' in typeInFiltered)) { addInaccessibleDirective(type); } else { const numOfFieldsInFiltered = Object.keys(typeInFiltered.getFields()).length; if (numOfFieldsInFiltered === 0) { addInaccessibleDirective(type); } } } return type; }, [utils_1.MapperKind.FIELD]: (fieldConfig, fieldName, typeName) => { const typeInFiltered = filteredSchema.getType(typeName); if (!typeInFiltered || !('getFields' in typeInFiltered)) { addInaccessibleDirective(fieldConfig); } else { const filteredFields = typeInFiltered.getFields(); const fieldInFiltered = filteredFields[fieldName]; if (!fieldInFiltered) { addInaccessibleDirective(fieldConfig); } else { if ('args' in fieldConfig && !('args' in fieldInFiltered)) { for (const argName in fieldConfig.args) { const argConfig = fieldConfig.args[argName]; addInaccessibleDirective(argConfig); } } else if ('args' in fieldConfig && 'args' in fieldInFiltered) { const filteredArgs = fieldInFiltered.args; for (const argName in fieldConfig.args) { if (!filteredArgs.some(arg => arg.name === argName)) { const argConfig = fieldConfig.args[argName]; addInaccessibleDirective(argConfig); if ((0, graphql_1.isNonNullType)(argConfig.type)) { argConfig.type = argConfig.type.ofType; } } } } } } return fieldConfig; }, }); } function createFilterTransform({ // Declarative Filters filters, filterDeprecatedTypes, filterDeprecatedFields, // Programmatic Filters ...programmaticFilters }) { const typeFilters = programmaticFilters.typeFilter ? [programmaticFilters.typeFilter] : []; const fieldFilters = programmaticFilters.fieldFilter ? [programmaticFilters.fieldFilter] : []; const argumentFilters = programmaticFilters.argumentFilter ? [programmaticFilters.argumentFilter] : []; if (filters?.length) { for (const filter of filters) { const [typeName, fieldNameOrGlob, argsGlob] = filter.split('.'); const typeMatcher = new minimatch_1.Minimatch(typeName); // TODO: deprecate this in next major release as dscussed in #1605 if (!fieldNameOrGlob) { typeFilters.push(type => typeMatcher.match(type.name)); continue; } let fixedFieldGlob = argsGlob || fieldNameOrGlob; if (fixedFieldGlob.includes('{') && !fixedFieldGlob.includes(',')) { fixedFieldGlob = fieldNameOrGlob.replace('{', '').replace('}', ''); } fixedFieldGlob = fixedFieldGlob.split(', ').join(','); const globalTypeMatcher = new minimatch_1.Minimatch(fixedFieldGlob.trim()); if (typeName === 'Type') { typeFilters.push(type => globalTypeMatcher.match(type.name)); continue; } if (argsGlob) { const fieldMatcher = new minimatch_1.Minimatch(fieldNameOrGlob); argumentFilters.push((typeName, fieldName, argName) => { if (typeMatcher.match(typeName) && fieldMatcher.match(fieldName)) { return globalTypeMatcher.match(argName); } }); continue; } // If the glob is not for Types nor Args, finally we register Fields filters fieldFilters.push((typeName, fieldName) => { if (typeMatcher.match(typeName)) { return globalTypeMatcher.match(fieldName); } return true; }); } } if (filterDeprecatedFields) { fieldFilters.push((_, __, fieldConfig) => !fieldConfig.deprecationReason); } if (filterDeprecatedTypes) { typeFilters.push(type => !(0, utils_1.getDirectiveExtensions)(type)?.deprecated?.length); } const schemaMapper = {}; if (programmaticFilters.rootFieldFilter) { schemaMapper[utils_1.MapperKind.ROOT_FIELD] = (fieldConfig, fieldName, typeName, schema) => { const filterResult = programmaticFilters.rootFieldFilter(typeName, fieldName); if (filterResult != null && !filterResult) { return null; } }; } if (typeFilters.length) { schemaMapper[utils_1.MapperKind.TYPE] = type => { for (const filter of typeFilters) { const filterResult = filter(type); if (filterResult != null && !filterResult) { return null; } } return type; }; } if (argumentFilters.length || fieldFilters.length) { schemaMapper[utils_1.MapperKind.FIELD] = (fieldConfig, fieldName, typeName, schema) => { for (const filter of fieldFilters) { const filterResult = filter(typeName, fieldName, fieldConfig); if (filterResult != null && !filterResult) { return null; } } if (argumentFilters.length && 'args' in fieldConfig && fieldConfig.args) { const newArgs = {}; for (const argName in fieldConfig.args) { const argConfig = fieldConfig.args[argName]; let filtered = false; for (const argFilter of argumentFilters) { const argFilterResult = argFilter(typeName, fieldName, argName); if (argFilterResult != null && !argFilterResult) { filtered = true; break; } } if (!filtered) { newArgs[argName] = argConfig; } } fieldConfig.args = newArgs; } return fieldConfig; }; } if (programmaticFilters.objectFieldFilter) { schemaMapper[utils_1.MapperKind.OBJECT_FIELD] = (fieldConfig, fieldName, typeName, schema) => { const filterResult = programmaticFilters.objectFieldFilter(typeName, fieldName); if (filterResult != null && !filterResult) { return null; } }; } if (programmaticFilters.interfaceFieldFilter) { schemaMapper[utils_1.MapperKind.INTERFACE_FIELD] = (fieldConfig, fieldName, typeName, schema) => { const filterResult = programmaticFilters.interfaceFieldFilter(typeName, fieldName); if (filterResult != null && !filterResult) { return null; } }; } if (programmaticFilters.inputObjectFieldFilter) { schemaMapper[utils_1.MapperKind.INPUT_OBJECT_FIELD] = (fieldConfig, fieldName, typeName, schema) => { const filterResult = programmaticFilters.inputObjectFieldFilter(typeName, fieldName); if (filterResult != null && !filterResult) { return null; } }; } return function filterTransform(schema) { return compareAndAddInaccessibleDirective(schema, (0, utils_1.mapSchema)(schema, schemaMapper)); }; }