/**
 * Copyright (c) 2016-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */ import * as Code from './code' ; import * as Either from './either' ; import * as Error from './error' ; import * as FileWriter from './file-writer' ; import * as List from './list' ; import * as Maybe from './maybe' ; import * as ObjC from './objc' ; import * as PluggableObjCFileCreation from './pluggable-objc-file-creation' ; import * as ObjectSpec from './object-spec' ; export interface Request extends PluggableObjCFileCreation . ObjCGenerationRequest < ObjectSpec . Type > { } interface ObjectSpecObjCPlugIn extends PluggableObjCFileCreation . ObjCGenerationPlugIn < ObjectSpec . Type > { } function createObjectSpecObjCPlugIn ( plugin ) { return { additionalFiles : function ( typeInformation ) : Code . File [ ] { return plugin . additionalFiles ( typeInformation ) ; } , transformBaseFile : function ( typeInformation , baseFile ) : Code . File { return plugin . transformBaseFile ( typeInformation , baseFile ) ; } , baseClass : plugin . baseClass != null ? plugin . baseClass : ( _ ) => null , blockTypes : plugin . blockTypes != null ? plugin . blockTypes : ( _ ) => [ ] , classMethods : function ( typeInformation ) : ObjC . Method [ ] { return plugin . classMethods ( typeInformation ) ; } , comments : function ( typeInformation ) : ObjC . Comment [ ] { return plugin . headerComments ( typeInformation ) ; } , enumerations : function ( typeInformation ) : ObjC . Enumeration [ ] { return [ ] ; } , transformFileRequest : function ( writeRequest ) : FileWriter . Request { return plugin . transformFileRequest ( writeRequest ) ; } , fileType : function ( typeInformation ) : Code . FileType | null { return plugin . fileType ( typeInformation ) ; } , forwardDeclarations : function ( typeInformation ) : ObjC . ForwardDeclaration [ ] { return plugin . forwardDeclarations ( typeInformation ) ; } , functions : function ( typeInformation ) : ObjC . Function [ ] { return plugin . functions ( typeInformation ) ; } , implementedProtocols : function ( typeInformation ) : ObjC . ImplementedProtocol [ ] { return plugin . implementedProtocols ( typeInformation ) ; } , imports : function ( typeInformation ) : ObjC . Import [ ] { return plugin . imports ( typeInformation ) ; } , instanceVariables : function ( typeInformation ) : ObjC . InstanceVariable [ ] { return plugin . instanceVariables != null ? plugin . instanceVariables ( typeInformation ) : [ ] ; } , instanceMethods : function ( typeInformation ) : ObjC . Method [ ] { return plugin . instanceMethods ( typeInformation ) ; } , macros : plugin . macros , properties : function ( typeInformation ) : ObjC . Property [ ] { return plugin . properties ( typeInformation ) ; } , protocols : function ( typeInformation ) : ObjC . Protocol [ ] { return plugin . protocols != null ? plugin . protocols ( typeInformation ) : [ ] ; } , staticConstants : function ( typeInformation ) : ObjC . Constant [ ] { return plugin . staticConstants ( typeInformation ) ; } , globalVariables : function ( typeInformation ) : ObjC . GlobalVariable [ ] { return plugin . globalVariables ? plugin . globalVariables ( typeInformation ) : [ ] ; } , validationErrors : function ( typeInformation ) : Error . Error [ ] { return plugin . validationErrors ( typeInformation ) ; } , nullability : function ( typeInformation ) : ObjC . ClassNullability | null { return plugin . nullability ( typeInformation ) ; } , subclassingRestricted : function ( typeInformation ) : boolean { return plugin . subclassingRestricted ( typeInformation ) ; } , structs : function ( typeInformation ) : Code . Struct [ ] { return plugin . structs != null ? plugin . structs ( typeInformation ) : [ ] ; } , requiredIncludesToRun : plugin . requiredIncludesToRun } ; } function buildExtraAttributes ( typeInformation , soFar , plugin ) { return soFar . concat ( plugin . attributes ( typeInformation ) ) ; } function buildExtraTypes ( typeInformation , soFar , plugin ) { return soFar . concat ( plugin . additionalTypes ( typeInformation ) ) ; } function typeInformationWithAllAttributesFromPlugins ( typeInformation , plugins ) { const pluginAttributes = List . foldl < ObjectSpec . Plugin , ObjectSpec . Attribute [ ] > ( ( soFar , plugin ) => buildExtraAttributes ( typeInformation , soFar , plugin ) , [ ] , plugins ) ; return { annotations : typeInformation . annotations , attributes : typeInformation . attributes . concat ( pluginAttributes ) , comments : typeInformation . comments , excludes : typeInformation . excludes , includes : typeInformation . includes , libraryName : typeInformation . libraryName , typeLookups : typeInformation . typeLookups , typeName : typeInformation . typeName } ; } function additionalTypesFromPlugins ( typeInformation , plugins ) { return List . foldl < ObjectSpec . Plugin , ObjectSpec . Type [ ] > ( ( soFar , plugin ) => buildExtraTypes ( typeInformation , soFar , plugin ) , [ ] , plugins ) ; } function shouldRunPluginForInclude ( includes , requiredIncludeToRun ) { return includes . indexOf ( requiredIncludeToRun ) !== - 1 ; } function shouldRunPluginForIncludes ( includes , plugin ) { return plugin . requiredIncludesToRun . every ( ( requiredInclude ) => shouldRunPluginForInclude ( includes , requiredInclude ) ) ; } function pluginsToRunForValueType ( plugins , objectType ) { return List . filter ( ( plugin ) => shouldRunPluginForIncludes ( objectType . includes , plugin ) , plugins ) ; } function objcPluginForObjectSpecPlugin ( plugin ) { return createObjectSpecObjCPlugIn ( plugin ) ; } function additionalTypesForType ( plugins , typeInformation ) { return additionalTypesFromPlugins ( typeInformation , plugins ) ; } function typeNameForType ( typeInformation ) { return typeInformation . typeName ; } function commentsForType ( typeInformation ) { return typeInformation . comments ; } function visibilityForType ( typeInformation ) { var visibility = undefined ; for ( const key in typeInformation . annotations ) { if ( key === 'visibility' ) { const len = typeInformation . annotations [ key ] . length ; if ( len > 0 ) { const lastValue = typeInformation . annotations [ key ] [ len - 1 ] . properties [ 'value' ] ; if ( lastValue === 'default' ) { visibility = ObjC . ClassVisibility . default ; } else if ( lastValue === 'hidden' ) { visibility = ObjC . ClassVisibility . hidden ; } } } } return visibility ; } export function fileWriteRequest ( request , plugins ) { const pluginsToRun = pluginsToRunForValueType ( plugins , request . typeInformation ) ; const wrappedPlugins = List . map ( objcPluginForObjectSpecPlugin , pluginsToRun ) ; const typeInfoProvider = { additionalTypesForType : ( type ) => additionalTypesForType ( pluginsToRun , type ) , typeNameForType : typeNameForType , commentsForType : commentsForType , visibilityForType : visibilityForType } ; const requestWithUpdatedType = { diagnosticIgnores : request . diagnosticIgnores , baseClassLibraryName : request . baseClassLibraryName , baseClassName : request . baseClassName , path : request . path , outputPath : request . outputPath , outputFlags : request . outputFlags , typeInformation : typeInformationWithAllAttributesFromPlugins ( request . typeInformation , pluginsToRun ) } ; return PluggableObjCFileCreation . fileWriteRequest ( requestWithUpdatedType , typeInfoProvider , wrappedPlugins ) ; }