Skip to content

Commit 8387e54

Browse files
committed
Rework applies blocks to applies_to with new semantics
1 parent 5f22e13 commit 8387e54

File tree

19 files changed

+825
-282
lines changed

19 files changed

+825
-282
lines changed

docs/syntax/applies.md

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
---
2-
applies:
3-
stack: ga 8.1
4-
serverless: tech-preview
5-
hosted: beta 8.1.1
6-
eck: beta 3.0.2
7-
ece: unavailable
2+
applies_to:
3+
stack: ga 9.1
4+
deployment:
5+
eck: ga 9.0
6+
ess: beta 9.1
7+
ece: discontinued 9.2.0
8+
self: unavailable 9.3.0
9+
serverless:
10+
security: ga 9.0.0
11+
elasticsearch: beta 9.1.0
12+
observability: discontinued 9.2.0
13+
product: coming 9.5, discontinued 9.7
814
---
915

1016
# Applies to
@@ -14,12 +20,18 @@ Using yaml frontmatter pages can explicitly indicate to each deployment targets
1420

1521

1622
```yaml
17-
applies:
18-
stack: ga 8.1
19-
serverless: tech-preview
20-
hosted: beta 8.1.1
21-
eck: beta 3.0.2
22-
ece: unavailable
23+
applies_to:
24+
stack: ga 9.1
25+
deployment:
26+
eck: ga 9.0
27+
ess: beta 9.1
28+
ece: discontinued 9.2.0
29+
self: unavailable 9.3.0
30+
serverless:
31+
security: ga 9.0.0
32+
elasticsearch: beta 9.1.0
33+
observability: discontinued 9.2.0
34+
product: coming 9.5, discontinued 9.7
2335
```
2436
2537
Its syntax is

src/Elastic.Markdown/Myst/Directives/AppliesBlock.cs

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -12,73 +12,5 @@ public class AppliesBlock(DirectiveBlockParser parser, ParserContext context) :
1212
{
1313
public override string Directive => "mermaid";
1414

15-
public Deployment? Deployment { get; private set; }
16-
17-
public override void FinalizeAndValidate(ParserContext context)
18-
{
19-
if (TryGetAvailability("cloud", out var version))
20-
{
21-
Deployment ??= new Deployment();
22-
Deployment.Cloud ??= new CloudManagedDeployment();
23-
Deployment.Cloud.Serverless = version;
24-
Deployment.Cloud.Hosted = version;
25-
}
26-
if (TryGetAvailability("self", out version))
27-
{
28-
Deployment ??= new Deployment();
29-
Deployment.SelfManaged ??= new SelfManagedDeployment();
30-
Deployment.SelfManaged.Ece = version;
31-
Deployment.SelfManaged.Eck = version;
32-
Deployment.SelfManaged.Stack = version;
33-
}
34-
35-
if (TryGetAvailability("stack", out version))
36-
{
37-
Deployment ??= new Deployment();
38-
Deployment.SelfManaged ??= new SelfManagedDeployment();
39-
Deployment.SelfManaged.Stack = version;
40-
}
41-
if (TryGetAvailability("ece", out version))
42-
{
43-
Deployment ??= new Deployment();
44-
Deployment.SelfManaged ??= new SelfManagedDeployment();
45-
Deployment.SelfManaged.Ece = version;
46-
}
47-
if (TryGetAvailability("eck", out version))
48-
{
49-
Deployment ??= new Deployment();
50-
Deployment.SelfManaged ??= new SelfManagedDeployment();
51-
Deployment.SelfManaged.Eck = version;
52-
}
53-
if (TryGetAvailability("hosted", out version))
54-
{
55-
Deployment ??= new Deployment();
56-
Deployment.Cloud ??= new CloudManagedDeployment();
57-
Deployment.Cloud.Hosted = version;
58-
}
59-
if (TryGetAvailability("serverless", out version))
60-
{
61-
Deployment ??= new Deployment();
62-
Deployment.Cloud ??= new CloudManagedDeployment();
63-
Deployment.Cloud.Serverless = version;
64-
}
65-
66-
if (Deployment is null)
67-
this.EmitError("{applies} block with no product availability specified");
68-
69-
var index = Parent?.IndexOf(this);
70-
if (Parent is not null && index > 0)
71-
{
72-
var i = index - 1 ?? 0;
73-
var prevSib = Parent[i];
74-
if (prevSib is not HeadingBlock)
75-
this.EmitError("{applies} should follow a heading");
76-
}
77-
78-
bool TryGetAvailability(string key, out ProductAvailability? semVersion)
79-
{
80-
semVersion = null;
81-
return Prop(key) is { } v && ProductAvailability.TryParse(v, out semVersion);
82-
}
83-
}
15+
public override void FinalizeAndValidate(ParserContext context) => this.EmitWarning("{applies} is deprecated, please use the {apply} directive");
8416
}

