-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathProductExtensions.cs
More file actions
106 lines (86 loc) · 3.5 KB
/
ProductExtensions.cs
File metadata and controls
106 lines (86 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
using System.Collections.Frozen;
using Elastic.Documentation.Configuration.Versions;
using YamlDotNet.Serialization;
namespace Elastic.Documentation.Configuration.Products;
public static class ProductExtensions
{
public static ProductsConfiguration CreateProducts(this ConfigurationFileProvider provider, VersionsConfiguration versionsConfiguration)
{
var productsFilePath = provider.ProductsFile;
var productsDto = ConfigurationFileProvider.Deserializer.Deserialize<ProductConfigDto>(productsFilePath.OpenText());
var products = productsDto.Products.ToDictionary(
kvp => kvp.Key,
kvp =>
{
var features = ResolveFeatures(kvp.Key, kvp.Value.Features);
var versioningSystem = ResolveVersioningSystem(versionsConfiguration, kvp.Value.Versioning ?? kvp.Key);
versioningSystem ??= !features.PublicReference
? VersioningSystem.None
: throw new InvalidOperationException(
$"Product '{kvp.Key}' has invalid or missing versioning '{kvp.Value.Versioning ?? kvp.Key}' while 'public-reference' is enabled.");
return new Product
{
Id = kvp.Key,
DisplayName = kvp.Value.Display,
VersioningSystem = versioningSystem,
Repository = kvp.Value.Repository ?? kvp.Key,
Features = features
};
});
var publicReferenceProducts = products
.Where(kvp => kvp.Value.Features.PublicReference)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var productDisplayNames = productsDto.Products.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.Display);
return new ProductsConfiguration
{
Products = products.ToFrozenDictionary(),
PublicReferenceProducts = publicReferenceProducts.ToFrozenDictionary(),
ProductDisplayNames = productDisplayNames.ToFrozenDictionary()
};
}
private static VersioningSystem? ResolveVersioningSystem(VersionsConfiguration versionsConfiguration, string id) =>
VersioningSystemIdExtensions.TryParse(id, out var versioningSystemId, ignoreCase: true, allowMatchingMetadataAttribute: true)
? versionsConfiguration.GetVersioningSystem(versioningSystemId)
: null;
private static ProductFeatures ResolveFeatures(string productId, Dictionary<string, bool>? featuresDto)
{
if (featuresDto is null)
return ProductFeatures.All;
var unknownKeys = featuresDto.Keys
.Where(k => !ProductFeatures.KnownKeys.Contains(k))
.ToList();
if (unknownKeys is { Count: > 0 })
{
var known = string.Join(", ", ProductFeatures.KnownKeys.Order());
throw new InvalidOperationException(
$"Product '{productId}' has unknown feature key(s): {string.Join(", ", unknownKeys)}. Known features: {known}."
);
}
return new ProductFeatures
{
PublicReference = featuresDto.GetValueOrDefault("public-reference"),
ReleaseNotes = featuresDto.GetValueOrDefault("release-notes")
};
}
}
// Private DTOs for deserialization. These match the YAML structure directly.
internal sealed record ProductConfigDto
{
[YamlMember(Alias = "products")]
public Dictionary<string, ProductDto> Products { get; set; } = [];
}
internal sealed record ProductDto
{
[YamlMember(Alias = "display")]
public string Display { get; set; } = string.Empty;
[YamlMember(Alias = "versioning")]
public string? Versioning { get; set; }
public string? Repository { get; set; }
[YamlMember(Alias = "features")]
public Dictionary<string, bool>? Features { get; set; }
}