Esempio n. 1
0
        private string GenerateEnumerableMethodForBatchApiEndpoint(ApiEndpoint apiEndpoint, string baseEndpointPath)
        {
            var indent  = new Indent();
            var builder = new StringBuilder();

            var endpointPath = (baseEndpointPath + "/" + apiEndpoint.Path.Segments.ToPath()).TrimEnd('/');

            var methodNameForEndpoint = apiEndpoint.ToCSharpMethodName();

            var batchDataType = ((ApiFieldType.Object)apiEndpoint.ResponseBody !).GetBatchDataType() !;

            if (apiEndpoint.ResponseBody != null)
            {
                var methodParametersBuilder = new MethodParametersBuilder(_codeGenerationContext)
                                              .WithParametersForApiParameters(apiEndpoint.Parameters);

                if (apiEndpoint.RequestBody != null)
                {
                    if (FeatureFlags.DoNotExposeRequestObjects)
                    {
                        methodParametersBuilder = methodParametersBuilder
                                                  .WithParametersForApiFields(apiEndpoint.RequestBody.Fields);
                    }
                    else
                    {
                        methodParametersBuilder = methodParametersBuilder
                                                  .WithParameter(
                            apiEndpoint.ToCSharpRequestBodyClassName(endpointPath) !,
                            "data");
                    }
                }

                var partialType = "Partial<" + batchDataType.GetBatchElementTypeOrType().ToCSharpType(_codeGenerationContext) + ">";
                var funcType    = $"Func<{partialType}, {partialType}>?";
                methodParametersBuilder = methodParametersBuilder
                                          .WithParameter(
                    funcType,
                    "partial",
                    CSharpExpression.NullLiteral);

                methodParametersBuilder = methodParametersBuilder
                                          .WithParameter(CSharpType.CancellationToken.Value,
                                                         "cancellationToken",
                                                         CSharpExpression.DefaultLiteral);

                builder.Append(
                    indent.Wrap(GenerateMethodDocumentationForEndpoint(apiEndpoint)));
                builder.Append($"{indent}public IAsyncEnumerable<");
                builder.Append(batchDataType.ElementType.ToCSharpType(_codeGenerationContext));
                builder.Append(">");
                builder.Append($" {methodNameForEndpoint}AsyncEnumerable(");
                builder.Append(methodParametersBuilder.BuildMethodParametersList());
                builder.AppendLine(")");

                indent.Increment();
                builder.Append($"{indent}=> BatchEnumerator.AllItems((batchSkip, batchCancellationToken) => ");

                builder.Append($"{methodNameForEndpoint}Async(");

                var partialTypeForBatch = "Partial<Batch<" + batchDataType.GetBatchElementTypeOrType().ToCSharpType(_codeGenerationContext) + ">>";
                builder.Append(
                    methodParametersBuilder
                    .WithDefaultValueForAllParameters(null)
                    .WithDefaultValueForParameter("skip", "batchSkip")
                    .WithDefaultValueForParameter("partial", $"builder => {partialTypeForBatch}.Default().WithNext().WithTotalCount().WithData(partial != null ? partial : _ => {partialType}.Default())")
                    .WithDefaultValueForParameter(CSharpType.CancellationToken.Value, "batchCancellationToken")
                    .BuildMethodCallParameters());

                builder.Append("), skip, cancellationToken);");
                indent.Decrement();
            }
            else
            {
                builder.AppendLine($"{indent}#warning UNSUPPORTED CASE - " + apiEndpoint.ToCSharpMethodName() + " - " + apiEndpoint.Method.ToHttpMethod() + " " + endpointPath);
            }

            return(builder.ToString());
        }
