using System.ComponentModel; namespace Umbraco.Cms.Core; /// /// Represents a string-based entity identifier. /// [TypeConverter(typeof(UdiTypeConverter))] public class StringUdi : Udi { /// /// Initializes a new instance of the StringUdi class with an entity type and a string id. /// /// The entity type part of the udi. /// The string id part of the udi. public StringUdi(string entityType, string id) : base(entityType, Constants.Conventions.Udi.Prefix + entityType + "/" + EscapeUriString(id)) => Id = id; /// /// Initializes a new instance of the StringUdi class with a uri value. /// /// The uri value of the udi. public StringUdi(Uri uriValue) : base(uriValue) => Id = Uri.UnescapeDataString(uriValue.AbsolutePath.TrimStart(Constants.CharArrays.ForwardSlash)); /// /// The string part of the identifier. /// public string Id { get; } /// public override bool IsRoot => Id == string.Empty; public StringUdi EnsureClosed() { EnsureNotRoot(); return this; } private static string EscapeUriString(string s) => // Uri.EscapeUriString preserves / but also [ and ] which is bad // Uri.EscapeDataString does not preserve / which is bad // reserved = : / ? # [ ] @ ! $ & ' ( ) * + , ; = // unreserved = alpha digit - . _ ~ // we want to preserve the / and the unreserved // so... string.Join("/", s.Split(Constants.CharArrays.ForwardSlash).Select(Uri.EscapeDataString)); }