Created
November 16, 2023 21:29
-
-
Save SebastianStehle/039ef22e5e5042b45652649f761e1417 to your computer and use it in GitHub Desktop.
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
using Jint; | |
using Jint.Native; | |
using Jint.Runtime.Interop; | |
using System.Diagnostics.CodeAnalysis; | |
using System.Text.Json.Nodes; | |
using System.Collections; | |
using System.Runtime.CompilerServices; | |
using System; | |
using Squidex.Text; | |
namespace ConsoleApp3 | |
{ | |
internal class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var engine = new Engine(); | |
var metadata = new Dictionary<string, MyNumber>(); | |
var context = new MyContext | |
{ | |
Metadata = metadata | |
}; | |
engine.SetValue("context", context); | |
engine.Evaluate("context.metadata['abc'] = 42"); | |
} | |
} | |
} | |
class MyContext : ScriptVars | |
{ | |
public MyContext() | |
{ | |
} | |
public Dictionary<string, MyNumber> Metadata | |
{ | |
set | |
{ | |
SetInitial(new AssetMetadataWrapper(value)); | |
} | |
} | |
} | |
public class MyNumber | |
{ | |
public double Value { get; set; } | |
} | |
public sealed class AssetMetadataWrapper : IDictionary<string, object?> | |
{ | |
private readonly Dictionary<string, MyNumber> metadata; | |
public int Count | |
{ | |
get => metadata.Count; | |
} | |
public ICollection<string> Keys | |
{ | |
get => metadata.Keys; | |
} | |
public ICollection<object?> Values | |
{ | |
get => metadata.Values.Cast<object?>().ToList(); | |
} | |
public object? this[string key] | |
{ | |
get => metadata[key]; | |
set => metadata[key] = new MyNumber { Value = (double)value }; | |
} | |
public bool IsReadOnly | |
{ | |
get => false; | |
} | |
public AssetMetadataWrapper(Dictionary<string, MyNumber> metadata) | |
{ | |
this.metadata = metadata; | |
} | |
public bool TryGetValue(string key, [MaybeNullWhen(false)] out object? value) | |
{ | |
if (metadata.TryGetValue(key, out var temp)) | |
{ | |
value = temp; | |
return true; | |
} | |
else | |
{ | |
value = null; | |
return false; | |
} | |
} | |
public void Add(string key, object? value) | |
{ | |
metadata.Add(key, new MyNumber { Value = (int)value }); | |
} | |
public void Add(KeyValuePair<string, object?> item) | |
{ | |
Add(item.Key, item.Value); | |
} | |
public bool Remove(string key) | |
{ | |
return metadata.Remove(key); | |
} | |
public bool Remove(KeyValuePair<string, object?> item) | |
{ | |
return false; | |
} | |
public void Clear() | |
{ | |
metadata.Clear(); | |
} | |
public bool Contains(KeyValuePair<string, object?> item) | |
{ | |
return false; | |
} | |
public bool ContainsKey(string key) | |
{ | |
return metadata.ContainsKey(key); | |
} | |
public void CopyTo(KeyValuePair<string, object?>[] array, int arrayIndex) | |
{ | |
var i = arrayIndex; | |
foreach (var item in metadata) | |
{ | |
if (i >= array.Length) | |
{ | |
break; | |
} | |
array[i] = new KeyValuePair<string, object?>(item.Key, item.Value); | |
i++; | |
} | |
} | |
public IEnumerator<KeyValuePair<string, object?>> GetEnumerator() | |
{ | |
return metadata.Select(x => new KeyValuePair<string, object?>(x.Key, x.Value)).GetEnumerator(); | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
return ((IEnumerable)metadata).GetEnumerator(); | |
} | |
} | |
public class ScriptVars : IReadOnlyDictionary<string, object?> | |
{ | |
private readonly Dictionary<string, object?> values = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase); | |
private readonly HashSet<string> lockedKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase); | |
public IEnumerable<string> Keys | |
{ | |
get => values.Keys; | |
} | |
public IEnumerable<object?> Values | |
{ | |
get => values.Values; | |
} | |
public int Count | |
{ | |
get => values.Count; | |
} | |
public object? this[string key] | |
{ | |
get | |
{ | |
TryGetValue(key, out var result); | |
return result; | |
} | |
set | |
{ | |
Set(key, value); | |
} | |
} | |
public void CopyFrom(ScriptVars vars) | |
{ | |
foreach (var (key, item) in vars.values) | |
{ | |
if (!values.ContainsKey(key)) | |
{ | |
Set(key, item, vars.lockedKeys.Contains(key)); | |
} | |
} | |
} | |
public void Set(string? key, object? value, bool isReadonly = false) | |
{ | |
if (string.IsNullOrWhiteSpace(key)) | |
{ | |
return; | |
} | |
var finalKey = key.ToCamelCase(); | |
if (lockedKeys.Contains(finalKey)) | |
{ | |
return; | |
} | |
values[finalKey] = value; | |
if (isReadonly) | |
{ | |
lockedKeys.Add(finalKey); | |
} | |
else | |
{ | |
lockedKeys.Remove(finalKey); | |
} | |
} | |
public bool TryGetValue(string key, [MaybeNullWhen(false)] out object? value) | |
{ | |
values.TryGetValue(key, out value); | |
return true; | |
} | |
public bool TryGetValueIfExists<T>(string key, [MaybeNullWhen(false)] out T value) | |
{ | |
value = default!; | |
if (values.TryGetValue(key, out var item) && item is T typed) | |
{ | |
value = typed; | |
return true; | |
} | |
return false; | |
} | |
public ScriptVars SetInitial(object? value, [CallerMemberName] string? key = null) | |
{ | |
Set(key, value, true); | |
return this; | |
} | |
public T GetValue<T>([CallerMemberName] string? key = null) | |
{ | |
if (key != null && TryGetValue(key, out var temp) && temp is T result) | |
{ | |
return result; | |
} | |
return default!; | |
} | |
public bool ContainsKey(string key) | |
{ | |
return values.ContainsKey(key); | |
} | |
IEnumerator<KeyValuePair<string, object?>> IEnumerable<KeyValuePair<string, object?>>.GetEnumerator() | |
{ | |
return values.GetEnumerator(); | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
return values.GetEnumerator(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment