/**
 * 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 AlgebraicType from './algebraic-type' ; import * as AlgebraicTypeCreation from './algebraic-type-creation' ; import * as AlgebraicTypeParser from './algebraic-type-parser' ; import * as CommandLine from './commandline' ; import * as Configuration from './configuration' ; import * as Either from './either' ; import * as Error from './error' ; import * as File from './file' ; import * as FileFinder from './file-finder' ; import * as FileWriter from './file-writer' ; import * as List from './list' ; import * as Logging from './logging' ; import * as LoggingSequenceUtils from './logged-sequence-utils' ; import * as Maybe from './maybe' ; import * as OutputControl from './output-control' ; import * as PathUtils from './path-utils' ; import * as PluginInclusionUtils from './plugin-inclusion-utils' ; import * as Promise from './promise' ; import * as ReadFileUtils from './file-logged-sequence-read-utils' ; import * as RequirePlugin from './require-plugin' ; import * as WriteFileUtils from './file-logged-sequence-write-utils' ; interface AlgebraicTypeCreationContext { baseClassName : string ; baseClassLibraryName : string | null ; diagnosticIgnores : List . List < string > ; plugins : List . List < AlgebraicType . Plugin > ; defaultIncludes : List . List < string > ; } interface PathAndTypeInfo { path : File . AbsoluteFilePath ; typeInformation : AlgebraicType . Type ; } interface GenerationOptions { outputPath : File . AbsoluteFilePath | null ; outputFlags : OutputControl . OutputFlags ; } const BASE_INCLUDES = List . of ( 'AlgebraicTypeInitialization' , 'RMAssertNullability' , 'RMCopying' , 'RMDescription' , 'RMEquality' , 'RMInitNewUnavailable' , 'VoidMatching' ) ; const BASE_PLUGINS = List . of ( 'algebraic-type-initialization' , 'assert-nullability' , 'assume-nonnull' , 'coding' , 'copying' , 'copying-type-safety' , 'description' , 'equality' , 'init-new-unavailable' , 'subclassing-restricted' , 'use-cpp' , 'algebraic-type-matching-bool' , 'algebraic-type-matching-double' , 'algebraic-type-matching-generic' , 'algebraic-type-matching-integer' , 'algebraic-type-matching-void' , 'algebraic-type-case-matching' , 'algebraic-type-templated-matching' ) ; function evaluateUnparsedAlgebraicTypeCreationRequest ( request ) { const parseResult = AlgebraicTypeParser . parse ( File . getContents ( request . fileContents ) ) ; return Either . map ( function ( foundType ) { return { path : request . path , typeInformation : foundType } ; } , parseResult ) ; } function parseValues ( either ) { return Promise . munit ( Logging . munit ( Either . mbind ( evaluateUnparsedAlgebraicTypeCreationRequest , either ) ) ) ; } function typeInformationContainingDefaultIncludes ( typeInformation , defaultIncludes ) { return { annotations : typeInformation . annotations , comments : typeInformation . comments , excludes : typeInformation . excludes , includes : PluginInclusionUtils . includesContainingDefaultIncludes ( typeInformation . includes , typeInformation . excludes , defaultIncludes ) , libraryName : typeInformation . libraryName , name : typeInformation . name , typeLookups : typeInformation . typeLookups , subtypes : typeInformation . subtypes } ; } function processAlgebraicTypeCreationRequest ( options , future , either ) { return Promise . map ( function ( creationContextEither ) { return Logging . munit ( Either . mbind ( function ( pathAndTypeInfo ) { return Either . mbind ( function ( creationContext ) { const request = { diagnosticIgnores : creationContext . diagnosticIgnores , baseClassLibraryName : creationContext . baseClassLibraryName , baseClassName : creationContext . baseClassName , path : pathAndTypeInfo . path , outputPath : options . outputPath , outputFlags : options . outputFlags , typeInformation : typeInformationContainingDefaultIncludes ( pathAndTypeInfo . typeInformation , creationContext . defaultIncludes ) } ; return AlgebraicTypeCreation . fileWriteRequest ( request , creationContext . plugins ) ; } , creationContextEither ) ; } , either ) ) ; } , future ) ; } function pluginsFromPluginConfigs ( pluginConfigs ) { return List . foldr ( function ( soFar , config ) : Either . Either < Error . Error [ ] , List . List < AlgebraicType . Plugin > > { return Either . mbind ( function ( list ) : Either . Either < Error . Error [ ] , List . List < AlgebraicType . Plugin > > { return Either . map ( function ( maybePlugin ) : List . List < AlgebraicType . Plugin > { return Maybe . match ( function ( plugin ) { return List . cons ( plugin , list ) ; } , function ( ) { return list ; } , maybePlugin ) ; } , RequirePlugin . requireAlgebraicTypePlugin ( config . absolutePath ) ) ; } , soFar ) ; } , Either . Right < Error . Error [ ] , List . List < AlgebraicType . Plugin > > ( List . of < AlgebraicType . Plugin > ( ) ) , pluginConfigs ) ; } function getAlgebraicTypeCreationContext ( findConfigFuture , parsedArgs ) { return Promise . mbind ( function ( maybePath ) : Promise . Future < Either . Either < Error . Error [ ] , AlgebraicTypeCreationContext > > { const configurationContext = { basePlugins : BASE_PLUGINS , baseIncludes : BASE_INCLUDES } ; const configFuture = Configuration . generateConfig ( maybePath , configurationContext ) ; return Promise . map ( function ( either ) : Either . Either < Error . Error [ ] , AlgebraicTypeCreationContext > { return Either . match ( function ( error ) : Either . Either < Error . Error [ ] , AlgebraicTypeCreationContext > { return Either . Left < Error . Error [ ] , AlgebraicTypeCreationContext > ( error ) ; } , function ( configuration ) : Either . Either < Error . Error [ ] , AlgebraicTypeCreationContext > { const pluginsEither = pluginsFromPluginConfigs ( configuration . pluginConfigs ) ; return Either . map ( function ( plugins ) : AlgebraicTypeCreationContext { return { baseClassName : configuration . baseClassName , baseClassLibraryName : configuration . baseClassLibraryName , diagnosticIgnores : configuration . diagnosticIgnores , plugins : plugins , defaultIncludes : List . fromArray < string > ( PluginInclusionUtils . includesContainingDefaultIncludes ( parsedArgs . includes , parsedArgs . excludes , configuration . defaultIncludes ) ) } ; } , pluginsEither ) ; } , either ) ; } , configFuture ) ; } , findConfigFuture ) ; } function outputDirectory ( directoryRunFrom , outputPath ) { if ( outputPath === undefined || outputPath === '' ) { return null ; } else { return PathUtils . getAbsolutePathFromDirectoryAndAbsoluteOrRelativePath ( File . getAbsoluteFilePath ( directoryRunFrom ) , outputPath ) ; } } export function generate ( directoryRunFrom , optionalConfigPath , parsedArgs ) { const promises = parsedArgs . givenPaths . map ( ( givenPath ) => { const requestedPath = PathUtils . getAbsolutePathFromDirectoryAndAbsoluteOrRelativePath ( File . getAbsoluteFilePath ( directoryRunFrom ) , givenPath ) ; const outputPath = outputDirectory ( directoryRunFrom , parsedArgs . outputPath ) ; const configPath = optionalConfigPath ? FileFinder . findConfigAtPath ( File . getAbsoluteFilePath ( optionalConfigPath ) ) : FileFinder . searchForConfig ( '.algebraicTypeConfig' , requestedPath ) ; const algebraicTypeCreationContextFuture = getAlgebraicTypeCreationContext ( configPath , parsedArgs ) ; const readFileSequence = ReadFileUtils . loggedSequenceThatReadsFiles ( requestedPath , 'adtValue' ) ; const parsedSequence = LoggingSequenceUtils . mapLoggedSequence ( readFileSequence , parseValues ) ; const options = { outputPath : outputPath , outputFlags : parsedArgs . outputFlags } ; const pluginProcessedSequence = LoggingSequenceUtils . mapLoggedSequence ( parsedSequence , ( either ) => processAlgebraicTypeCreationRequest ( options , algebraicTypeCreationContextFuture , either ) ) ; return WriteFileUtils . evaluateObjectFileWriteRequestSequence ( parsedArgs , pluginProcessedSequence ) ; } ) ; return Promise . all ( List . fromArray ( promises ) ) ; }