Compare commits

...

2 Commits

Author SHA1 Message Date
Tom Pipinic 43312c3362 AsUrlFriendly extension added
2 years ago
Tom Pipinic 3890d27d7f Property aggregation bug fix
2 years ago

@ -7,9 +7,9 @@ root = true
#### Core EditorConfig Options #### #### Core EditorConfig Options ####
# Indentation and spacing # Indentation and spacing
indent_size = 4 indent_size = 3
indent_style = tab indent_style = tab
tab_width = 4 tab_width = 3
# New line preferences # New line preferences
end_of_line = crlf end_of_line = crlf

@ -39,7 +39,7 @@ namespace Connected.Caching {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Caching.SR", typeof(SR).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Caching.SR", typeof(SR).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

@ -39,7 +39,7 @@ namespace Connected.Collections {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Collections.SR", typeof(SR).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Collections.SR", typeof(SR).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

@ -39,7 +39,7 @@ namespace Connected.Entities {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Entities.SR", typeof(SR).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Entities.SR", typeof(SR).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

@ -39,7 +39,7 @@ namespace Connected.Hosting {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Hosting.SR", typeof(SR).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Hosting.SR", typeof(SR).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

@ -1,5 +1,4 @@
using Connected.ServiceModel; using System.Collections;
using System.Collections;
using System.Reflection; using System.Reflection;
namespace Connected.Interop.Merging namespace Connected.Interop.Merging
@ -11,7 +10,7 @@ namespace Connected.Interop.Merging
if (destination is null || !HasSource(sources)) if (destination is null || !HasSource(sources))
return; return;
var sourceProperties = AggregateProperties(sources); var sourceProperties = PropertyAggregator.Aggregate(sources);
foreach (var property in Properties.GetImplementedProperties(destination)) foreach (var property in Properties.GetImplementedProperties(destination))
MergeProperty(destination, sourceProperties, property); MergeProperty(destination, sourceProperties, property);
@ -28,42 +27,6 @@ namespace Connected.Interop.Merging
return false; return false;
} }
private static Dictionary<string, object> AggregateProperties(params object[] sources)
{
var result = new Dictionary<string, object>();
for (var i = sources.Length - 1; i >= 0; i--)
{
var source = sources[i];
if (source is null)
continue;
var props = Properties.GetImplementedProperties(source);
foreach (var property in props)
{
if (result.ContainsKey(property.Name))
continue;
result.Add(property.Name, source);
}
if (source is IPropertyProvider provider)
{
foreach (var property in provider.Properties)
{
if (result.ContainsKey(property.Key))
continue;
result.Add(property.Key, property.Value);
}
}
}
return result;
}
private void MergeProperty(object destination, Dictionary<string, object> sourceProperties, PropertyInfo property) private void MergeProperty(object destination, Dictionary<string, object> sourceProperties, PropertyInfo property)
{ {
if (property.PropertyType.IsTypePrimitive()) if (property.PropertyType.IsTypePrimitive())
@ -74,7 +37,8 @@ namespace Connected.Interop.Merging
if (!sourceProperties.TryGetValue(property.Name, out object? source)) if (!sourceProperties.TryGetValue(property.Name, out object? source))
return; return;
property.SetValue(destination, source.GetType().GetProperty(property.Name).GetValue(source)); if (source.GetType() is Type propertyType && PropertyResolver.Resolve(propertyType, property.Name) is PropertyInfo propertyInfo)
property.SetValue(destination, propertyInfo.GetValue(source));
} }
else if (IsArray(property)) else if (IsArray(property))
MergeEnumerable(destination, sourceProperties, property); MergeEnumerable(destination, sourceProperties, property);

@ -0,0 +1,68 @@
using Connected.ServiceModel;
namespace Connected.Interop.Merging;
internal static class PropertyAggregator
{
public static Dictionary<string, object> Aggregate(params object[] values)
{
var result = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
for (var i = values.Length - 1; i >= 0; i--)
{
if (values[i] is not object value)
continue;
foreach (var property in GetImplementedProperties(value))
{
if (result.ContainsKey(property.Key))
continue;
result.Add(property.Key, property.Value);
}
if (value is IPropertyProvider provider)
{
foreach (var property in provider.Properties)
{
if (result.ContainsKey(property.Key))
continue;
result.Add(property.Key, property.Value);
}
}
}
return result;
}
private static Dictionary<string, object> GetImplementedProperties(object value)
{
if (value is null)
return new();
if (value is object[] objectArray)
{
var result = new Dictionary<string, object>();
for (var i = objectArray.Length - 1; i >= 0; i--)
{
var implementations = Properties.GetImplementedProperties(objectArray[i]);
foreach (var property in implementations)
result.Add(property.Name, objectArray[i]);
}
return result;
}
else
{
var implementations = Properties.GetImplementedProperties(value);
var result = new Dictionary<string, object>();
foreach (var property in implementations)
result.Add(property.Name, value);
return result;
}
}
}

@ -0,0 +1,19 @@
using System.Reflection;
namespace Connected.Interop.Merging;
internal static class PropertyResolver
{
public static PropertyInfo? Resolve(Type type, string propertyName)
{
if (type.GetProperty(propertyName) is PropertyInfo property)
return property;
if (type.GetProperty(propertyName.ToCamelCase()) is PropertyInfo camelProperty)
return camelProperty;
if (type.GetProperty(propertyName.ToPascalCase()) is PropertyInfo pascalProperty)
return pascalProperty;
return null;
}
}

@ -39,7 +39,7 @@ namespace Connected.Interop {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Interop.SR", typeof(SR).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Interop.SR", typeof(SR).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

@ -39,7 +39,7 @@ namespace Connected.Net {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Net.SR", typeof(SR).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Net.SR", typeof(SR).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

@ -39,7 +39,7 @@ namespace Connected.Security {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Security.SR", typeof(SR).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Security.SR", typeof(SR).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

@ -39,7 +39,7 @@ namespace Connected.Services {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Services.SR", typeof(SR).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Services.SR", typeof(SR).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

@ -51,4 +51,14 @@ public static class ServicesExtensions
return (f is not null && type.GetInterface(f) is not null) return (f is not null && type.GetInterface(f) is not null)
|| (nf is not null && type.GetInterface(nf) is not null); || (nf is not null && type.GetInterface(nf) is not null);
} }
public static string AsUrlFriendly(this string value)
{
return UrlGenerator.Generate(value);
}
public static string AsUrlFriendly(this string value, IEnumerable<string> existing)
{
return UrlGenerator.Generate(value, existing);
}
} }

@ -0,0 +1,112 @@
using System.Text;
namespace Connected.Services;
internal static class UrlGenerator
{
private const string ValidCharacters = "abcdefghijklmnopqrstuvzxyw-";
private const string MinusReplacements = "_ .\t\r\n";
static UrlGenerator()
{
Replacements = new(StringComparer.OrdinalIgnoreCase)
{
{"č", "c"},
{"š", "s"},
{"ž", "z"},
{"đ", "d"},
{"ć", "c"}
};
}
private static Dictionary<string, string> Replacements { get; }
public static string Generate(string text)
{
if (string.IsNullOrEmpty(text))
throw new NullReferenceException(nameof(text));
var result = new StringBuilder();
/*
* Analyze each character.
*/
foreach (var s in text.Trim())
{
/*
* If it's in a ValidCharacters collection that's fine, we just copy it
* into the result.
*/
if (ValidCharacters.Contains(s, StringComparison.OrdinalIgnoreCase))
{
result.Append(s);
continue;
}
/*
* Look if it's in the MinusReplacements collection which means we'll
* replace the character with the minus sign.
*/
if (MinusReplacements.Contains(s, StringComparison.OrdinalIgnoreCase))
{
result.Append('-');
continue;
}
/*
* Last chance for the character to be included in the result is to
* resolve the hardcoded character replacements.
*/
if (Replacements.TryGetValue(s.ToString(), out var replacement))
result.Append(replacement);
}
/*
* It's possible that no characters are included in the result. If that's
* the case we are going to include an a character just for the sake of
* being a valid string.
*/
if (result.Length == 0)
result.Append('a');
/*
* Remove any redundant minus characters and we are done.
*/
var sb = new StringBuilder();
var active = false;
for (var i = 0; i < result.Length; i++)
{
if (result[i] == '-')
{
if (active)
continue;
active = true;
sb.Append(result[i]);
}
else
{
active = false;
sb.Append(result[i]);
}
}
/*
* Remove trailing minus if exists.
*/
return sb.ToString().Trim().Trim('-').ToLowerInvariant();
}
public static string Generate(string text, IEnumerable<string> existing)
{
var prepared = Generate(text);
if (!existing.Any())
return prepared;
var idx = 0;
while (true)
{
var key = $"{prepared}-{idx}";
if (!existing.Contains(key, StringComparer.OrdinalIgnoreCase))
return key;
idx++;
}
}
}

@ -39,7 +39,7 @@ namespace Connected.Threading {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Threading.SR", typeof(SR).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Threading.SR", typeof(SR).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

Loading…
Cancel
Save