mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
3.3 KiB
113 lines
3.3 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using Squidex.Infrastructure.Collections;
|
|
|
|
namespace Squidex.Infrastructure.Queries
|
|
{
|
|
public sealed class PropertyPath : ReadonlyList<string>
|
|
{
|
|
private static readonly char[] Separators = { '.', '/' };
|
|
|
|
public PropertyPath(IList<string> items)
|
|
: base(items)
|
|
{
|
|
if (items.Count == 0)
|
|
{
|
|
ThrowHelper.ArgumentException("Path cannot be empty.", nameof(items));
|
|
}
|
|
}
|
|
|
|
public static implicit operator PropertyPath(string path)
|
|
{
|
|
var result = new List<string>();
|
|
|
|
var currentPath = path.AsSpan();
|
|
var currentPosition = 0;
|
|
|
|
void Add(ReadOnlySpan<char> value)
|
|
{
|
|
var property = value.Trim(Separators).ToString();
|
|
|
|
if (property.Length == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
property = property.Replace("\\/", "/", StringComparison.OrdinalIgnoreCase);
|
|
property = property.Replace("\\.", ".", StringComparison.OrdinalIgnoreCase);
|
|
|
|
result.Add(property);
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
var nextDot = currentPath[currentPosition..].IndexOfAny(Separators) + currentPosition;
|
|
|
|
if (nextDot < currentPosition)
|
|
{
|
|
Add(currentPath);
|
|
break;
|
|
}
|
|
else if (nextDot == currentPosition)
|
|
{
|
|
currentPath = currentPath[1..];
|
|
}
|
|
else if (currentPath[nextDot - 1] == '\\')
|
|
{
|
|
currentPosition = nextDot + 1;
|
|
}
|
|
else
|
|
{
|
|
Add(currentPath[..nextDot]);
|
|
|
|
currentPath = currentPath[nextDot..].Trim(Separators);
|
|
currentPosition = 0;
|
|
}
|
|
}
|
|
|
|
return Create(result);
|
|
}
|
|
|
|
public static implicit operator PropertyPath(string[] path)
|
|
{
|
|
return Create(path);
|
|
}
|
|
|
|
public static implicit operator PropertyPath(List<string> path)
|
|
{
|
|
return Create(path);
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return string.Join(".", this);
|
|
}
|
|
|
|
private static string Unescape(string source)
|
|
{
|
|
return source
|
|
.Replace("\\/", "/", StringComparison.OrdinalIgnoreCase)
|
|
.Replace("\\.", ".", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private static PropertyPath Create(IEnumerable<string>? source)
|
|
{
|
|
var inner = source?.ToList();
|
|
|
|
if (inner == null || inner.Count == 0)
|
|
{
|
|
ThrowHelper.ArgumentException("Path cannot be empty.", nameof(source));
|
|
return null!;
|
|
}
|
|
else
|
|
{
|
|
return new PropertyPath(inner);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|