Rasagar/Library/PackageCache/com.unity.package-validation-suite/Lib/PvpXray/Json.cs
2024-08-26 23:07:20 +03:00

137 lines
4.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using JsonObject = System.Collections.Generic.Dictionary<string, object>;
namespace PvpXray
{
public enum Undefined { Undefined }
public class Json
{
/// Object property name simple enough to use in Path unquoted.
static readonly Regex k_SimpleKey = new Regex("^[_a-zA-Z][_a-zA-Z0-9]*$");
readonly object m_Value;
readonly Json m_Parent;
// The key of this JSON value in the parent object, or the index (as
// a string) in the parent array, or null if this is the root value.
public string Key { get; }
string PackageFilePath { get; }
void BuildPath(StringBuilder sb)
{
if (m_Parent != null)
{
m_Parent.BuildPath(sb);
var isIndexOperation = m_Parent.IsArray || !k_SimpleKey.IsMatch(Key);
if (!isIndexOperation || sb.Length == 0)
{
sb.Append('.');
}
if (isIndexOperation)
{
sb.Append('[');
}
if (isIndexOperation && !m_Parent.IsArray) // complex object key
{
Encode(Key, sb);
}
else
{
sb.Append(Key);
}
if (isIndexOperation)
{
sb.Append(']');
}
}
}
static readonly Dictionary<Type, string> k_JsonTypeNames = new Dictionary<Type, string>()
{
[typeof(Undefined)] = "undefined",
[typeof(void)] = "null",
[typeof(bool)] = "boolean",
[typeof(string)] = "string",
[typeof(double)] = "number",
[typeof(JsonObject)] = "object",
[typeof(List<object>)] = "array",
};
Type Kind => m_Value == null ? typeof(void) : m_Value.GetType();
T CheckKind<T>()
{
if (Kind != typeof(T))
{
throw new SimpleJsonException($"{Path} was {k_JsonTypeNames[Kind]}, expected {k_JsonTypeNames[typeof(T)]}") { PackageFilePath = PackageFilePath };
}
return (T)m_Value;
}
Json(object value, Json parent, string key, string packageFilePath)
{
m_Value = value;
m_Parent = parent;
Key = key;
PackageFilePath = packageFilePath;
}
public Json(string json, string packageFilePath) : this(SimpleJsonReader.Read(json, packageFilePath), null, null, packageFilePath) { }
internal Json(object root, string packageFilePath) : this(root, null, null, packageFilePath) { }
internal SimpleJsonException GetException(string message)
=> new SimpleJsonException($"{Path}: {message}") { PackageFilePath = PackageFilePath };
// Enumerate elements of a JSON array.
public IEnumerable<Json> Elements
=> CheckKind<List<object>>().Select((elm, index) => new Json(elm, this, index.ToString(), PackageFilePath));
public IEnumerable<Json> ElementsIfPresent
=> IfPresent?.Elements ?? Enumerable.Empty<Json>();
// Enumerate members of a JSON object.
public IEnumerable<Json> Members
=> RawObject.Select(kv => new Json(kv.Value, this, kv.Key, PackageFilePath));
public IEnumerable<Json> MembersIfPresent
=> IfPresent?.Members ?? Enumerable.Empty<Json>();
public Json IfPresent => IsPresent ? this : null;
public bool IsArray => Kind == typeof(List<object>);
public bool IsBoolean => Kind == typeof(bool);
public bool IsNumber => Kind == typeof(double);
public bool IsObject => Kind == typeof(JsonObject);
public bool IsPresent => !(m_Value is Undefined);
public bool IsString => Kind == typeof(string);
/// Returns the "location" of this element in the document as a jq-style path.
public string Path
{
get
{
var sb = new StringBuilder();
BuildPath(sb);
return sb.Length == 0 ? "." : sb.ToString();
}
}
public JsonObject RawObject => CheckKind<JsonObject>();
public bool Boolean => CheckKind<bool>();
public string String => CheckKind<string>();
public double Number => CheckKind<double>();
public Json this[string key] => new Json(RawObject.TryGetValue(key, out var result) ? result : Undefined.Undefined, this, key, PackageFilePath);
internal static void Encode(string str, StringBuilder sb) => Yaml.Encode(str, sb);
}
}