-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathInterpolation.cs
86 lines (72 loc) · 2.42 KB
/
Interpolation.cs
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
// 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.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using Elastic.Markdown.Diagnostics;
using Elastic.Markdown.Myst;
namespace Elastic.Markdown.Helpers;
internal static partial class InterpolationRegex
{
[GeneratedRegex(@"\{\{[^\r\n}]+?\}\}", RegexOptions.IgnoreCase, "en-US")]
public static partial Regex MatchSubstitutions();
}
public static class Interpolation
{
public static string ReplaceSubstitutions(
this string input,
ParserContext context
)
{
var span = input.AsSpan();
return span.ReplaceSubstitutions([context.Substitutions, context.ContextSubstitutions], context.Build.Collector, out var replacement)
? replacement : input;
}
public static bool ReplaceSubstitutions(
this ReadOnlySpan<char> span,
IReadOnlyDictionary<string, string>? properties,
DiagnosticsCollector? collector,
[NotNullWhen(true)] out string? replacement
)
{
replacement = null;
return properties is not null && properties.Count != 0 &&
span.IndexOf("}}") >= 0 && span.ReplaceSubstitutions([properties], collector, out replacement);
}
private static bool ReplaceSubstitutions(
this ReadOnlySpan<char> span,
IReadOnlyDictionary<string, string>[] properties,
DiagnosticsCollector? collector,
[NotNullWhen(true)] out string? replacement
)
{
replacement = null;
if (span.IndexOf("}}") < 0)
return false;
if (properties.Length == 0 || properties.Sum(p => p.Count) == 0)
return false;
var lookups = properties
.Select(p => p as Dictionary<string, string> ?? new Dictionary<string, string>(p, StringComparer.OrdinalIgnoreCase))
.Select(d => d.GetAlternateLookup<ReadOnlySpan<char>>())
.ToArray();
var matchSubs = InterpolationRegex.MatchSubstitutions().EnumerateMatches(span);
var replaced = false;
foreach (var match in matchSubs)
{
if (match.Length == 0)
continue;
var spanMatch = span.Slice(match.Index, match.Length);
var key = spanMatch.Trim(['{', '}']);
foreach (var lookup in lookups)
{
if (!lookup.TryGetValue(key, out var value))
continue;
collector?.CollectUsedSubstitutionKey(key);
replacement ??= span.ToString();
replacement = replacement.Replace(spanMatch.ToString(), value);
replaced = true;
}
}
return replaced;
}
}