import { FeatureDefinition , FeatureDefinitions , FeatureUrl , FeatureVersion } from "./coreSpec" ; import { DirectiveDefinition , FieldDefinition , isCompositeType , isInterfaceType , isObjectType , Schema , } from "./definitions" ; import { GraphQLError , DirectiveLocation } from "graphql" ; export const inaccessibleIdentity = 'https://specs.apollo.dev/inaccessible' ; export class InaccessibleSpecDefinition extends FeatureDefinition { constructor ( version ) { super ( new FeatureUrl ( inaccessibleIdentity , 'inaccessible' , version ) ) ; } addElementsToSchema ( schema ) { this . addDirective ( schema , 'inaccessible' ) . addLocations ( DirectiveLocation . FIELD_DEFINITION , DirectiveLocation . OBJECT , DirectiveLocation . INTERFACE , DirectiveLocation . UNION ) ; } inaccessibleDirective ( schema ) { return this . directive ( schema , 'inaccessible' ) ! ; } } export const INACCESSIBLE_VERSIONS = new FeatureDefinitions < InaccessibleSpecDefinition > ( inaccessibleIdentity ) . add ( new InaccessibleSpecDefinition ( new FeatureVersion ( 0 , 1 ) ) ) ; export function removeInaccessibleElements ( schema ) { const coreFeatures = schema . coreFeatures ; if ( ! coreFeatures ) { return ; } const inaccessibleFeature = coreFeatures . getByIdentity ( inaccessibleIdentity ) ; if ( ! inaccessibleFeature ) { return ; } const inaccessibleSpec = INACCESSIBLE_VERSIONS . find ( inaccessibleFeature . url . version ) ; if ( ! inaccessibleSpec ) { throw new GraphQLError ( `Cannot remove inaccessible elements: the schema uses unsupported inaccessible spec version ${ inaccessibleFeature . url . version } (supported versions: ${ INACCESSIBLE_VERSIONS . versions ( ) . join ( ', ' ) })` ) ; } const inaccessibleDirective = inaccessibleSpec . inaccessibleDirective ( schema ) ; if ( ! inaccessibleDirective ) { throw new GraphQLError ( `Invalid schema: declares ${ inaccessibleSpec . url } spec but does not define a @inaccessible directive` ) ; } for ( const type of schema . types ( ) ) { if ( ! isCompositeType ( type ) ) { continue ; } if ( type . hasAppliedDirective ( inaccessibleDirective ) ) { const references = type . remove ( ) ; for ( const reference of references ) { if ( reference . kind === 'FieldDefinition' ) { if ( ! reference . hasAppliedDirective ( inaccessibleDirective ) ) { throw new GraphQLError ( `Field ${ reference . coordinate } returns an @inaccessible type without being marked @inaccessible itself.` , reference . sourceAST ) ; } } } } else if ( isObjectType ( type ) || isInterfaceType ( type ) ) { const toRemove = ( type . fields ( ) as FieldDefinition < any > [ ] ) . filter ( f => f . hasAppliedDirective ( inaccessibleDirective ) ) ; toRemove . forEach ( f => f . remove ( ) ) ; } } }