/**
 * 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 File from '../file' ; import * as FileWriter from '../file-writer' ; import * as List from '../list' ; import * as Maybe from '../maybe' ; import * as ObjC from '../objc' ; import * as ObjectSpec from '../object-spec' ; import * as ObjectSpecCreation from '../object-spec-creation' ; import * as OutputControl from '../output-control' ; describe ( 'ObjectSpecCreation' , function ( ) { describe ( '#fileWriteRequests' , function ( ) { it ( 'returns a header and implementation including the instance methods ' + 'when there is a single plugin that returns instance methods' , function ( ) { const Plugin = { requiredIncludesToRun : [ ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ { content : '// Copyright something something. All Rights Reserved.' } , ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { const instanceMethods = [ { preprocessors : [ ] , belongsToProtocol : 'NSObject' , comments : [ ] , code : [ 'return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];' , ] , compilerAttributes : [ ] , keywords : [ { name : 'description' , argument : null } , ] , returnType : { type : { name : 'NSString' , reference : 'NSString *' } , modifiers : [ ] } } , ] ; return instanceMethods ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'Foo' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : null , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin ) ) ; const expectedRequests = List . of < FileWriter . Request > ( FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.h' ) , '// Copyright something something. All Rights Reserved.\n' + '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '@interface Foo : NSObject\n' + '\n' + '@end\n' ) , FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.m' ) , '// Copyright something something. All Rights Reserved.\n' + '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '#if  ! __has_feature(objc_arc)\n' + '#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).\n' + '#endif\n\n' + '@implementation Foo\n' + '\n' + '- (NSString *)description\n' + '{\n' + '  return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];\n' + '}\n' + '\n' + '@end\n' ) ) ; const expectedRequest = Either . Right < Error . Error , FileWriter . FileWriteRequest > ( { name : 'Foo' , requests : expectedRequests } ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; it ( 'returns two headers and implementations when there is a single plugin ' + 'which returns an additional header and implementation' , function ( ) { const Plugin = { requiredIncludesToRun : [ ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ { name : 'FooMore' , type : Code . FileType . ObjectiveC , imports : [ ] , comments : [ ] , enumerations : [ ] , blockTypes : [ ] , staticConstants : [ ] , globalVariables : [ ] , diagnosticIgnores : [ ] , forwardDeclarations : [ ] , functions : [ ] , classes : [ { baseClassName : 'NSObject' , covariantTypes : [ ] , classMethods : [ ] , inlineBlockTypedefs : [ ] , instanceMethods : [ ] , name : 'FooMore' , comments : [ ] , properties : [ ] , instanceVariables : [ ] , implementedProtocols : [ ] , nullability : ObjC . ClassNullability . default , subclassingRestricted : false } , ] , structs : [ ] , cppClasses : [ ] , namespaces : [ ] , macros : [ ] } , ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ { name : 'NSCopying' } ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'Foo' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : null , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin ) ) ; const expectedRequests = List . of < FileWriter . Request > ( FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.h' ) , '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '@interface Foo : NSObject <NSCopying>\n' + '\n' + '@end\n' ) , FileWriter . Request ( File . getAbsoluteFilePath ( 'FooMore.h' ) , '@interface FooMore : NSObject\n' + '\n' + '@end\n' ) ) ; const expectedRequest = Either . Right < Error . Error , FileWriter . FileWriteRequest > ( { name : 'Foo' , requests : expectedRequests } ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; it ( 'returns multiple types when there is ' + 'a single plugin that returns multiple methods' , function ( ) { const Plugin = { requiredIncludesToRun : [ ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'AddedType1' } , { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'AddedType2' } , ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ { name : 'NSCopying' } ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'ExistingType' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : null , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin ) ) ; const expectedRequests = List . of < FileWriter . Request > ( FileWriter . Request ( File . getAbsoluteFilePath ( 'ExistingType.h' ) , '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '@interface ExistingType : NSObject <NSCopying>\n' + '\n' + '@end\n' ) , FileWriter . Request ( File . getAbsoluteFilePath ( 'AddedType1.h' ) , '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '@interface AddedType1 : NSObject <NSCopying>\n' + '\n' + '@end\n' ) , FileWriter . Request ( File . getAbsoluteFilePath ( 'AddedType2.h' ) , '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '@interface AddedType2 : NSObject <NSCopying>\n' + '\n' + '@end\n' ) ) ; const expectedRequest = Either . Right < Error . Error , FileWriter . FileWriteRequest > ( { name : 'ExistingType' , requests : expectedRequests } ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; it ( 'returns a header not including the instance methods ' + 'from a plugin does not have its required includes fulfilled' + 'and that having a empty ObjectSpec does not produce an @interface declaration' , function ( ) { const Plugin = { requiredIncludesToRun : [ 'Test' ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { const instanceMethods = [ { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return @"foo";' ] , compilerAttributes : [ ] , keywords : [ { name : 'foo' , argument : null } , ] , returnType : { type : { name : 'NSString' , reference : 'NSString *' } , modifiers : [ ] } } , ] ; return instanceMethods ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'Foo' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : null , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin ) ) ; const expectedRequests = List . of < FileWriter . Request > ( FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.h' ) , '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n' ) ) ; const expectedRequest = Either . Right < Error . Error , FileWriter . FileWriteRequest > ( { name : 'Foo' , requests : expectedRequests } ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; it ( 'orders the initilizers at the top and the rest of the methods ' + 'alphabetically there are multiple initializers and methods' , function ( ) { const Plugin = { requiredIncludesToRun : [ ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { const instanceMethods = [ { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return @"something";' ] , compilerAttributes : [ ] , keywords : [ { name : 'getSomeString' , argument : null } , ] , returnType : { type : { name : 'NSString' , reference : 'NSString *' } , modifiers : [ ] } } , { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];' , ] , compilerAttributes : [ ] , keywords : [ { name : 'debugDescription' , argument : null } , ] , returnType : { type : { name : 'NSString' , reference : 'NSString *' } , modifiers : [ ] } } , { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return [self init];' ] , compilerAttributes : [ ] , keywords : [ { name : 'initSomethingElse' , argument : null } , ] , returnType : { type : { name : 'instancetype' , reference : 'instancetype' } , modifiers : [ ] } } , ] ; return instanceMethods ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'Foo' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : null , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin ) ) ; const expectedRequests = List . of < FileWriter . Request > ( FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.h' ) , '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '@interface Foo : NSObject\n' + '\n' + '- (instancetype)initSomethingElse;\n' + '\n' + '- (NSString *)debugDescription;\n' + '\n' + '- (NSString *)getSomeString;\n' + '\n' + '@end\n' ) , FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.m' ) , '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '#if  ! __has_feature(objc_arc)\n' + '#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).\n' + '#endif\n\n' + '@implementation Foo\n' + '\n' + '- (instancetype)initSomethingElse\n' + '{\n' + '  return [self init];\n' + '}\n' + '\n' + '- (NSString *)debugDescription\n' + '{\n' + '  return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];\n' + '}\n' + '\n' + '- (NSString *)getSomeString\n' + '{\n' + '  return @"something";\n' + '}\n' + '\n' + '@end\n' ) ) ; const expectedRequest = Either . Right < Error . Error , FileWriter . FileWriteRequest > ( { name : 'Foo' , requests : expectedRequests } ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; it ( 'returns errors returned from the plugin if it returns a ' + 'validation error' , function ( ) { const Plugin = { requiredIncludesToRun : [ ] , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ Error . Error ( 'Some error' ) ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'Foo' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : null , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin ) ) ; const expectedRequest = Either . Left < Error . Error [ ] , FileWriter . FileWriteRequest > ( [ Error . Error ( '[something.value]Some error' ) , ] ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; it ( 'returns errors returned from two plugins if both return ' + 'validation errors' , function ( ) { const Plugin1 = { requiredIncludesToRun : [ ] , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ Error . Error ( 'Some error' ) , Error . Error ( 'Another error' ) ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const Plugin2 = { requiredIncludesToRun : [ ] , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ Error . Error ( 'Yet another error' ) ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'Foo' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : null , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin1 , Plugin2 ) ) ; const expectedRequest = Either . Left < Error . Error [ ] , FileWriter . FileWriteRequest > ( [ Error . Error ( '[something.value]Some error' ) , Error . Error ( '[something.value]Another error' ) , Error . Error ( '[something.value]Yet another error' ) , ] ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; it ( 'combines the initilizers of multiple plugins when given multiple plugins ' + 'to create an object from' , function ( ) { const Plugin1 = { requiredIncludesToRun : [ ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { const instanceMethods = [ { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return @"something";' ] , compilerAttributes : [ ] , keywords : [ { name : 'getSomeString' , argument : null } , ] , returnType : { type : { name : 'NSString' , reference : 'NSString *' } , modifiers : [ ] } } , { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];' , ] , compilerAttributes : [ ] , keywords : [ { name : 'debugDescription' , argument : null } , ] , returnType : { type : { name : 'NSString' , reference : 'NSString *' } , modifiers : [ ] } } , ] ; return instanceMethods ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const Plugin2 = { requiredIncludesToRun : [ ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { const instanceMethods = [ { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return [self init];' ] , compilerAttributes : [ ] , keywords : [ { name : 'initSomethingElse' , argument : null } , ] , returnType : { type : { name : 'instancetype' , reference : 'instancetype' } , modifiers : [ ] } } , ] ; return instanceMethods ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'Foo' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : null , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin1 , Plugin2 ) ) ; const expectedRequests = List . of < FileWriter . Request > ( FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.h' ) , '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '@interface Foo : NSObject\n' + '\n' + '- (instancetype)initSomethingElse;\n' + '\n' + '- (NSString *)debugDescription;\n' + '\n' + '- (NSString *)getSomeString;\n' + '\n' + '@end\n' ) , FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.m' ) , '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '#if  ! __has_feature(objc_arc)\n' + '#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).\n' + '#endif\n\n' + '@implementation Foo\n' + '\n' + '- (instancetype)initSomethingElse\n' + '{\n' + '  return [self init];\n' + '}\n' + '\n' + '- (NSString *)debugDescription\n' + '{\n' + '  return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];\n' + '}\n' + '\n' + '- (NSString *)getSomeString\n' + '{\n' + '  return @"something";\n' + '}\n' + '\n' + '@end\n' ) ) ; const expectedRequest = Either . Right < Error . Error , FileWriter . FileWriteRequest > ( { name : 'Foo' , requests : expectedRequests } ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; it ( 'combines multiple file transformations when given multiple plugins ' + 'that each transform the file write request' , function ( ) { const Plugin1 = { requiredIncludesToRun : [ ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { const newRequest = { content : 'Plugin1\n' + request . content , path : request . path } ; return newRequest ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { const instanceMethods = [ { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return @"something";' ] , compilerAttributes : [ ] , keywords : [ { name : 'getSomeString' , argument : null } , ] , returnType : { type : { name : 'NSString' , reference : 'NSString *' } , modifiers : [ ] } } , { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];' , ] , compilerAttributes : [ ] , keywords : [ { name : 'debugDescription' , argument : null } , ] , returnType : { type : { name : 'NSString' , reference : 'NSString *' } , modifiers : [ ] } } , ] ; return instanceMethods ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const Plugin2 = { requiredIncludesToRun : [ ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { const newRequest = { content : 'Plugin2\n' + request . content , path : request . path } ; return newRequest ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { const instanceMethods = [ { preprocessors : [ ] , belongsToProtocol : null , comments : [ ] , code : [ 'return [self init];' ] , compilerAttributes : [ ] , keywords : [ { name : 'initSomethingElse' , argument : null } , ] , returnType : { type : { name : 'instancetype' , reference : 'instancetype' } , modifiers : [ ] } } , ] ; return instanceMethods ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'Foo' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : null , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin1 , Plugin2 ) ) ; const expectedRequests = List . of < FileWriter . Request > ( FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.h' ) , 'Plugin1\n' + 'Plugin2\n' + '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '@interface Foo : NSObject\n' + '\n' + '- (instancetype)initSomethingElse;\n' + '\n' + '- (NSString *)debugDescription;\n' + '\n' + '- (NSString *)getSomeString;\n' + '\n' + '@end\n' ) , FileWriter . Request ( File . getAbsoluteFilePath ( 'Foo.m' ) , 'Plugin1\n' + 'Plugin2\n' + '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '#if  ! __has_feature(objc_arc)\n' + '#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).\n' + '#endif\n\n' + '@implementation Foo\n' + '\n' + '- (instancetype)initSomethingElse\n' + '{\n' + '  return [self init];\n' + '}\n' + '\n' + '- (NSString *)debugDescription\n' + '{\n' + '  return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];\n' + '}\n' + '\n' + '- (NSString *)getSomeString\n' + '{\n' + '  return @"something";\n' + '}\n' + '\n' + '@end\n' ) ) ; const expectedRequest = Either . Right < Error . Error , FileWriter . FileWriteRequest > ( { name : 'Foo' , requests : expectedRequests } ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; it ( 'writes the output files into a given output directory' , function ( ) { const Plugin = { requiredIncludesToRun : [ ] , imports : function ( objectType ) : ObjC . Import [ ] { return [ ] ; } , transformFileRequest : function ( request ) : FileWriter . Request { return request ; } , fileType : function ( objectType ) : Code . FileType | null { return null ; } , forwardDeclarations : function ( objectType ) : ObjC . ForwardDeclaration [ ] { return [ ] ; } , headerComments : function ( objectType ) : ObjC . Comment [ ] { return [ { content : '// Copyright something something. All Rights Reserved.' } , ] ; } , instanceMethods : function ( objectType ) : ObjC . Method [ ] { const instanceMethods = [ { preprocessors : [ ] , belongsToProtocol : 'NSObject' , comments : [ ] , code : [ 'return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];' , ] , compilerAttributes : [ ] , keywords : [ { name : 'description' , argument : null } , ] , returnType : { type : { name : 'NSString' , reference : 'NSString *' } , modifiers : [ ] } } , ] ; return instanceMethods ; } , additionalFiles : function ( objectType ) : Code . File [ ] { return [ ] ; } , transformBaseFile : function ( objectType , baseFile ) : Code . File { return baseFile ; } , additionalTypes : function ( objectType ) : ObjectSpec . Type [ ] { return [ ] ; } , attributes : function ( objectType ) : ObjectSpec . Attribute [ ] { return [ ] ; } , properties : function ( objectType ) : ObjC . Property [ ] { return [ ] ; } , classMethods : function ( objectType ) : ObjC . Method [ ] { return [ ] ; } , staticConstants : function ( objectType ) : ObjC . Constant [ ] { return [ ] ; } , implementedProtocols : function ( objectType ) : ObjC . ImplementedProtocol [ ] { return [ ] ; } , functions : function ( objectType ) : ObjC . Function [ ] { return [ ] ; } , macros : function ( valueType ) : ObjC . Macro [ ] { return [ ] ; } , validationErrors : function ( objectType ) : Error . Error [ ] { return [ ] ; } , nullability : function ( objectType ) : ObjC . ClassNullability | null { return null ; } , subclassingRestricted : function ( objectType ) : boolean { return false ; } } ; const objectType = { annotations : { } , attributes : [ ] , comments : [ ] , typeLookups : [ ] , excludes : [ ] , includes : [ ] , libraryName : null , typeName : 'Foo' } ; const generationRequest = { baseClassName : 'NSObject' , baseClassLibraryName : null , diagnosticIgnores : List . of < string > ( ) , path : File . getAbsoluteFilePath ( 'something.value' ) , typeInformation : objectType , outputPath : { absolutePath : 'local/path' } , outputFlags : { emitHeaders : true , emitImplementations : true , outputList : [ ] , singleFile : false } } ; const writeRequest = ObjectSpecCreation . fileWriteRequest ( generationRequest , List . of ( Plugin ) ) ; const expectedRequests = List . of < FileWriter . Request > ( FileWriter . Request ( File . getAbsoluteFilePath ( 'local/path/Foo.h' ) , '// Copyright something something. All Rights Reserved.\n' + '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '@interface Foo : NSObject\n' + '\n' + '@end\n' ) , FileWriter . Request ( File . getAbsoluteFilePath ( 'local/path/Foo.m' ) , '// Copyright something something. All Rights Reserved.\n' + '/**\n' + ' * This file is generated using the remodel generation script.\n' + ' * The name of the input file is something.value\n' + ' */\n\n' + '#if  ! __has_feature(objc_arc)\n' + '#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).\n' + '#endif\n\n' + '@implementation Foo\n' + '\n' + '- (NSString *)description\n' + '{\n' + '  return [NSString stringWithFormat:@"%@ - \\n\\t age: %zd; \\n", [super description], _age];\n' + '}\n' + '\n' + '@end\n' ) ) ; const expectedRequest = Either . Right < Error . Error , FileWriter . FileWriteRequest > ( { name : 'Foo' , requests : expectedRequests } ) ; expect ( writeRequest ) . toEqualJSON ( expectedRequest ) ; } ) ; } ) ; } ) ;