src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ protected override void Write(HtmlRenderer renderer, DirectiveBlock directiveBlo
3636
case MermaidBlock mermaidBlock:
3737
WriteMermaid(renderer, mermaidBlock);
3838
return;
39-
case AppliesBlock appliesBlock:
40-
WriteApplies(renderer, appliesBlock);
39+
case AppliesBlock: //deprecated scheduled for removal
4140
return;
4241
case FigureBlock imageBlock:
4342
WriteFigure(renderer, imageBlock);
@@ -189,15 +188,6 @@ private void WriteMermaid(HtmlRenderer renderer, MermaidBlock block)
189188
RenderRazorSliceRawContent(slice, renderer, block);
190189
}
191190

192-
private void WriteApplies(HtmlRenderer renderer, AppliesBlock block)
193-
{
194-
if (block.Deployment is null || block.Deployment == Deployment.All)
195-
return;
196-
197-
var slice = Applies.Create(block.Deployment);
198-
RenderRazorSliceNoContent(slice, renderer);
199-
}
200-
201191
private void WriteLiteralIncludeBlock(HtmlRenderer renderer, IncludeBlock block)
202192
{
203193
if (!block.Found || block.IncludePath is null)
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System.Collections;
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.Text;
8+
using Elastic.Markdown.Helpers;
9+
using YamlDotNet.Serialization;
10+
11+
namespace Elastic.Markdown.Myst.FrontMatter;
12+
13+
[YamlSerializable]
14+
public record ApplicabilityOverTime : IReadOnlyCollection<Applicability>
15+
{
16+
private readonly IReadOnlyCollection<Applicability> _items;
17+
public ApplicabilityOverTime(Applicability[] items) => _items = items;
18+
19+
// <lifecycle> [version]
20+
public static bool TryParse(string? value, out ApplicabilityOverTime? availability)
21+
{
22+
availability = null;
23+
if (string.IsNullOrWhiteSpace(value) || string.Equals(value.Trim(), "all", StringComparison.InvariantCultureIgnoreCase))
24+
{
25+
availability = GenerallyAvailable;
26+
return true;
27+
}
28+
29+
var items = value.Split(',');
30+
var applications = new List<Applicability>(items.Length);
31+
foreach (var item in items)
32+
{
33+
if (Applicability.TryParse(item.Trim(), out var a))
34+
applications.Add(a);
35+
}
36+
37+
if (applications.Count == 0)
38+
return false;
39+
40+
availability = new ApplicabilityOverTime(applications.ToArray());
41+
return true;
42+
}
43+
44+
public virtual bool Equals(ApplicabilityOverTime? other)
45+
{
46+
if ((object)this == other)
47+
return true;
48+
49+
if ((object?)other is null || EqualityContract != other.EqualityContract)
50+
return false;
51+
52+
var comparer = StructuralComparisons.StructuralEqualityComparer;
53+
return comparer.Equals(_items, other._items);
54+
}
55+
56+
public override int GetHashCode()
57+
{
58+
var comparer = StructuralComparisons.StructuralEqualityComparer;
59+
return (EqualityComparer<Type>.Default.GetHashCode(EqualityContract) * -1521134295)
60+
+ comparer.GetHashCode(_items);
61+
}
62+
63+
64+
public static explicit operator ApplicabilityOverTime(string b)
65+
{
66+
var productAvailability = TryParse(b, out var version) ? version : null;
67+
return productAvailability ?? throw new ArgumentException($"'{b}' is not a valid applicability string array.");
68+
}
69+
70+
public static ApplicabilityOverTime GenerallyAvailable { get; }
71+
= new([Applicability.GenerallyAvailable]);
72+
73+
public override string ToString()
74+
{
75+
if (this == GenerallyAvailable)
76+
return "all";
77+
var sb = new StringBuilder();
78+
foreach (var item in _items)
79+
sb.Append(item).Append(", ");
80+
return sb.ToString();
81+
}
82+
83+
public IEnumerator<Applicability> GetEnumerator() => _items.GetEnumerator();
84+
85+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
86+
87+
public int Count => _items.Count;
88+
}
89+
90+
[YamlSerializable]
91+
public record Applicability
92+
{
93+
public ProductLifecycle Lifecycle { get; init; }
94+
public SemVersion? Version { get; init; }
95+
96+
public static Applicability GenerallyAvailable { get; } = new()
97+
{
98+
Lifecycle = ProductLifecycle.GenerallyAvailable,
99+
Version = AllVersions.Instance
100+
};
101+
102+
public override string ToString()
103+
{
104+
if (this == GenerallyAvailable)
105+
return "all";
106+
var sb = new StringBuilder();
107+
var lifecycle = Lifecycle switch
108+
{
109+
ProductLifecycle.TechnicalPreview => "preview",
110+
ProductLifecycle.Beta => "beta",
111+
ProductLifecycle.Development => "dev",
112+
ProductLifecycle.Deprecated => "deprecated",
113+
ProductLifecycle.Coming => "coming",
114+
ProductLifecycle.Discontinued => "discontinued",
115+
ProductLifecycle.Unavailable => "unavailable",
116+
ProductLifecycle.GenerallyAvailable => "ga",
117+
_ => throw new ArgumentOutOfRangeException()
118+
};
119+
sb.Append(lifecycle);
120+
if (Version is not null && Version != AllVersions.Instance)
121+
sb.Append(" ").Append(Version);
122+
return sb.ToString();
123+
}
124+
125+
public static explicit operator Applicability(string b)
126+
{
127+
var productAvailability = TryParse(b, out var version) ? version : TryParse(b + ".0", out version) ? version : null;
128+
return productAvailability ?? throw new ArgumentException($"'{b}' is not a valid applicability string.");
129+
}
130+
131+
// <lifecycle> [version]
132+
public static bool TryParse(string? value, [NotNullWhen(true)] out Applicability? availability)
133+
{
134+
if (string.IsNullOrWhiteSpace(value) || string.Equals(value.Trim(), "all", StringComparison.InvariantCultureIgnoreCase))
135+
{
136+
availability = GenerallyAvailable;
137+
return true;
138+
}
139+
140+
var tokens = value.Split(" ", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
141+
if (tokens.Length < 1)
142+
{
143+
availability = null;
144+
return false;
145+
}
146+
var lifecycle = tokens[0].ToLowerInvariant() switch
147+
{
148+
"preview" => ProductLifecycle.TechnicalPreview,
149+
"tech-preview" => ProductLifecycle.TechnicalPreview,
150+
"beta" => ProductLifecycle.Beta,
151+
"dev" => ProductLifecycle.Development,
152+
"development" => ProductLifecycle.Development,
153+
"deprecated" => ProductLifecycle.Deprecated,
154+
"coming" => ProductLifecycle.Coming,
155+
"discontinued" => ProductLifecycle.Discontinued,
156+
"unavailable" => ProductLifecycle.Unavailable,
157+
"ga" => ProductLifecycle.GenerallyAvailable,
158+
_ => throw new ArgumentOutOfRangeException(nameof(tokens), tokens, $"Unknown product lifecycle: {tokens[0]}")
159+
};
160+
161+
var version = tokens.Length < 2 ? null : tokens[1] switch
162+
{
163+
null => AllVersions.Instance,
164+
"all" => AllVersions.Instance,
165+
"" => AllVersions.Instance,
166+
var t => SemVersionConverter.TryParse(t, out var v) ? v : null
167+
};
168+
availability = new Applicability { Version = version, Lifecycle = lifecycle };
169+
return true;
170+
}
171+
}

0 commit comments

Comments
 (0)