Esempio n. 2
0
        public string GenerateDtoDefinition(ApiDto apiDto)
        {
            var indent  = new Indent();
            var builder = new StringBuilder();

            var typeNameForDto = apiDto.ToCSharpClassName();

            if (apiDto.Deprecation != null)
            {
                builder.AppendLine(apiDto.Deprecation.ToCSharpDeprecation());
            }

            if (apiDto.HierarchyRole != HierarchyRole.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.HierarchyRole == HierarchyRole.INTERFACE
                ? "interface"
                : apiDto.HierarchyRole == HierarchyRole.ABSTRACT
                    ? "abstract class"
                    : apiDto.HierarchyRole == HierarchyRole.FINAL
                        ? "sealed class"
                        : "class";

            var dtoHierarchy           = new List <string>();
            var dtoHierarchyFieldNames = new List <string>();

            if (apiDto.Extends != null && _codeGenerationContext.TryGetDto(apiDto.Extends.Id, out var apiDtoExtends))
            {
                dtoHierarchy.Add(apiDtoExtends !.ToCSharpClassName());
                dtoHierarchyFieldNames.AddRange(apiDtoExtends !.Fields.Select(it => it.Field.Name));
            }
            if (apiDto.Implements != null)
            {
                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));

            builder.AppendLine($"{indent}public {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.HierarchyRole != HierarchyRole.INTERFACE)
            {
                var modifierForClassNameProperty = apiDto.Extends == null
                    ? apiDto.HierarchyRole != HierarchyRole.FINAL
                        ? "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 !.HierarchyRole != HierarchyRole.INTERFACE && apiDtoInheritor.HierarchyRole != HierarchyRole.ABSTRACT)
                {
                    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.HierarchyRole != HierarchyRole.INTERFACE && apiDto.HierarchyRole != HierarchyRole.ABSTRACT)
            {
                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 (FeatureFlags.GenerateAlternativeForOptionalParameterDefaultReferenceTypes && 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(typeNameForDto, apiDtoField.Field)));
            }

            // Implement IPropagatePropertyAccessPath?
            if (dtoHierarchy.Contains(nameof(IPropagatePropertyAccessPath)) && apiDto.HierarchyRole != HierarchyRole.INTERFACE)
            {
                builder.AppendLine(indent.Wrap(GenerateDtoPropagatePropertyAccessPath(apiDto, apiDtoFields)));
            }

            indent.Decrement();
            builder.AppendLine($"{indent}}}");
            return(builder.ToString());
        }
Esempio n. 3
0
        private string GenerateMethodForApiEndpoint(ApiEndpoint apiEndpoint, string baseEndpointPath)
        {
            var indent  = new Indent();
            var builder = new StringBuilder();

            var endpointPath = (baseEndpointPath + "/" + apiEndpoint.Path.Segments.ToPath()).TrimEnd('/');

            var apiCallMethod         = apiEndpoint.Method.ToHttpMethod();
            var methodNameForEndpoint = apiEndpoint.ToCSharpMethodName();

            var isResponsePrimitiveOrArrayOfPrimitive = apiEndpoint.ResponseBody is ApiFieldType.Primitive ||
                                                        (apiEndpoint.ResponseBody is ApiFieldType.Array arrayField && arrayField.ElementType is ApiFieldType.Primitive);

            if (apiEndpoint.ResponseBody == null)
            {
                var methodParametersBuilder = new MethodParametersBuilder(_codeGenerationContext)
                                              .WithParametersForApiParameters(apiEndpoint.Parameters);

                if (apiEndpoint.RequestBody != null)
                {
                    if (FeatureFlags.DoNotExposeRequestObjects)
                    {
                        methodParametersBuilder = methodParametersBuilder
                                                  .WithParametersForApiFields(apiEndpoint.RequestBody.Fields);
                    }
                    else
                    {
                        methodParametersBuilder = methodParametersBuilder
                                                  .WithParameter(
                            apiEndpoint.ToCSharpRequestBodyClassName(endpointPath) !,
                            "data");
                    }
                }

                methodParametersBuilder = methodParametersBuilder
                                          .WithParameter(CSharpType.CancellationToken.Value,
                                                         "cancellationToken",
                                                         CSharpExpression.DefaultLiteral);

                builder.Append(
                    indent.Wrap(GenerateMethodDocumentationForEndpoint(apiEndpoint)));
                builder.Append($"{indent}public async Task {methodNameForEndpoint}Async(");
                builder.Append(methodParametersBuilder.BuildMethodParametersList());
                builder.AppendLine(")");
                builder.AppendLine($"{indent}{{");

                indent.Increment();

                // Generate query string
                var requestParametersBuilder = new QueryStringParameterConversionGenerator("queryParameters", _codeGenerationContext)
                                               .WithQueryStringParametersForEndpoint(apiEndpoint);

                if (apiEndpoint.ResponseBody != null && !isResponsePrimitiveOrArrayOfPrimitive)
                {
                    var partialType = "Partial<" + apiEndpoint.ResponseBody.GetArrayElementTypeOrType().ToCSharpType(_codeGenerationContext) + ">";

                    requestParametersBuilder = requestParametersBuilder
                                               .WithQueryStringParameter("$fields", $"(partial != null ? partial(new {partialType}()) : {partialType}.Default()).ToString()");
                }

                builder.AppendLine($"{indent}var {requestParametersBuilder.TargetNameValueCollectionName} = new NameValueCollection();");
                requestParametersBuilder.WriteTo(builder, indent);
                builder.AppendLine($"{indent}");

                // Generate HTTP request
                builder.Append($"{indent}await _connection.RequestResourceAsync");
                builder.Append("(\"" + apiCallMethod + "\", ");
                builder.Append("$\"api/http/" + endpointPath + "{" + requestParametersBuilder.TargetNameValueCollectionName + ".ToQueryString()}");
                builder.Append("\"");

                if (apiEndpoint.RequestBody != null)
                {
                    if (FeatureFlags.DoNotExposeRequestObjects)
                    {
                        // TODO MAARTEN REFACTOR WITH PROPER NEWLINES
                        builder.Append(", " + ConstructNewRequestObject(indent, apiEndpoint, endpointPath));
                    }
                    else
                    {
                        builder.Append(", data");
                    }
                }

                builder.Append(", cancellationToken");
                builder.AppendLine(");");
                indent.Decrement();
                builder.AppendLine($"{indent}}}");
            }
            else if (apiEndpoint.ResponseBody != null)
            {
                var methodParametersBuilder = new MethodParametersBuilder(_codeGenerationContext)
                                              .WithParametersForApiParameters(apiEndpoint.Parameters);

                if (apiEndpoint.RequestBody != null)
                {
                    if (FeatureFlags.DoNotExposeRequestObjects)
                    {
                        methodParametersBuilder = methodParametersBuilder
                                                  .WithParametersForApiFields(apiEndpoint.RequestBody.Fields);
                    }
                    else
                    {
                        methodParametersBuilder = methodParametersBuilder
                                                  .WithParameter(
                            apiEndpoint.ToCSharpRequestBodyClassName(endpointPath) !,
                            "data");
                    }
                }

                if (apiEndpoint.ResponseBody != null && !isResponsePrimitiveOrArrayOfPrimitive)
                {
                    var partialType = "Partial<" + apiEndpoint.ResponseBody.GetArrayElementTypeOrType().ToCSharpType(_codeGenerationContext) + ">";
                    var funcType    = $"Func<{partialType}, {partialType}>?";
                    methodParametersBuilder = methodParametersBuilder
                                              .WithParameter(
                        funcType,
                        "partial",
                        CSharpExpression.NullLiteral);
                }

                methodParametersBuilder = methodParametersBuilder
                                          .WithParameter(CSharpType.CancellationToken.Value,
                                                         "cancellationToken",
                                                         CSharpExpression.DefaultLiteral);

                builder.Append(
                    indent.Wrap(GenerateMethodDocumentationForEndpoint(apiEndpoint)));
                builder.Append($"{indent}public async Task<");
                builder.Append(apiEndpoint.ResponseBody !.ToCSharpType(_codeGenerationContext));
                builder.Append(">");
                builder.Append($" {methodNameForEndpoint}Async(");
                builder.Append(methodParametersBuilder.BuildMethodParametersList());
                builder.AppendLine(")");
                builder.AppendLine($"{indent}{{");

                indent.Increment();

                // Generate query string
                var requestParametersBuilder = new QueryStringParameterConversionGenerator("queryParameters", _codeGenerationContext)
                                               .WithQueryStringParametersForEndpoint(apiEndpoint);

                if (apiEndpoint.ResponseBody != null && !isResponsePrimitiveOrArrayOfPrimitive)
                {
                    var partialType = "Partial<" + apiEndpoint.ResponseBody.GetArrayElementTypeOrType().ToCSharpType(_codeGenerationContext) + ">";

                    requestParametersBuilder = requestParametersBuilder
                                               .WithQueryStringParameter("$fields", $"(partial != null ? partial(new {partialType}()) : {partialType}.Default()).ToString()");
                }

                builder.AppendLine($"{indent}var {requestParametersBuilder.TargetNameValueCollectionName} = new NameValueCollection();");
                requestParametersBuilder.WriteTo(builder, indent);
                builder.AppendLine($"{indent}");

                // Generate HTTP request
                builder.Append($"{indent}return await _connection.RequestResourceAsync<");
                if (apiEndpoint.RequestBody != null)
                {
                    builder.Append(apiEndpoint.ToCSharpRequestBodyClassName(endpointPath) !);
                    builder.Append(", ");
                }
                builder.Append(apiEndpoint.ResponseBody !.ToCSharpType(_codeGenerationContext));
                builder.Append(">");
                builder.Append("(\"" + apiCallMethod + "\", ");
                builder.Append("$\"api/http/" + endpointPath + "{" + requestParametersBuilder.TargetNameValueCollectionName + ".ToQueryString()}");
                builder.Append("\"");

                if (apiEndpoint.RequestBody != null)
                {
                    if (FeatureFlags.DoNotExposeRequestObjects)
                    {
                        builder.Append(", " + ConstructNewRequestObject(indent, apiEndpoint, endpointPath));
                    }
                    else
                    {
                        builder.Append(", data");
                    }
                }

                builder.Append(", cancellationToken");
                builder.AppendLine(");");
                indent.Decrement();
                builder.AppendLine($"{indent}}}");
            }
            else
            {
                builder.AppendLine($"{indent}#warning UNSUPPORTED CASE - " + apiEndpoint.ToCSharpMethodName() + " - " + apiEndpoint.Method.ToHttpMethod() + " " + endpointPath);
            }

            return(builder.ToString());
        }