Files
Print_server/Inspectron.Epson.Templates/Interpreter/DataContext.cs
2026-01-21 15:56:37 +01:00

214 lines
6.6 KiB
C#

using System.Text.Json;
namespace Inspectron.Epson.Templates.Interpreter;
public class DataContext
{
private readonly JsonElement _root;
private readonly DataContext? _parent;
private readonly Dictionary<string, JsonElement> _localVariables = new();
private readonly Dictionary<string, object> _loopMetadata = new();
public DataContext(JsonElement root)
{
_root = root;
_parent = null;
}
private DataContext(JsonElement root, DataContext parent)
{
_root = root;
_parent = parent;
}
public DataContext CreateChildContext(string variableName, JsonElement value, int index, int count)
{
var child = new DataContext(_root, this);
child._localVariables[variableName] = value;
child._loopMetadata["_index"] = index;
child._loopMetadata["_number"] = index + 1;
child._loopMetadata["_first"] = index == 0;
child._loopMetadata["_last"] = index == count - 1;
child._loopMetadata["_count"] = count;
return child;
}
public JsonElement? Resolve(string path)
{
if (string.IsNullOrEmpty(path))
{
return _root;
}
// Check loop metadata first
if (_loopMetadata.TryGetValue(path, out var metadata))
{
return JsonSerializer.SerializeToElement(metadata);
}
var segments = path.Split('.');
var firstSegment = segments[0];
// Check local variables (loop variables)
if (_localVariables.TryGetValue(firstSegment, out var localValue))
{
return NavigatePath(localValue, segments.Skip(1).ToArray());
}
// Check parent context for local variables
if (_parent != null)
{
// First check if parent has this as a local variable
var parentResult = _parent.ResolveLocalOnly(firstSegment);
if (parentResult.HasValue)
{
return NavigatePath(parentResult.Value, segments.Skip(1).ToArray());
}
// Also check parent's loop metadata
if (_parent._loopMetadata.TryGetValue(path, out var parentMetadata))
{
return JsonSerializer.SerializeToElement(parentMetadata);
}
}
// Navigate from root
return NavigatePath(_root, segments);
}
private JsonElement? ResolveLocalOnly(string name)
{
if (_localVariables.TryGetValue(name, out var value))
{
return value;
}
return _parent?.ResolveLocalOnly(name);
}
private JsonElement? NavigatePath(JsonElement element, string[] segments)
{
var current = element;
foreach (var segment in segments)
{
if (current.ValueKind == JsonValueKind.Null || current.ValueKind == JsonValueKind.Undefined)
{
return null;
}
// Handle array access: collection.count or collection.length
if (segment.Equals("count", StringComparison.OrdinalIgnoreCase) ||
segment.Equals("length", StringComparison.OrdinalIgnoreCase))
{
if (current.ValueKind == JsonValueKind.Array)
{
return JsonSerializer.SerializeToElement(current.GetArrayLength());
}
}
// Handle array index: collection.0, collection.1
if (int.TryParse(segment, out var index))
{
if (current.ValueKind == JsonValueKind.Array && index >= 0 && index < current.GetArrayLength())
{
current = current[index];
continue;
}
return null;
}
// Handle object property
if (current.ValueKind == JsonValueKind.Object)
{
if (current.TryGetProperty(segment, out var property))
{
current = property;
}
else
{
// Try case-insensitive match
var found = false;
foreach (var prop in current.EnumerateObject())
{
if (prop.Name.Equals(segment, StringComparison.OrdinalIgnoreCase))
{
current = prop.Value;
found = true;
break;
}
}
if (!found) return null;
}
}
else
{
return null;
}
}
return current;
}
public IEnumerable<JsonElement> ResolveCollection(string path)
{
var element = Resolve(path);
if (element.HasValue && element.Value.ValueKind == JsonValueKind.Array)
{
foreach (var item in element.Value.EnumerateArray())
{
yield return item;
}
}
}
public string? GetString(string path)
{
var element = Resolve(path);
if (!element.HasValue) return null;
return element.Value.ValueKind switch
{
JsonValueKind.String => element.Value.GetString(),
JsonValueKind.Number => element.Value.GetRawText(),
JsonValueKind.True => "true",
JsonValueKind.False => "false",
JsonValueKind.Null => null,
_ => element.Value.GetRawText()
};
}
public bool IsTruthy(string path)
{
var element = Resolve(path);
if (!element.HasValue) return false;
return element.Value.ValueKind switch
{
JsonValueKind.Null or JsonValueKind.Undefined => false,
JsonValueKind.False => false,
JsonValueKind.True => true,
JsonValueKind.String => !string.IsNullOrEmpty(element.Value.GetString()),
JsonValueKind.Number => element.Value.GetDouble() != 0,
JsonValueKind.Array => element.Value.GetArrayLength() > 0,
JsonValueKind.Object => true,
_ => false
};
}
public object? GetValue(string path)
{
var element = Resolve(path);
if (!element.HasValue) return null;
return element.Value.ValueKind switch
{
JsonValueKind.String => element.Value.GetString(),
JsonValueKind.Number => element.Value.TryGetInt64(out var l) ? l : element.Value.GetDouble(),
JsonValueKind.True => true,
JsonValueKind.False => false,
JsonValueKind.Null => null,
_ => element.Value.GetRawText()
};
}
}