-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Imported Tingle.Extensions.Mustache (#230)
- Loading branch information
1 parent
f4100fc
commit 61fb3e9
Showing
40 changed files
with
2,640 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
[codespell] | ||
skip = .git,*/wwwroot,*.g.cs,countries-20200124.json,iso-639-3.tab,iso-4217.json,countries.json,currencies.json,languages.json | ||
# some modules, parts of regexes, and variable names to ignore | ||
ignore-words-list = aci | ||
ignore-words-list = aci,eachs,coppy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
src/Tingle.Extensions.Mustache/Contexts/BaseTraversalContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
using System.Text.RegularExpressions; | ||
|
||
namespace Tingle.Extensions.Mustache.Contexts; | ||
|
||
/// <param name="key">The key for access.</param> | ||
public abstract partial class BaseTraversalContext<T>(string key) : ITraversalContext where T : ITraversalContext | ||
{ | ||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="key">The key for access.</param> | ||
/// <param name="parent">The owning context.</param> | ||
public BaseTraversalContext(string key, T parent) : this(key) | ||
{ | ||
Parent = parent; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public string Key { get; } = key; | ||
|
||
/// <summary> | ||
/// The owning context. | ||
/// </summary> | ||
public T? Parent { get; } | ||
|
||
/// | ||
protected abstract T GetContextForPath(Queue<string> elements, bool ignoreCase); | ||
|
||
/// | ||
protected internal virtual T GetContextForPath(string path, bool ignoreCase) | ||
{ | ||
if (string.IsNullOrWhiteSpace(path)) | ||
{ | ||
throw new ArgumentException($"'{nameof(path)}' cannot be null or whitespace.", nameof(path)); | ||
} | ||
|
||
var elements = new Queue<string>(); | ||
var matches = GetPathFinderFormat().Matches(path).OfType<Match>().ToList(); | ||
foreach (var m in matches) | ||
{ | ||
elements.Enqueue(m.Value); | ||
} | ||
|
||
return GetContextForPath(elements, ignoreCase); | ||
} | ||
|
||
[GeneratedRegex("(\\.\\.[\\\\/]{1})|([^.]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline, "en-KE")] | ||
private static partial Regex GetPathFinderFormat(); | ||
} |
10 changes: 10 additions & 0 deletions
10
src/Tingle.Extensions.Mustache/Contexts/ITraversalContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace Tingle.Extensions.Mustache.Contexts; | ||
|
||
/// | ||
public interface ITraversalContext | ||
{ | ||
/// <summary> | ||
/// The key for access. | ||
/// </summary> | ||
string Key { get; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace Tingle.Extensions.Mustache.Contexts; | ||
|
||
/// <summary> | ||
/// Allows us to capture how each path is used in an inferred template. | ||
/// </summary> | ||
public enum InferredUsage | ||
{ | ||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member | ||
Scalar, | ||
ConditionalValue, | ||
Collection, | ||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member | ||
} |
95 changes: 95 additions & 0 deletions
95
src/Tingle.Extensions.Mustache/Contexts/InferredValuesContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
namespace Tingle.Extensions.Mustache.Contexts; | ||
|
||
/// | ||
public class InferredValuesContext : BaseTraversalContext<InferredValuesContext> | ||
{ | ||
/// | ||
public InferredValuesContext(string key) : base(key) { } | ||
|
||
/// | ||
public InferredValuesContext(string key, InferredValuesContext parent) : base(key, parent) { } | ||
|
||
/// <summary>Usages for this context.</summary> | ||
public ICollection<InferredUsage> Usages { get; } = new HashSet<InferredUsage>(); | ||
|
||
/// <summary>Children owned by this context.</summary> | ||
private Dictionary<string, InferredValuesContext> Children { get; } = []; | ||
|
||
/// <inheritdoc/> | ||
protected override InferredValuesContext GetContextForPath(Queue<string> elements, bool ignoreCase) | ||
{ | ||
ArgumentNullException.ThrowIfNull(elements); | ||
if (elements.Count == 0) return this; | ||
|
||
var element = elements.Dequeue(); | ||
if (element.StartsWith("..")) | ||
{ | ||
if (Parent is not null) | ||
{ | ||
return Parent.GetContextForPath(elements, ignoreCase); | ||
} | ||
else | ||
{ | ||
// calling "../" too much may be okay in that if we're at root, | ||
// we may just stop recursion and traverse down the path. | ||
return GetContextForPath(elements, ignoreCase); | ||
} | ||
} | ||
// TODO: handle array accessor and maybe "special" keys | ||
else | ||
{ | ||
// always return the context, even if the value is null | ||
if (!Children.TryGetValue(element, out var inner)) | ||
{ | ||
inner = new InferredValuesContext(key: element, parent: this); | ||
Children[element] = inner; | ||
} | ||
return inner.GetContextForPath(elements, ignoreCase); | ||
} | ||
} | ||
|
||
/// | ||
public InferredValuesContext GetInferredContextForPath(string path, InferredUsage accessType, bool ignoreCase) | ||
{ | ||
var context = GetContextForPath(path, ignoreCase); | ||
context.Usages.Add(accessType); | ||
return context; | ||
} | ||
|
||
/// <summary> | ||
/// Returns an <see cref="object"/> containing the current inferred model representation. | ||
/// </summary> | ||
/// <returns></returns> | ||
public object ToModel() | ||
{ | ||
object result; | ||
if (Usages.Count == 0) | ||
{ | ||
result = Children.ToDictionary(k => k.Key, v => v.Value.ToModel()); | ||
} | ||
else if (Usages.Contains(InferredUsage.Scalar) && Usages.Count == 1) | ||
{ | ||
result = Key + "_Value"; | ||
} | ||
else | ||
{ | ||
if (Usages.Contains(InferredUsage.Collection)) | ||
{ | ||
if (Children.Count != 0) | ||
{ | ||
result = new[] { Children.ToDictionary(k => k.Key, v => v.Value.ToModel()) }; | ||
} | ||
else | ||
{ | ||
result = Enumerable.Range(1, 3).Select(k => Key + "_" + k).ToArray(); | ||
} | ||
} | ||
else | ||
{ | ||
result = Children.ToDictionary(k => k.Key, v => v.Value.ToModel()); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
} |
99 changes: 99 additions & 0 deletions
99
src/Tingle.Extensions.Mustache/Contexts/ProvidedValuesContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
using System.Reflection; | ||
|
||
namespace Tingle.Extensions.Mustache.Contexts; | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public class ProvidedValuesContext : BaseTraversalContext<ProvidedValuesContext> | ||
{ | ||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="key">The key for access.</param> | ||
/// <param name="value">The value associated with this context.</param> | ||
public ProvidedValuesContext(string key, object value) : base(key) | ||
{ | ||
Value = value; | ||
} | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="key">The key for access.</param> | ||
/// <param name="value">The value associated with this context.</param> | ||
/// <param name="parent">The owning context.</param> | ||
public ProvidedValuesContext(string key, object value, ProvidedValuesContext parent) : base(key, parent) | ||
{ | ||
Value = value; | ||
} | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="key">The key for access.</param> | ||
/// <param name="parent">The owning context.</param> | ||
public ProvidedValuesContext(string key, ProvidedValuesContext parent) : base(key, parent) { } | ||
|
||
/// <summary> | ||
/// The value associated with this context. | ||
/// </summary> | ||
public object? Value { get; set; } | ||
|
||
/// <summary>Determines if the value of this context exists.</summary> | ||
public bool Exists() => Value is not null; | ||
|
||
/// <inheritdoc/> | ||
protected override ProvidedValuesContext GetContextForPath(Queue<string> elements, bool ignoreCase) | ||
{ | ||
ArgumentNullException.ThrowIfNull(elements); | ||
if (elements.Count == 0) return this; | ||
|
||
var element = elements.Dequeue(); | ||
if (element.StartsWith("..")) | ||
{ | ||
if (Parent is not null) | ||
{ | ||
return Parent.GetContextForPath(elements, ignoreCase); | ||
} | ||
else | ||
{ | ||
// calling "../" too much may be okay in that if we're at root, | ||
// we may just stop recursion and traverse down the path. | ||
return GetContextForPath(elements, ignoreCase); | ||
} | ||
} | ||
// TODO: handle array accessor and maybe "special" keys | ||
else | ||
{ | ||
// always return the context, even if the value is null | ||
ProvidedValuesContext? inner = null; | ||
if (Value is IDictionary<string, object> ctx) | ||
{ | ||
if (ignoreCase) | ||
{ | ||
ctx = new Dictionary<string, object>(ctx, StringComparer.OrdinalIgnoreCase); | ||
} | ||
|
||
ctx.TryGetValue(element, out var innerV); | ||
inner = new ProvidedValuesContext(key: element, value: innerV!, parent: this); | ||
} | ||
else if (Value is not null) | ||
{ | ||
var type = Value.GetType(); | ||
var flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy; | ||
if (ignoreCase) flags |= BindingFlags.IgnoreCase; | ||
var prop = type.GetProperty(element, flags); | ||
if (prop is not null) | ||
{ | ||
var innerV = prop.GetValue(Value); | ||
inner = new ProvidedValuesContext(key: element, value: innerV!, parent: this); | ||
} | ||
} | ||
|
||
//return inner ?? new ProvidedValuesContext(key: element, parent: this); | ||
inner ??= new ProvidedValuesContext(key: element, parent: this); | ||
return inner.GetContextForPath(elements, ignoreCase); | ||
} | ||
} | ||
} |
Oops, something went wrong.