11using System ;
2- using System . Collections ;
32using System . Collections . Generic ;
43using System . IO ;
54using System . Linq ;
1211using TypeGen . Core . Logging ;
1312using TypeGen . Core . Metadata ;
1413using TypeGen . Core . SpecGeneration ;
14+ using TypeGen . Core . SpecGeneration . Builders . Traits ;
1515using TypeGen . Core . Storage ;
1616using TypeGen . Core . TypeAnnotations ;
1717using TypeGen . Core . Validation ;
@@ -65,8 +65,8 @@ public Generator(GeneratorOptions options, ILogger logger = null)
6565 _typeService = new TypeService ( _metadataReaderFactory , generatorOptionsProvider ) ;
6666 _typeDependencyService = new TypeDependencyService ( _typeService , _metadataReaderFactory , generatorOptionsProvider ) ;
6767 _templateService = new TemplateService ( internalStorage , generatorOptionsProvider ) ;
68-
6968 _tsContentGenerator = new TsContentGenerator ( _typeDependencyService ,
69+
7070 _typeService ,
7171 _templateService ,
7272 new TsContentParser ( _fileSystem ) ,
@@ -140,6 +140,7 @@ public IEnumerable<string> Generate(IEnumerable<GenerationSpec> generationSpecs)
140140 Requires . NotNullOrEmpty ( generationSpecs , nameof ( generationSpecs ) ) ;
141141
142142 generationSpecs = generationSpecs . ToList ( ) ;
143+
143144 var files = new List < string > ( ) ;
144145 _generationContext = new GenerationContext ( _fileSystem ) ;
145146
@@ -153,7 +154,7 @@ public IEnumerable<string> Generate(IEnumerable<GenerationSpec> generationSpecs)
153154 _metadataReaderFactory . GenerationSpec = generationSpec ;
154155
155156 foreach ( KeyValuePair < Type , TypeSpec > kvp in generationSpec . TypeSpecs )
156- files . AddRange ( GenerateMarkedType ( kvp . Key ) ) ;
157+ files . AddRange ( GenerateMarkedType ( kvp . Key , kvp . Value ) ) ;
157158 }
158159
159160 files = files . Distinct ( ) . ToList ( ) ;
@@ -326,15 +327,15 @@ private IEnumerable<string> GenerateIndexFile(IEnumerable<string> generatedFiles
326327 return new [ ] { filename } ;
327328 }
328329
329- private IEnumerable < string > GenerateMarkedType ( Type type )
330+ private IEnumerable < string > GenerateMarkedType ( Type type , TypeSpec typeSpec )
330331 {
331332 if ( Options . IsTypeBlacklisted ( type ) ) return Enumerable . Empty < string > ( ) ;
332333
333334 IEnumerable < string > files = Enumerable . Empty < string > ( ) ;
334335
335336 _generationContext . BeginTypeGeneration ( type ) ;
336337 _generationContext . AddGeneratedType ( type ) ;
337- ExecuteWithTypeContextLogging ( ( ) => { files = GenerateType ( type ) ; } ) ;
338+ ExecuteWithTypeContextLogging ( ( ) => { files = GenerateType ( type , typeSpec ) ; } ) ;
338339 _generationContext . EndTypeGeneration ( ) ;
339340
340341 return files . Distinct ( ) ;
@@ -346,50 +347,51 @@ private IEnumerable<string> GenerateMarkedType(Type type)
346347 /// </summary>
347348 /// <param name="type"></param>
348349 /// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
349- private IEnumerable < string > GenerateType ( Type type )
350+ private IEnumerable < string > GenerateType ( Type type , TypeSpec typeSpec )
350351 {
351352 var classAttribute = _metadataReaderFactory . GetInstance ( ) . GetAttribute < ExportTsClassAttribute > ( type ) ;
352353 var interfaceAttribute = _metadataReaderFactory . GetInstance ( ) . GetAttribute < ExportTsInterfaceAttribute > ( type ) ;
353354 var enumAttribute = _metadataReaderFactory . GetInstance ( ) . GetAttribute < ExportTsEnumAttribute > ( type ) ;
354355
355356 if ( classAttribute != null )
356357 {
357- return GenerateClass ( type , classAttribute ) ;
358+ return GenerateClass ( type , classAttribute , typeSpec ) ;
358359 }
359360
360361 if ( interfaceAttribute != null )
361362 {
362- return GenerateInterface ( type , interfaceAttribute ) ;
363+ return GenerateInterface ( type , interfaceAttribute , typeSpec ) ;
363364 }
364365
365366 if ( enumAttribute != null )
366367 {
367368 return GenerateEnum ( type , enumAttribute ) ;
368369 }
369370
370- return GenerateNotMarkedType ( type , Options . BaseOutputDirectory ) ;
371+ return GenerateNotMarkedType ( type , Options . BaseOutputDirectory , typeSpec ) ;
371372 }
372-
373+
373374 /// <summary>
374375 /// Generates TypeScript files for types that are not marked with an ExportTs... attribute
375376 /// </summary>
376377 /// <param name="type"></param>
377378 /// <param name="outputDirectory"></param>
379+ /// <param name="typeSpec"></param>
378380 /// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
379- private IEnumerable < string > GenerateNotMarkedType ( Type type , string outputDirectory )
381+ private IEnumerable < string > GenerateNotMarkedType ( Type type , string outputDirectory , TypeSpec typeSpec )
380382 {
381383 if ( Options . IsTypeBlacklisted ( type ) ) return Enumerable . Empty < string > ( ) ;
382384
383385 var typeInfo = type . GetTypeInfo ( ) ;
384386 if ( typeInfo . IsClass || typeInfo . IsStruct ( ) )
385387 {
386388 return Options . ExportTypesAsInterfacesByDefault
387- ? GenerateInterface ( type , new ExportTsInterfaceAttribute { OutputDir = outputDirectory } )
388- : GenerateClass ( type , new ExportTsClassAttribute { OutputDir = outputDirectory } ) ;
389+ ? GenerateInterface ( type , new ExportTsInterfaceAttribute { OutputDir = outputDirectory } , typeSpec )
390+ : GenerateClass ( type , new ExportTsClassAttribute { OutputDir = outputDirectory } , typeSpec ) ;
389391 }
390392
391393 if ( typeInfo . IsInterface )
392- return GenerateInterface ( type , new ExportTsInterfaceAttribute { OutputDir = outputDirectory } ) ;
394+ return GenerateInterface ( type , new ExportTsInterfaceAttribute { OutputDir = outputDirectory } , typeSpec ) ;
393395
394396 if ( typeInfo . IsEnum )
395397 return GenerateEnum ( type , new ExportTsEnumAttribute { OutputDir = outputDirectory } ) ;
@@ -402,11 +404,12 @@ private IEnumerable<string> GenerateNotMarkedType(Type type, string outputDirect
402404 /// </summary>
403405 /// <param name="type"></param>
404406 /// <param name="classAttribute"></param>
407+ /// <param name="typeSpec"></param>
405408 /// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
406- private IEnumerable < string > GenerateClass ( Type type , ExportTsClassAttribute classAttribute )
409+ private IEnumerable < string > GenerateClass ( Type type , ExportTsClassAttribute classAttribute , TypeSpec typeSpec )
407410 {
408411 string outputDir = classAttribute . OutputDir ;
409- IEnumerable < string > dependenciesGenerationResult = GenerateTypeDependencies ( type , outputDir ) ;
412+ IEnumerable < string > dependenciesGenerationResult = GenerateTypeDependencies ( type , outputDir , typeSpec ) ;
410413
411414 // get text for sections
412415
@@ -428,7 +431,7 @@ private IEnumerable<string> GenerateClass(Type type, ExportTsClassAttribute clas
428431 }
429432
430433 string importsText = _tsContentGenerator . GetImportsText ( type , outputDir ) ;
431- string propertiesText = GetClassPropertiesText ( type ) ;
434+ string propertiesText = GetClassPropertiesText ( type , typeSpec . AdditionalClassProperties ) ;
432435
433436 // generate the file content
434437
@@ -458,11 +461,12 @@ private IEnumerable<string> GenerateClass(Type type, ExportTsClassAttribute clas
458461 /// </summary>
459462 /// <param name="type"></param>
460463 /// <param name="interfaceAttribute"></param>
464+ /// <param name="typeSpec"></param>
461465 /// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
462- private IEnumerable < string > GenerateInterface ( Type type , ExportTsInterfaceAttribute interfaceAttribute )
466+ private IEnumerable < string > GenerateInterface ( Type type , ExportTsInterfaceAttribute interfaceAttribute , TypeSpec typeSpec )
463467 {
464468 string outputDir = interfaceAttribute . OutputDir ;
465- IEnumerable < string > dependenciesGenerationResult = GenerateTypeDependencies ( type , outputDir ) ;
469+ IEnumerable < string > dependenciesGenerationResult = GenerateTypeDependencies ( type , outputDir , typeSpec ) ;
466470
467471 // get text for sections
468472
@@ -648,20 +652,44 @@ private void LogClassPropertyWarnings(MemberInfo memberInfo)
648652 /// Gets TypeScript class properties definition source code
649653 /// </summary>
650654 /// <param name="type"></param>
655+ /// <param name="additionalProperties"></param>
651656 /// <returns></returns>
652- private string GetClassPropertiesText ( Type type )
657+ private string GetClassPropertiesText ( Type type , IEnumerable < AdditionalClassProperty > additionalProperties )
653658 {
654659 var propertiesText = "" ;
655660 IEnumerable < MemberInfo > memberInfos = type . GetTsExportableMembers ( _metadataReaderFactory . GetInstance ( ) ) ;
656661
657- // create TypeScript source code for properties' definition
658-
662+ // Generate TypeScript properties from C# members
659663 propertiesText += memberInfos
660- . Aggregate ( propertiesText , ( current , memberInfo ) => current + GetClassPropertyText ( type , memberInfo ) ) ;
664+ . Aggregate ( "" , ( current , memberInfo ) => current + GetClassPropertyText ( type , memberInfo ) ) ;
665+
666+ propertiesText += GetAdditionalPropertiesText ( additionalProperties ) ;
661667
662668 return RemoveLastLineEnding ( propertiesText ) ;
663669 }
664670
671+ /// <summary>
672+ /// Gets TypeScript class additional properties if defined
673+ /// </summary>
674+ /// <param name="additionalProperties"></param>
675+ /// <returns></returns>
676+ private string GetAdditionalPropertiesText ( IEnumerable < AdditionalClassProperty > additionalProperties )
677+ {
678+ if ( ! additionalProperties . Any ( ) )
679+ {
680+ return "" ;
681+ }
682+
683+ var additionalPropertiesText = _templateService . FillWithSingleLineComment ( "Additional properties" ) ;
684+
685+ foreach ( var property in additionalProperties )
686+ {
687+ additionalPropertiesText += _templateService . FillClassPropertyTemplate ( property . Name , property . Type , property . DefaultValue ) ;
688+ }
689+
690+ return additionalPropertiesText ;
691+ }
692+
665693 /// <summary>
666694 /// Gets TypeScript interface property definition source code
667695 /// </summary>
@@ -772,8 +800,9 @@ private string GetEnumMembersText(Type type, bool asUnionType)
772800 /// </summary>
773801 /// <param name="type"></param>
774802 /// <param name="outputDir"></param>
803+ /// <param name="typeSpec"></param>
775804 /// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
776- private IEnumerable < string > GenerateTypeDependencies ( Type type , string outputDir )
805+ private IEnumerable < string > GenerateTypeDependencies ( Type type , string outputDir , TypeSpec typeSpec )
777806 {
778807 var generatedFiles = new List < string > ( ) ;
779808 var typeDependencies = _typeDependencyService . GetTypeDependencies ( type ) ;
@@ -793,7 +822,7 @@ private IEnumerable<string> GenerateTypeDependencies(Type type, string outputDir
793822
794823 try
795824 {
796- generatedFiles . AddRange ( GenerateNotMarkedType ( typeDependency , defaultOutputDir ) ) ;
825+ generatedFiles . AddRange ( GenerateNotMarkedType ( typeDependency , defaultOutputDir , typeSpec ) ) ;
797826 }
798827 catch ( Exception ex )
799828 {
0 commit comments