44using System . IO ;
55using System . Linq ;
66using System . Reflection ;
7+ using System . Runtime . CompilerServices ;
8+ using System . Text ;
79using System . Threading . Tasks ;
810using TypeGen . Core . Conversion ;
11+ using TypeGen . Core . Converters ;
912using TypeGen . Core . Extensions ;
1013using TypeGen . Core . Generator . Context ;
1114using TypeGen . Core . Generator . Services ;
@@ -428,6 +431,9 @@ private IEnumerable<string> GenerateClass(Type type, ExportTsClassAttribute clas
428431 }
429432
430433 string importsText = _tsContentGenerator . GetImportsText ( type , outputDir ) ;
434+
435+ string constructorsText = GetClassConstructorsText ( type ) ;
436+
431437 string propertiesText = GetClassPropertiesText ( type ) ;
432438
433439 // generate the file content
@@ -445,8 +451,8 @@ private IEnumerable<string> GenerateClass(Type type, ExportTsClassAttribute clas
445451 var tsDoc = GetTsDocForType ( type ) ;
446452
447453 var content = _typeService . UseDefaultExport ( type ) ?
448- _templateService . FillClassDefaultExportTemplate ( importsText , tsTypeName , tsTypeNameFirstPart , extendsText , implementsText , propertiesText , tsDoc , customHead , customBody , Options . FileHeading ) :
449- _templateService . FillClassTemplate ( importsText , tsTypeName , extendsText , implementsText , propertiesText , tsDoc , customHead , customBody , Options . FileHeading ) ;
454+ _templateService . FillClassDefaultExportTemplate ( importsText , tsTypeName , tsTypeNameFirstPart , extendsText , implementsText , propertiesText , tsDoc , customHead , customBody , constructorsText , Options . FileHeading ) :
455+ _templateService . FillClassTemplate ( importsText , tsTypeName , extendsText , implementsText , propertiesText , tsDoc , customHead , customBody , constructorsText , Options . FileHeading ) ;
450456
451457 // write TypeScript file
452458 FileContentGenerated ? . Invoke ( this , new FileContentGeneratedArgs ( type , filePath , content ) ) ;
@@ -644,6 +650,74 @@ private void LogClassPropertyWarnings(MemberInfo memberInfo)
644650 Logger . Log ( $ "TsOptionalAttribute used for a class property ({ memberInfo . DeclaringType ? . FullName } .{ memberInfo . Name } ). The attribute will be ignored.", LogLevel . Warning ) ;
645651 }
646652
653+ private string GetClassConstructorsText ( Type type )
654+ {
655+ var constructorsText = "" ;
656+ var constructors = type . GetConstructors ( ) ;
657+
658+ //var isRecord = ((TypeInfo)type).DeclaredProperties.FirstOrDefault(x => x.Name == "EqualityContract")?.GetMethod?.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) is object;
659+
660+ var classHasTsConstructorAttribute = type . GetCustomAttributes ( typeof ( TsConstructorAttribute ) ) . Any ( ) ;
661+
662+ var members = type . GetTsExportableMembers ( _metadataReaderFactory . GetInstance ( ) ) . Select ( memberInfo =>
663+ {
664+ var nameAttribute = _metadataReaderFactory . GetInstance ( ) . GetAttribute < TsMemberNameAttribute > ( memberInfo ) ;
665+ var memberName = nameAttribute ? . Name ?? Options . PropertyNameConverters . Convert ( memberInfo . Name , memberInfo ) ;
666+ var typeName = _typeService . GetTsTypeName ( memberInfo ) ;
667+ Type memberType = null ;
668+
669+ switch ( memberInfo . MemberType )
670+ {
671+ case MemberTypes . Field :
672+ memberType = ( ( FieldInfo ) memberInfo ) . FieldType ;
673+ break ;
674+ case MemberTypes . Property :
675+ memberType = ( ( PropertyInfo ) memberInfo ) . PropertyType ;
676+ break ;
677+ }
678+
679+ return new { memberName = memberInfo . Name , memberType , tsName = memberName , tsType = typeName } ;
680+ } ) ;
681+
682+ var tsMemberTypes = members . ToDictionary ( x => x . tsName , x => x . tsType ) ;
683+
684+ //if ctor params all match member names and types or is a Record
685+ var matchedConstructors = constructors . Where ( ctor =>
686+ ( classHasTsConstructorAttribute || ctor . GetCustomAttributes ( typeof ( TsConstructorAttribute ) ) . Any ( ) ) &&
687+ ctor . GetParameters ( ) . All ( p => members . Any ( m => m . memberName . Equals ( p . Name , StringComparison . InvariantCultureIgnoreCase ) && m . memberType == p . ParameterType ) ) ) . ToArray ( ) ;
688+
689+ //if single empty constructor, skip
690+ if ( matchedConstructors . Length == 1 && matchedConstructors [ 0 ] . GetParameters ( ) . Length == 0 )
691+ {
692+ return constructorsText ;
693+ }
694+
695+ constructorsText += matchedConstructors . Aggregate ( constructorsText , ( current , ctorInfo ) => current + GetClassConstructorText ( ctorInfo , tsMemberTypes ) ) ;
696+
697+ return constructorsText ;
698+ }
699+
700+ private string GetClassConstructorText ( ConstructorInfo ctor , Dictionary < string , string > tsMemberTypes )
701+ {
702+ string argumentsText = "" ;
703+ string assignmentsText = "" ;
704+
705+ var parameters = ctor . GetParameters ( ) ;
706+
707+ foreach ( var param in parameters )
708+ {
709+ var matchingKey = tsMemberTypes . Keys . FirstOrDefault ( k => k . Equals ( param . Name , StringComparison . InvariantCultureIgnoreCase ) ) ;
710+
711+ argumentsText += _templateService . FillClassConstructorArgumentTemplate ( matchingKey , tsMemberTypes [ matchingKey ] ) ;
712+ assignmentsText += _templateService . FillClassConstructorAssignmentTemplate ( matchingKey , matchingKey ) ;
713+ }
714+
715+ argumentsText = argumentsText . TrimEnd ( ',' , ' ' ) ;
716+ assignmentsText = RemoveLastLineEnding ( assignmentsText ) ;
717+
718+ return _templateService . FillClassConstructorTemplate ( argumentsText , assignmentsText ) ;
719+ }
720+
647721 /// <summary>
648722 /// Gets TypeScript class properties definition source code
649723 /// </summary>
0 commit comments