Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/ApiCodeGenerator.Abstraction/ILogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ namespace ApiCodeGenerator.Abstraction
{
public interface ILogger
{
void LogError(string? sourceFile, string message, params object[] messageArgs);
void LogError(string? code, string? sourceFile, string message, params object[] messageArgs);

void LogMessage(string message, params object[] messageArgs);
void LogMessage(string? code, string? sourceFile, string message, params object[] messageArgs);

void LogWarning(string? sourceFile, string message, params object[] messageArgs);
void LogWarning(string? code, string? sourceFile, string message, params object[] messageArgs);
}
}
36 changes: 19 additions & 17 deletions src/ApiCodeGenerator.Core/GenerationTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using ApiCodeGenerator.Abstraction;
using ApiCodeGenerator.Core.NswagDocument;
using ApiCodeGenerator.Core.NswagDocument.Converters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using static ApiCodeGenerator.Core.LogCodes;

namespace ApiCodeGenerator.Core
{
Expand Down Expand Up @@ -69,45 +68,45 @@ internal GenerationTask(
/// Генерирует код и сохраняет его в указанный файл.
/// </summary>
/// <param name="nswagFilePath">Путь к файлу настроек генератора.</param>
/// <param name="openApiFilePath">Путь к файлу документа OpenApi.</param>
/// <param name="apiDocumentPath">Путь к файлу документа Api.</param>
/// <param name="outFilePath">Путь к фалу с результатами генерации.</param>
/// <param name="variables">Перечень пар ключ=значение разделенныз запятой.</param>
/// <param name="baseNswagFilePath">Файл базовых настроек.</param>
/// <returns>True если процесс генерации успешно завершен.</returns>
public async Task<bool> ExecuteAsync(string nswagFilePath,
string openApiFilePath,
string apiDocumentPath,
string outFilePath,
string? variables = null,
string? baseNswagFilePath = null)
{
if (!_fileProvider.Exists(nswagFilePath))
{
Log?.LogError(null, "File '{0}' not found.", nswagFilePath);
Log?.LogError(FileNotFound, nswagFilePath, message: "File '{0}' not found.", messageArgs: nswagFilePath);
return false;
}

// System.Diagnostics.Debugger.Launch();
var vars = ParseVariables(variables);
vars["InputJson"] = openApiFilePath;
vars["InputJson"] = apiDocumentPath;
vars["OutFile"] = outFilePath;
var roVariables = new ReadOnlyDictionary<string, string>(vars);

Log?.LogMessage("Values of nswag variables");
Log?.LogMessage(string.Join(Environment.NewLine, vars.Select(_ => $"\t[{_.Key}] = {_.Value}")));
LogMessage("Values of nswag variables");
LogMessage(string.Join(Environment.NewLine, vars.Select(_ => $"\t[{_.Key}] = {_.Value}")));

JObject? baseNswagDocument = LoadBaseNswag(baseNswagFilePath);
var nswagDocument = _documentFactory.LoadNswagDocument(nswagFilePath, roVariables, baseNswagDocument);

var generatorSettings = nswagDocument.CodeGenerators.FirstOrDefault();
if (generatorSettings.Key is null)
{
Log?.LogWarning(nswagFilePath, "Nswag not contains codeGenerator definition. Skip generation.");
Log?.LogWarning(NotDefineGenerator, nswagFilePath, "Nswag not contains codeGenerator definition. Skip generation.");
return true;
}

if (!_extensions.CodeGenerators.TryGetValue(generatorSettings.Key, out var contentGeneratorFactory))
{
Log?.LogError(nswagFilePath, $"Unable find generator {generatorSettings.Key}. Check package references.");
Log?.LogError(GenNotFound, nswagFilePath, $"Unable find generator {generatorSettings.Key}. Check package references.");
return false;
}

Expand All @@ -117,38 +116,41 @@ public async Task<bool> ExecuteAsync(string nswagFilePath,
{
if (context.DocumentReader is null)
{
Log?.LogWarning(nswagFilePath, "Source not set. Skip generation.");
Log?.LogWarning(NotSetInput, nswagFilePath, "Source not set. Skip generation.");
return true;
}

try
{
Log?.LogMessage($"Use settings: {generatorSettings.Key}");
LogMessage($"Use settings: {generatorSettings.Key}");
var contentGenerator = await contentGeneratorFactory.Invoke(context);

Log?.LogMessage("Generate content for file '{0}'", outFilePath);
LogMessage("Generate content for file '{0}'", outFilePath);
var code = contentGenerator.Generate();

try
{
Log?.LogMessage("Write file '{0}'", outFilePath);
LogMessage("Write file '{0}'", outFilePath);
await _fileProvider.WriteAllTextAsync(outFilePath, code);
}
catch (Exception ex)
{
Log?.LogError("Unable write file. Error:", ex.Message);
Log?.LogError(WriteFileErr, outFilePath, "Unable write file. Error: {0}", ex.Message);
}
}
catch (InvalidOperationException ex)
{
Log?.LogError(nswagFilePath, ex.Message);
Log?.LogError(GenerationErr, nswagFilePath, ex.Message);
return false;
}

return true;
}

return false;

void LogMessage(string message, params object[] messageArgs)
=> Log?.LogMessage(null, nswagFilePath, message, messageArgs);
}

private async Task<GeneratorContext?> CreateGenerationContext(
Expand All @@ -175,7 +177,7 @@ public async Task<bool> ExecuteAsync(string nswagFilePath,

if (result is not null && !string.IsNullOrEmpty(result.Error))
{
Log?.LogError(result.FilePath ?? nswagFilePath, result.Error!);
Log?.LogError(DocumentOpenErr, result.FilePath ?? nswagFilePath, result.Error!);
return null;
}

Expand Down
14 changes: 14 additions & 0 deletions src/ApiCodeGenerator.Core/LogCodes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace ApiCodeGenerator.Core;

internal static class LogCodes
{
public const string FileNotFound = "ACG0001";
public const string GenNotFound = "ACG0002";
public const string DocumentOpenErr = "ACG0003";
public const string WriteFileErr = "ACG0004";
public const string GenerationErr = "ACG0005";

public const string NotDefineGenerator = "ACG1001";
public const string NotSetInput = "ACG1002";
public const string PreprocSkiped = "ACG1003";
}
16 changes: 14 additions & 2 deletions src/ApiCodeGenerator.Core/NswagDocument/PreprocessorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,26 @@ public static Preprocessors GetPreprocessors(IExtensions? extensions, IDictionar
{
var tuple = CreatePreprocessor(processor, method);
if (tuple is null)
log?.LogWarning(null, "Method '{0}' skiped, because his signature not like Func<T,string,T>.", method.ToString());
{
log?.LogWarning(
LogCodes.PreprocSkiped,
null,
message: "Method '{0}' skiped, because his signature not like Func<T,string,T>.",
messageArgs: [method.ToString()]);
}
else
{
yield return tuple.Value;
}
}
}
else
{
log?.LogWarning(null, "Preprocessor '{0}' skiped, because method 'Process' not found.", name!);
log?.LogWarning(
LogCodes.PreprocSkiped,
null,
message: "Preprocessor '{0}' skiped, because method 'Process' not found.",
messageArgs: [name!]);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/ApiCodeGenerator.MSBuild/Console/ConsoleLogAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ namespace ApiCodeGenerator.MSBuild
{
internal class ConsoleLogAdapter : ILogger
{
public void LogError(string? sourceFile, string message, params object[] messageArgs)
public void LogError(string? code, string? sourceFile, string message, params object[] messageArgs)
=> Console.Error.WriteLine($"{sourceFile}: {string.Format(message, messageArgs)}");

public void LogMessage(string message, params object[] messageArgs)
public void LogMessage(string? code, string? sourceFile, string message, params object[] messageArgs)
=> Console.WriteLine($"INFO: {string.Format(message, messageArgs)}");

public void LogWarning(string? sourceFile, string message, params object[] messageArgs)
public void LogWarning(string? code, string? sourceFile, string message, params object[] messageArgs)
=> Console.WriteLine($"WARNING {sourceFile}: {string.Format(message, messageArgs)}");
}
}
12 changes: 6 additions & 6 deletions src/ApiCodeGenerator.MSBuild/Task/MSBuildLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ public MSBuildLogger(TaskLoggingHelper log)
_log = log;
}

public void LogError(string? sourceFile, string message, params object[] messageArgs)
=> _log.LogError(null, null, null, sourceFile, 0, 0, 0, 0, message, messageArgs);
public void LogError(string? errorCode, string? sourceFile, string message, params object[] messageArgs)
=> _log.LogError(null, errorCode, null, sourceFile, 0, 0, 0, 0, message, messageArgs);

public void LogMessage(string message, params object[] messageArgs)
=> _log.LogMessage(message, messageArgs);
public void LogMessage(string? code, string? sourceFile, string message, params object[] messageArgs)
=> _log.LogMessage(null, code, null, sourceFile, 0, 0, 0, 0, Microsoft.Build.Framework.MessageImportance.Normal, message, messageArgs);

public void LogWarning(string? sourceFile, string message, params object[] messageArgs)
=> _log.LogWarning(null, null, null, sourceFile, 0, 0, 0, 0, message, messageArgs);
public void LogWarning(string? warningCode, string? sourceFile, string message, params object[] messageArgs)
=> _log.LogWarning(null, warningCode, null, sourceFile, 0, 0, 0, 0, message, messageArgs);
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public async Task LoadApiDocument_WithTextPreprocess_Log()
Assert.That(apiDocument?.Components?.Schemas, Does.ContainKey(schemaName));
var sch = apiDocument?.Components?.Schemas[schemaName].ToJson(Newtonsoft.Json.Formatting.None);
Assert.That(sch, Is.EqualTo("{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"processed\":{}}"));
logger.Verify(l => l.LogWarning(filePath, It.IsAny<string>()));
logger.Verify(l => l.LogWarning(It.IsAny<string>(), filePath, It.IsAny<string>()));
}

[Test]
Expand Down Expand Up @@ -181,17 +181,17 @@ private void ValidateDocument(AsyncApiDocument document)
.And.ContainKey(channelPrefix + "action.{streetlightId}.dim"));

Assert.NotNull(document.Components);
Assert.That(document.Components.Messages,
Assert.That(document.Components?.Messages,
Is.Not.Null
.And.ContainKey("lightMeasured")
.And.ContainKey("turnOnOff")
.And.ContainKey("dimLight"));

Assert.That(document.Components.Parameters,
Assert.That(document.Components?.Parameters,
Is.Not.Null
.And.ContainKey("streetlightId"));

Assert.That(document.Components.Schemas,
Assert.That(document.Components?.Schemas,
Is.Not.Null
.And.ContainKey("lightMeasuredPayload")
.And.ContainKey("turnOnOffPayload")
Expand All @@ -204,32 +204,32 @@ private void ValidateDocument(AsyncApiDocument document)
.And.ContainKey("mtls-connections"));

// Resolve $ref in channel defintion
var actualChannel = document.Channels[channelPrefix + "event.{streetlightId}.lighting.measured"];
var actualChannel = document.Channels?[channelPrefix + "event.{streetlightId}.lighting.measured"];
Assert.That(actualChannel,
Is.Not.Null
.And.Property("Publish").Not.Null
.And.Property("Subscribe").Null);
Assert.That(actualChannel.Parameters,
Assert.That(actualChannel?.Parameters,
Is.Not.Null
.And.ContainKey("streetlightId"));
Assert.That(actualChannel.Parameters["streetlightId"],
Assert.That(actualChannel?.Parameters["streetlightId"],
Is.Not.Null
.And.Property("ReferencePath").EqualTo("#/components/parameters/streetlightId")
.And.Property("Reference").EqualTo(document.Components.Parameters["streetlightId"]));
Assert.That(actualChannel.Publish?.Message,
.And.Property("Reference").EqualTo(document.Components?.Parameters["streetlightId"]));
Assert.That(actualChannel?.Publish?.Message,
Is.Not.Null
.And.Property("ReferencePath").EqualTo("#/components/messages/lightMeasured")
.And.Property("Reference").EqualTo(document.Components.Messages["lightMeasured"]));
.And.Property("Reference").EqualTo(document.Components?.Messages["lightMeasured"]));

// Resolve $ref in message definition
var actualMessage = document.Components.Messages["turnOnOff"];
var actualMessage = document.Components?.Messages["turnOnOff"];
Assert.That(actualMessage, Is.Not.Null);
Assert.That(actualMessage.Payload,
Assert.That(actualMessage?.Payload,
Is.Not.Null
.And.Property("Reference").EqualTo(document.Components.Schemas["turnOnOffPayload"]));
.And.Property("Reference").EqualTo(document.Components?.Schemas["turnOnOffPayload"]));

// Resolve $ref in schema definition
Assert.That(document.Components.Schemas["turnOnOffPayload"]?.ActualProperties,
Assert.That(document.Components?.Schemas["turnOnOffPayload"]?.ActualProperties,
Is.Not.Null
.And.ContainKey("command"));

Expand All @@ -243,24 +243,24 @@ private void ValidateDocument(AsyncApiDocument document)
// Resolve $ref in servers
Assert.That(document.Servers["mtls-connections"],
Is.Not.Null
.And.Property("Reference").EqualTo(document.Components.Servers["mtls-connections"]));
.And.Property("Reference").EqualTo(document.Components?.Servers["mtls-connections"]));

// Resolve $ref in server variables
Assert.Multiple(() =>
{
var variables = document.Components.Servers["mtls-connections"].Variables;
var variables = document.Components?.Servers["mtls-connections"].Variables;
Assert.That(variables,
Is.Not.Null
.And.ContainKey("someRefVariable")
.And.ContainKey("someVariable"));

Assert.That(variables!["someRefVariable"],
Is.Not.Null
.And.Property("Reference").EqualTo(document.Components.ServerVariables["someRefVariable"]));
.And.Property("Reference").EqualTo(document.Components?.ServerVariables["someRefVariable"]));
});

//Read server variables
Assert.That(document.Components.ServerVariables["someRefVariable"],
Assert.That(document.Components?.ServerVariables["someRefVariable"],
new PredicateConstraint<ServerVariable>(a =>
a.Description == "Some ref variable"
&& a.Enum?.FirstOrDefault() == "def"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public string Process(string data, string? fileName)

public string Process(string data, string? fileName, ILogger? logger)
{
logger?.LogWarning(fileName, "test");
logger?.LogWarning(null, fileName, "test");
return Process(data, fileName);
}
}
Expand Down
Loading
Loading