• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

net-daemon / netdaemon / 6742201237

03 Nov 2023 06:54AM UTC coverage: 79.655% (+0.1%) from 79.548%
6742201237

push

github

helto4real
[Codegen] Allow any nullable double fields to be strings or doubles and improved error reporting (#984)

* Allow any nullable double fields to be strings or doubles and improved error reporting

* small fix

813 of 1153 branches covered (0.0%)

Branch coverage included in aggregate %.

49 of 57 new or added lines in 5 files covered. (85.96%)

8 existing lines in 3 files now uncovered.

2926 of 3541 relevant lines covered (82.63%)

50.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.56
/src/HassModel/NetDaemon.HassModel.CodeGenerator/Controller.cs
1
using System.IO;
2
using System.Reflection;
3
using System.Threading.Tasks;
4
using NetDaemon.Client.Settings;
5

6
namespace NetDaemon.HassModel.CodeGenerator;
7

8
#pragma warning disable CA1303
9
#pragma warning disable CA2000 // because of await using ... configureAwait()
10

11
internal class Controller
12
{
13
    private const string ResourceName = "NetDaemon.HassModel.CodeGenerator.MetaData.DefaultMetadata.DefaultEntityMetaData.json";
14
    private readonly CodeGenerationSettings _generationSettings;
15
    private readonly HomeAssistantSettings _haSettings;
16

17
    public Controller(CodeGenerationSettings generationSettings, HomeAssistantSettings haSettings)
1✔
18
    {
19
        _generationSettings = generationSettings;
1✔
20
        _haSettings = haSettings;
1✔
21
    }
1✔
22

23
    private string EntityMetaDataFileName => Path.Combine(OutputFolder, "EntityMetaData.json");
1✔
24
    private string ServicesMetaDataFileName => Path.Combine(OutputFolder, "ServicesMetaData.json");
×
25

26
    private string OutputFolder => string.IsNullOrEmpty(_generationSettings.OutputFolder)
1!
27
        ? Directory.GetParent(Path.GetFullPath(_generationSettings.OutputFile))!.FullName
1✔
28
        : _generationSettings.OutputFolder;
1✔
29

30
    public async Task RunAsync()
31
    {
32
        var (hassStates, servicesMetaData) = await HaRepositry.GetHaData(_haSettings).ConfigureAwait(false);
×
33

34
        var previousEntityMetadata = await LoadEntitiesMetaDataAsync().ConfigureAwait(false);
×
35
        var currentEntityMetaData = EntityMetaDataGenerator.GetEntityDomainMetaData(hassStates);
×
36
        var mergedEntityMetaData = EntityMetaDataMerger.Merge(_generationSettings, previousEntityMetadata, currentEntityMetaData);
×
37

38
        await Save(mergedEntityMetaData, EntityMetaDataFileName).ConfigureAwait(false);
×
39
        await Save(servicesMetaData, ServicesMetaDataFileName).ConfigureAwait(false);
×
40

NEW
41
        var hassServiceDomains = ServiceMetaDataParser.Parse(servicesMetaData!.Value, out var deserializationErrors);
×
NEW
42
        CheckParseErrors(deserializationErrors);
×
43

NEW
44
        var generatedTypes = Generator.GenerateTypes(mergedEntityMetaData.Domains, hassServiceDomains);
×
45

46
        SaveGeneratedCode(generatedTypes);
×
47
    }
×
48

49
    internal static void CheckParseErrors(List<DeserializationError> parseErrors)
50
    {
51
        if (parseErrors.Count == 0) return;
1!
52

53
        Console.ForegroundColor = ConsoleColor.Yellow;
1✔
54
        Console.WriteLine("""
1✔
55
                          Errors occured while parsing metadata from Home Assistant for one or more services.
1✔
56
                          This is usually caused by metadata from HA that is not in the expected JSON format.
1✔
57
                          nd-codegen will try to continue to generate code for other services.
1✔
58
                          """);
1✔
59
        Console.ResetColor();
1✔
60
        foreach (var deserializationError in parseErrors)
4✔
61
        {
62
            Console.WriteLine();
1✔
63
            Console.WriteLine(deserializationError.Exception);
1✔
64
            Console.WriteLine(deserializationError.Context + " = ");
1✔
65
            Console.Out.Flush();
1✔
66
            Console.WriteLine(JsonSerializer.Serialize(deserializationError.Element, new JsonSerializerOptions{WriteIndented = true}));
1✔
67
        }
68
    }
1✔
69

70
    internal async Task<EntitiesMetaData> LoadEntitiesMetaDataAsync()
71
    {
72
        var fileStream = File.Exists(EntityMetaDataFileName) switch
1!
73
        {
1✔
74
            true => File.OpenRead(EntityMetaDataFileName),
×
75
            false => GetDefaultMetaDataFileFromResource()
1✔
76
        };
1✔
77

78
        await using var _ = fileStream.ConfigureAwait(false);
1✔
79

80
        var loaded = await JsonSerializer.DeserializeAsync<EntitiesMetaData>(fileStream, JsonSerializerOptions).ConfigureAwait(false);
1✔
81

82
        return loaded ?? new EntitiesMetaData();
1!
83
    }
1✔
84

85
    private static Stream GetDefaultMetaDataFileFromResource()
86
    {
87
        var assembly = Assembly.GetExecutingAssembly();
1✔
88
        return assembly.GetManifestResourceStream(ResourceName)!;
1✔
89
    }
90

91
    private async Task Save<T>(T merged, string fileName)
92
    {
93
        Directory.CreateDirectory(OutputFolder);
×
94

95
        var fileStream = File.Create(fileName);
×
96
        await using var _ = fileStream.ConfigureAwait(false);
×
97
        await JsonSerializer.SerializeAsync(fileStream, merged, JsonSerializerOptions).ConfigureAwait(false);
×
98
    }
×
99

100
    private static JsonSerializerOptions JsonSerializerOptions =>
101
        new()
1✔
102
        {
1✔
103
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
1✔
104
            WriteIndented = true,
1✔
105
            Converters = { new ClrTypeJsonConverter() }
1✔
106
        };
1✔
107

108
    private void SaveGeneratedCode(MemberDeclarationSyntax[] generatedTypes)
109
    {
110
        if (!_generationSettings.GenerateOneFilePerEntity)
×
111
        {
112
            Console.WriteLine("Generating single file for all entities.");
×
113
            var unit = Generator.BuildCompilationUnit(_generationSettings.Namespace, generatedTypes.ToArray());
×
114

115
            Directory.CreateDirectory(Directory.GetParent(_generationSettings.OutputFile)!.FullName);
×
116

117
            using var writer = new StreamWriter(_generationSettings.OutputFile);
×
118
            unit.WriteTo(writer);
×
119

120
            Console.WriteLine(Path.GetFullPath(_generationSettings.OutputFile));
×
121
        }
122
        else
123
        {
124
            Console.WriteLine("Generating separate file per entity.");
×
125

126
            Directory.CreateDirectory(OutputFolder);
×
127

128
            foreach (var type in generatedTypes)
×
129
            {
130
                var unit = Generator.BuildCompilationUnit(_generationSettings.Namespace, type);
×
131
                using var writer = new StreamWriter(Path.Combine(OutputFolder, $"{unit.GetClassName()}.cs"));
×
132
                unit.WriteTo(writer);
×
133
            }
134

135
            Console.WriteLine($"Generated {generatedTypes.Length} files.");
×
136
            Console.WriteLine(OutputFolder);
×
137
        }
138
    }
×
139
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc