in src/JetBrains.Space.Generator/CodeGeneration/CSharp/Generators/CSharpApiModelDtoGenerator.cs [16:171]
public string GenerateDtoDefinition(ApiDto apiDto)
{
var indent = new Indent();
var builder = new CSharpBuilder();
var typeNameForDto = apiDto.ToCSharpClassName();
if (apiDto.Deprecation != null)
{
builder.AppendLine($"{indent}{apiDto.Deprecation.ToCSharpDeprecation()}");
}
else if (apiDto.FeatureFlag != null && _codeGenerationContext.TryGetFeatureFlag(apiDto.FeatureFlag, out var featureFlag))
{
builder.AppendLine($"{indent}{featureFlag.ToCSharpFeatureFlag()}");
}
else if (apiDto.Experimental != null && FeatureFlags.GenerateExperimentalAnnotations)
{
builder.AppendLine($"{indent}{apiDto.Experimental.ToCSharpExperimental()}");
}
if (apiDto.HierarchyRole2 != HierarchyRole2.INTERFACE && apiDto.HierarchyRole2 != HierarchyRole2.SEALED_INTERFACE && apiDto.Extends == null && apiDto.Inheritors.Count > 0)
{
// When extending another DTO, make sure to apply a converter
builder.AppendLine($"{indent}[JsonConverter(typeof(ClassNameDtoTypeConverter))]");
}
var modifierForDto = apiDto.HierarchyRole2 switch
{
HierarchyRole2.INTERFACE => "interface",
HierarchyRole2.SEALED_INTERFACE => "interface",
HierarchyRole2.ABSTRACT_CLASS => "abstract class",
HierarchyRole2.FINAL_CLASS => "sealed class",
_ => "class"
};
var dtoHierarchy = new List<string>();
if (apiDto.Extends != null && _codeGenerationContext.TryGetDto(apiDto.Extends.Id, out var apiDtoExtends))
{
dtoHierarchy.Add(apiDtoExtends!.ToCSharpClassName());
}
foreach (var dtoImplements in apiDto.Implements)
{
if (_codeGenerationContext.TryGetDto(dtoImplements.Id, out var apiDtoImplements))
{
dtoHierarchy.Add(apiDtoImplements!.ToCSharpClassName());
}
}
if (dtoHierarchy.Count > 0 || apiDto.Inheritors.Count > 0)
{
dtoHierarchy.Add(nameof(IClassNameConvertible));
}
dtoHierarchy.Add(nameof(IPropagatePropertyAccessPath));
var visibilityModifier = "public";
if (FeatureFlags.DoNotExposeRequestObjects && _codeGenerationContext.IsRequestBodyDto(apiDto.Id))
{
visibilityModifier = "internal";
}
builder.AppendLine($"{indent}{visibilityModifier} {modifierForDto} {typeNameForDto}");
indent.Increment();
builder.AppendLine($"{indent} : " + string.Join(", ", dtoHierarchy));
indent.Decrement();
builder.AppendLine($"{indent}{{");
indent.Increment();
// When in a hierarchy with IClassNameConvertible, make sure we can capture the class name.
if (dtoHierarchy.Contains(nameof(IClassNameConvertible)) && apiDto.HierarchyRole2 != HierarchyRole2.INTERFACE && apiDto.HierarchyRole2 != HierarchyRole2.SEALED_INTERFACE)
{
var modifierForClassNameProperty = apiDto.Extends == null
? apiDto.HierarchyRole2 != HierarchyRole2.FINAL_CLASS
? "virtual" // Parent
: ""
: "override"; // Inheritor
builder.AppendLine($"{indent}[JsonPropertyName(\"className\")]");
builder.AppendLine($"{indent}public {modifierForClassNameProperty} string? ClassName => \"{apiDto.Name}\";");
builder.AppendLine($"{indent}");
}
// Determine list of fields
var apiDtoFields = DetermineFieldsToGenerateFor(apiDto);
// Generate factories for inheritors
foreach (var apiDtoInheritorReference in apiDto.Inheritors)
{
if (_codeGenerationContext.TryGetDto(apiDtoInheritorReference.Id, out var apiDtoInheritor)
&& apiDtoInheritor!.HierarchyRole2 != HierarchyRole2.INTERFACE && apiDtoInheritor.HierarchyRole2 != HierarchyRole2.SEALED_INTERFACE && apiDtoInheritor.HierarchyRole2 != HierarchyRole2.ABSTRACT_CLASS)
{
var inheritorTypeName = apiDtoInheritor.ToCSharpClassName();
var inheritorFactoryMethodName = apiDtoInheritor.ToCSharpFactoryMethodName(apiDto);
var methodParametersBuilder = new MethodParametersBuilder(_codeGenerationContext)
.WithParametersForApiDtoFields(DetermineFieldsToGenerateFor(apiDtoInheritor));
builder.AppendLine($"{indent}public static {inheritorTypeName} {inheritorFactoryMethodName}({methodParametersBuilder.BuildMethodParametersList()})");
indent.Increment();
builder.AppendLine($"{indent}=> new {inheritorTypeName}({methodParametersBuilder.WithDefaultValueForAllParameters(null).BuildMethodCallParameters()});");
indent.Decrement();
builder.AppendLine($"{indent}");
}
}
// Generate constructor
// ReSharper disable once RedundantLogicalConditionalExpressionOperand
if (apiDto.HierarchyRole2 != HierarchyRole2.INTERFACE && apiDto.HierarchyRole2 != HierarchyRole2.SEALED_INTERFACE && apiDto.HierarchyRole2 != HierarchyRole2.ABSTRACT_CLASS)
{
var methodParametersBuilder = new MethodParametersBuilder(_codeGenerationContext)
.WithParametersForApiDtoFields(apiDtoFields);
// Empty constructor
builder.AppendLine($"{indent}public {typeNameForDto}() {{ }}");
builder.AppendLine($"{indent}");
// Parameterized constructor
if (apiDtoFields.Count > 0)
{
builder.AppendLine($"{indent}public {typeNameForDto}({methodParametersBuilder.BuildMethodParametersList()})");
builder.AppendLine($"{indent}{{");
indent.Increment();
foreach (var apiDtoField in apiDtoFields)
{
if (apiDtoField.Field.Type.IsCSharpReferenceType())
{
builder.AppendLine($"{indent}{apiDtoField.Field.ToCSharpPropertyName(typeNameForDto)} = {apiDtoField.Field.ToCSharpVariableInstanceOrDefaultValue(_codeGenerationContext)};");
}
else
{
builder.AppendLine($"{indent}{apiDtoField.Field.ToCSharpPropertyName(typeNameForDto)} = {apiDtoField.Field.ToCSharpVariableName()};");
}
}
indent.Decrement();
builder.AppendLine($"{indent}}}");
builder.AppendLine($"{indent}");
}
}
// Generate properties for fields
foreach (var apiDtoField in apiDtoFields)
{
builder.AppendLine(indent.Wrap(GenerateDtoFieldDefinition(apiDto.Id, typeNameForDto, apiDtoField.Field)));
}
// Implement IPropagatePropertyAccessPath?
if (dtoHierarchy.Contains(nameof(IPropagatePropertyAccessPath)) && apiDto.HierarchyRole2 != HierarchyRole2.INTERFACE && apiDto.HierarchyRole2 != HierarchyRole2.SEALED_INTERFACE)
{
builder.AppendLine(indent.Wrap(GenerateDtoPropagatePropertyAccessPath(apiDto, apiDtoFields)));
}
indent.Decrement();
builder.AppendLine($"{indent}}}");
return builder.ToString();
}