Browse Source

Word count V2 (#566)

pull/567/head
Sebastian Stehle 5 years ago
committed by GitHub
parent
commit
981a6c17c2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      backend/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs
  2. 1
      backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmSchemaExtensions.cs
  3. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmTypeVisitor.cs
  4. 1
      backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonSchemaExtensions.cs
  5. 1
      backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs
  6. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleRegistry.cs
  7. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ExecutionContext.cs
  8. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs
  9. 5
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringWordsJintExtension.cs
  10. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/StringFluidExtension.cs
  11. 5
      backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/StringWordsFluidExtension.cs
  12. 40
      backend/src/Squidex.Domain.Apps.Core.Operations/TextHelpers.cs
  13. 2
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/Visitors/FirstPascalPathExtension.cs
  14. 1
      backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardApp.cs
  15. 1
      backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs
  16. 2
      backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs
  17. 2
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetSlug.cs
  18. 1
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryParser.cs
  19. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/ContentChangedTriggerHandler.cs
  20. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Extensions.cs
  21. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs
  22. 1
      backend/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchema.cs
  23. 1
      backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs
  24. 1
      backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs
  25. 1
      backend/src/Squidex.Infrastructure/Configuration/ConfigurationExtensions.cs
  26. 1
      backend/src/Squidex.Infrastructure/Guard.cs
  27. 1
      backend/src/Squidex.Infrastructure/Log/Adapter/SemanticLogLogger.cs
  28. 1
      backend/src/Squidex.Infrastructure/Queries/PascalCasePathConverter.cs
  29. 1
      backend/src/Squidex.Infrastructure/Reflection/TypeNameBuilder.cs
  30. 1
      backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj
  31. 738
      backend/src/Squidex.Infrastructure/StringExtensions.cs
  32. 1
      backend/src/Squidex.Infrastructure/Translations/LocalizedCompareAttribute.cs
  33. 1
      backend/src/Squidex.Infrastructure/Translations/LocalizedRequired.cs
  34. 1
      backend/src/Squidex.Infrastructure/Validation/AbsoluteUrlAttribute.cs
  35. 1
      backend/src/Squidex.Infrastructure/Validation/Not.cs
  36. 1
      backend/src/Squidex.Web/Services/StringLocalizer.cs
  37. 93
      backend/tests/Squidex.Infrastructure.Tests/StringExtensionsTests.cs

1
backend/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs

@ -9,6 +9,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Text;
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
{ {

1
backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmSchemaExtensions.cs

@ -8,6 +8,7 @@
using Microsoft.OData.Edm; using Microsoft.OData.Edm;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Text;
namespace Squidex.Domain.Apps.Core.GenerateEdmSchema namespace Squidex.Domain.Apps.Core.GenerateEdmSchema
{ {

2
backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmTypeVisitor.cs

@ -7,7 +7,7 @@
using Microsoft.OData.Edm; using Microsoft.OData.Edm;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Text;
namespace Squidex.Domain.Apps.Core.GenerateEdmSchema namespace Squidex.Domain.Apps.Core.GenerateEdmSchema
{ {

1
backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonSchemaExtensions.cs

@ -8,6 +8,7 @@
using NJsonSchema; using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Text;
namespace Squidex.Domain.Apps.Core.GenerateJsonSchema namespace Squidex.Domain.Apps.Core.GenerateJsonSchema
{ {

1
backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs

@ -18,6 +18,7 @@ using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Core.Templates; using Squidex.Domain.Apps.Core.Templates;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json;
using Squidex.Text;
using ValueTaskSupplement; using ValueTaskSupplement;
namespace Squidex.Domain.Apps.Core.HandleRules namespace Squidex.Domain.Apps.Core.HandleRules

2
backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleRegistry.cs

@ -12,8 +12,8 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Text;
#pragma warning disable RECS0033 // Convert 'if' to '||' expression #pragma warning disable RECS0033 // Convert 'if' to '||' expression

2
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ExecutionContext.cs

@ -11,7 +11,7 @@ using System.Threading;
using Jint; using Jint;
using Jint.Native; using Jint.Native;
using Jint.Native.Object; using Jint.Native.Object;
using Squidex.Infrastructure; using Squidex.Text;
namespace Squidex.Domain.Apps.Core.Scripting namespace Squidex.Domain.Apps.Core.Scripting
{ {

2
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs

@ -8,7 +8,7 @@
using System; using System;
using Jint; using Jint;
using Jint.Native; using Jint.Native;
using Squidex.Infrastructure; using Squidex.Text;
namespace Squidex.Domain.Apps.Core.Scripting.Extensions namespace Squidex.Domain.Apps.Core.Scripting.Extensions
{ {

5
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringWordsJintExtension.cs

@ -8,6 +8,7 @@
using System; using System;
using Jint; using Jint;
using Jint.Native; using Jint.Native;
using Squidex.Text;
namespace Squidex.Domain.Apps.Core.Scripting.Extensions namespace Squidex.Domain.Apps.Core.Scripting.Extensions
{ {
@ -17,7 +18,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions
{ {
try try
{ {
return TextHelpers.WordCount(text); return text.WordCount();
} }
catch catch
{ {
@ -29,7 +30,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions
{ {
try try
{ {
return TextHelpers.CharacterCount(text); return text.CharacterCount();
} }
catch catch
{ {

2
backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/StringFluidExtension.cs

@ -8,7 +8,7 @@
using Fluid; using Fluid;
using Fluid.Values; using Fluid.Values;
using Newtonsoft.Json; using Newtonsoft.Json;
using Squidex.Infrastructure; using Squidex.Text;
namespace Squidex.Domain.Apps.Core.Templates.Extensions namespace Squidex.Domain.Apps.Core.Templates.Extensions
{ {

5
backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/StringWordsFluidExtension.cs

@ -7,6 +7,7 @@
using Fluid; using Fluid;
using Fluid.Values; using Fluid.Values;
using Squidex.Text;
namespace Squidex.Domain.Apps.Core.Templates.Extensions namespace Squidex.Domain.Apps.Core.Templates.Extensions
{ {
@ -14,12 +15,12 @@ namespace Squidex.Domain.Apps.Core.Templates.Extensions
{ {
private static readonly FilterDelegate WordCount = (input, arguments, context) => private static readonly FilterDelegate WordCount = (input, arguments, context) =>
{ {
return FluidValue.Create(TextHelpers.WordCount(input.ToStringValue())); return FluidValue.Create(input.ToStringValue().WordCount());
}; };
private static readonly FilterDelegate CharacterCount = (input, arguments, context) => private static readonly FilterDelegate CharacterCount = (input, arguments, context) =>
{ {
return FluidValue.Create(TextHelpers.CharacterCount(input.ToStringValue())); return FluidValue.Create(input.ToStringValue().CharacterCount());
}; };
public void RegisterGlobalTypes(IMemberAccessStrategy memberAccessStrategy) public void RegisterGlobalTypes(IMemberAccessStrategy memberAccessStrategy)

40
backend/src/Squidex.Domain.Apps.Core.Operations/TextHelpers.cs

@ -93,45 +93,5 @@ namespace Squidex.Domain.Apps.Core
WriteTextTo(child, sb); WriteTextTo(child, sb);
} }
} }
public static int CharacterCount(string text)
{
var characterCount = 0;
for (int i = 0; i < text.Length; i++)
{
if (char.IsLetter(text[i]))
{
characterCount++;
}
}
return characterCount;
}
public static int WordCount(string text)
{
var numWords = 0;
for (int i = 1; i < text.Length; i++)
{
if (char.IsWhiteSpace(text[i - 1]))
{
var character = text[i];
if (char.IsLetterOrDigit(character) || char.IsPunctuation(character))
{
numWords++;
}
}
}
if (text.Length > 2)
{
numWords++;
}
return numWords;
}
} }
} }

2
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/Visitors/FirstPascalPathExtension.cs

@ -6,8 +6,8 @@
// ========================================================================== // ==========================================================================
using System.Linq; using System.Linq;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.Queries;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors
{ {

1
backend/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardApp.cs

@ -11,6 +11,7 @@ using Squidex.Domain.Apps.Entities.Apps.Plans;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Apps.Guards namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {

1
backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs

@ -20,6 +20,7 @@ using Squidex.Infrastructure.Security;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Apps.Indexes namespace Squidex.Domain.Apps.Entities.Apps.Indexes
{ {

2
backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs

@ -9,7 +9,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Domain.Apps.Entities.Schemas.Commands;
using Squidex.Infrastructure; using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders
{ {

2
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetSlug.cs

@ -6,7 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using Squidex.Infrastructure; using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Assets namespace Squidex.Domain.Apps.Entities.Assets
{ {

1
backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryParser.cs

@ -21,6 +21,7 @@ using Squidex.Infrastructure.Queries.Json;
using Squidex.Infrastructure.Queries.OData; using Squidex.Infrastructure.Queries.OData;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Assets.Queries namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {

1
backend/src/Squidex.Domain.Apps.Entities/Contents/ContentChangedTriggerHandler.cs

@ -16,6 +16,7 @@ using Squidex.Domain.Apps.Events.Contents;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Contents namespace Squidex.Domain.Apps.Entities.Contents
{ {

1
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Extensions.cs

@ -11,6 +11,7 @@ using System.Threading.Tasks;
using GraphQL.DataLoader; using GraphQL.DataLoader;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {

1
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs

@ -29,6 +29,7 @@ using Squidex.Infrastructure.Queries.Json;
using Squidex.Infrastructure.Queries.OData; using Squidex.Infrastructure.Queries.OData;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Contents.Queries namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {

1
backend/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchema.cs

@ -14,6 +14,7 @@ using Squidex.Domain.Apps.Entities.Schemas.Commands;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Text;
#pragma warning disable IDE0060 // Remove unused parameter #pragma warning disable IDE0060 // Remove unused parameter
#pragma warning disable IDE0059 // Unnecessary assignment of a value #pragma warning disable IDE0059 // Unnecessary assignment of a value

1
backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs

@ -17,6 +17,7 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Schemas.Indexes namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
{ {

1
backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs

@ -14,6 +14,7 @@ using System.Threading.Tasks;
using EventStore.ClientAPI; using EventStore.ClientAPI;
using EventStore.ClientAPI.Exceptions; using EventStore.ClientAPI.Exceptions;
using EventStore.ClientAPI.Projections; using EventStore.ClientAPI.Projections;
using Squidex.Text;
namespace Squidex.Infrastructure.EventSourcing namespace Squidex.Infrastructure.EventSourcing
{ {

1
backend/src/Squidex.Infrastructure/Configuration/ConfigurationExtensions.cs

@ -8,6 +8,7 @@
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Text;
namespace Microsoft.Extensions.Configuration namespace Microsoft.Extensions.Configuration
{ {

1
backend/src/Squidex.Infrastructure/Guard.cs

@ -12,6 +12,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Text;
namespace Squidex.Infrastructure namespace Squidex.Infrastructure
{ {

1
backend/src/Squidex.Infrastructure/Log/Adapter/SemanticLogLogger.cs

@ -8,6 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Squidex.Text;
namespace Squidex.Infrastructure.Log.Adapter namespace Squidex.Infrastructure.Log.Adapter
{ {

1
backend/src/Squidex.Infrastructure/Queries/PascalCasePathConverter.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Linq; using System.Linq;
using Squidex.Text;
namespace Squidex.Infrastructure.Queries namespace Squidex.Infrastructure.Queries
{ {

1
backend/src/Squidex.Infrastructure/Reflection/TypeNameBuilder.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System; using System;
using Squidex.Text;
namespace Squidex.Infrastructure.Reflection namespace Squidex.Infrastructure.Reflection
{ {

1
backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj

@ -37,6 +37,7 @@
<PackageReference Include="NodaTime" Version="3.0.0" /> <PackageReference Include="NodaTime" Version="3.0.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-rc0003" /> <PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-rc0003" />
<PackageReference Include="Squidex.Text" Version="1.1.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="1.7.1" /> <PackageReference Include="System.Collections.Immutable" Version="1.7.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />

738
backend/src/Squidex.Infrastructure/StringExtensions.cs

@ -6,532 +6,17 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace Squidex.Infrastructure namespace Squidex.Infrastructure
{ {
public static class StringExtensions public static class StringExtensions
{ {
private const char NullChar = (char)0;
private static readonly Regex SlugRegex = new Regex("^[a-z0-9]+(\\-[a-z0-9]+)*$", RegexOptions.Compiled);
private static readonly Regex EmailRegex = new Regex(@"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-||_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+([a-z]+|\d|-|\.{0,1}|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])?([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex EmailRegex = new Regex(@"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-||_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+([a-z]+|\d|-|\.{0,1}|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])?([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex PropertyNameRegex = new Regex("^[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*$", RegexOptions.Compiled); private static readonly Regex PropertyNameRegex = new Regex("^[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*$", RegexOptions.Compiled);
private static readonly Dictionary<char, string> LowerCaseDiacritics;
private static readonly Dictionary<char, string> Diacritics = new Dictionary<char, string>
{
['$'] = "dollar",
['%'] = "percent",
['&'] = "and",
['<'] = "less",
['>'] = "greater",
['|'] = "or",
['¢'] = "cent",
['£'] = "pound",
['¤'] = "currency",
['¥'] = "yen",
['©'] = "(c)",
['ª'] = "a",
['®'] = "(r)",
['º'] = "o",
['À'] = "A",
['Á'] = "A",
['Â'] = "A",
['Ã'] = "A",
['Ä'] = "AE",
['Å'] = "A",
['Æ'] = "AE",
['Ç'] = "C",
['Ə'] = "E",
['È'] = "E",
['É'] = "E",
['Ê'] = "E",
['Ë'] = "E",
['Ì'] = "I",
['Í'] = "I",
['Î'] = "I",
['Ï'] = "I",
['Ð'] = "D",
['Ñ'] = "N",
['Ò'] = "O",
['Ó'] = "O",
['Ô'] = "O",
['Õ'] = "O",
['Ö'] = "OE",
['Ø'] = "O",
['Ù'] = "U",
['Ú'] = "U",
['Û'] = "U",
['Ü'] = "UE",
['Ý'] = "Y",
['Þ'] = "TH",
['ß'] = "ss",
['à'] = "a",
['á'] = "a",
['â'] = "a",
['ã'] = "a",
['ä'] = "ae",
['å'] = "a",
['æ'] = "ae",
['ç'] = "c",
['ə'] = "e",
['è'] = "e",
['é'] = "e",
['ê'] = "e",
['ë'] = "e",
['ì'] = "i",
['í'] = "i",
['î'] = "i",
['ï'] = "i",
['ð'] = "d",
['ñ'] = "n",
['ò'] = "o",
['ó'] = "o",
['ô'] = "o",
['õ'] = "o",
['ö'] = "oe",
['ø'] = "o",
['ù'] = "u",
['ú'] = "u",
['û'] = "u",
['ü'] = "ue",
['ý'] = "y",
['þ'] = "th",
['ÿ'] = "y",
['Ā'] = "A",
['ā'] = "a",
['Ă'] = "A",
['ă'] = "a",
['Ą'] = "A",
['ą'] = "a",
['Ć'] = "C",
['ć'] = "c",
['Č'] = "C",
['č'] = "c",
['Ď'] = "D",
['ď'] = "d",
['Đ'] = "DJ",
['đ'] = "dj",
['Ē'] = "E",
['ē'] = "e",
['Ė'] = "E",
['ė'] = "e",
['Ę'] = "e",
['ę'] = "e",
['Ě'] = "E",
['ě'] = "e",
['Ğ'] = "G",
['ğ'] = "g",
['Ģ'] = "G",
['ģ'] = "g",
['Ĩ'] = "I",
['ĩ'] = "i",
['Ī'] = "i",
['ī'] = "i",
['Į'] = "I",
['į'] = "i",
['İ'] = "I",
['ı'] = "i",
['Ķ'] = "k",
['ķ'] = "k",
['Ļ'] = "L",
['ļ'] = "l",
['Ľ'] = "L",
['ľ'] = "l",
['Ł'] = "L",
['ł'] = "l",
['Ń'] = "N",
['ń'] = "n",
['Ņ'] = "N",
['ņ'] = "n",
['Ň'] = "N",
['ň'] = "n",
['Ő'] = "O",
['ő'] = "o",
['Œ'] = "OE",
['œ'] = "oe",
['Ŕ'] = "R",
['ŕ'] = "r",
['Ř'] = "R",
['ř'] = "r",
['Ś'] = "S",
['ś'] = "s",
['Ş'] = "S",
['ş'] = "s",
['Š'] = "S",
['š'] = "s",
['Ţ'] = "T",
['ţ'] = "t",
['Ť'] = "T",
['ť'] = "t",
['Ũ'] = "U",
['ũ'] = "u",
['Ū'] = "u",
['ū'] = "u",
['Ů'] = "U",
['ů'] = "u",
['Ű'] = "U",
['ű'] = "u",
['Ų'] = "U",
['ų'] = "u",
['Ź'] = "Z",
['ź'] = "z",
['Ż'] = "Z",
['ż'] = "z",
['Ž'] = "Z",
['ž'] = "z",
['ƒ'] = "f",
['Ơ'] = "O",
['ơ'] = "o",
['Ư'] = "U",
['ư'] = "u",
['Lj'] = "LJ",
['lj'] = "lj",
['Nj'] = "NJ",
['nj'] = "nj",
['Ș'] = "S",
['ș'] = "s",
['Ț'] = "T",
['ț'] = "t",
['˚'] = "o",
['Ά'] = "A",
['Έ'] = "E",
['Ή'] = "H",
['Ί'] = "I",
['Ό'] = "O",
['Ύ'] = "Y",
['Ώ'] = "W",
['ΐ'] = "i",
['Α'] = "A",
['Β'] = "B",
['Γ'] = "G",
['Δ'] = "D",
['Ε'] = "E",
['Ζ'] = "Z",
['Η'] = "H",
['Θ'] = "8",
['Ι'] = "I",
['Κ'] = "K",
['Λ'] = "L",
['Μ'] = "M",
['Ν'] = "N",
['Ξ'] = "3",
['Ο'] = "O",
['Π'] = "P",
['Ρ'] = "R",
['Σ'] = "S",
['Τ'] = "T",
['Υ'] = "Y",
['Φ'] = "F",
['Χ'] = "X",
['Ψ'] = "PS",
['Ω'] = "W",
['Ϊ'] = "I",
['Ϋ'] = "Y",
['ά'] = "a",
['έ'] = "e",
['ή'] = "h",
['ί'] = "i",
['ΰ'] = "y",
['α'] = "a",
['β'] = "b",
['γ'] = "g",
['δ'] = "d",
['ε'] = "e",
['ζ'] = "z",
['η'] = "h",
['θ'] = "8",
['ι'] = "i",
['κ'] = "k",
['λ'] = "l",
['μ'] = "m",
['ν'] = "n",
['ξ'] = "3",
['ο'] = "o",
['π'] = "p",
['ρ'] = "r",
['ς'] = "s",
['σ'] = "s",
['τ'] = "t",
['υ'] = "y",
['φ'] = "f",
['χ'] = "x",
['ψ'] = "ps",
['ω'] = "w",
['ϊ'] = "i",
['ϋ'] = "y",
['ό'] = "o",
['ύ'] = "y",
['ώ'] = "w",
['Ё'] = "Yo",
['Ђ'] = "DJ",
['Є'] = "Ye",
['І'] = "I",
['Ї'] = "Yi",
['Ј'] = "J",
['Љ'] = "LJ",
['Њ'] = "NJ",
['Ћ'] = "C",
['Џ'] = "DZ",
['А'] = "A",
['Б'] = "B",
['В'] = "V",
['Г'] = "G",
['Д'] = "D",
['Е'] = "E",
['Ж'] = "Zh",
['З'] = "Z",
['И'] = "I",
['Й'] = "J",
['К'] = "K",
['Л'] = "L",
['М'] = "M",
['Н'] = "N",
['О'] = "O",
['П'] = "P",
['Р'] = "R",
['С'] = "S",
['Т'] = "T",
['У'] = "U",
['Ф'] = "F",
['Х'] = "H",
['Ц'] = "C",
['Ч'] = "Ch",
['Ш'] = "Sh",
['Щ'] = "Sh",
['Ъ'] = "U",
['Ы'] = "Y",
['Ь'] = "b",
['Э'] = "E",
['Ю'] = "Yu",
['Я'] = "Ya",
['а'] = "a",
['б'] = "b",
['в'] = "v",
['г'] = "g",
['д'] = "d",
['е'] = "e",
['ж'] = "zh",
['з'] = "z",
['и'] = "i",
['й'] = "j",
['к'] = "k",
['л'] = "l",
['м'] = "m",
['н'] = "n",
['о'] = "o",
['п'] = "p",
['р'] = "r",
['с'] = "s",
['т'] = "t",
['у'] = "u",
['ф'] = "f",
['х'] = "h",
['ц'] = "c",
['ч'] = "ch",
['ш'] = "sh",
['щ'] = "sh",
['ъ'] = "u",
['ы'] = "y",
['ь'] = "s",
['э'] = "e",
['ю'] = "yu",
['я'] = "ya",
['ё'] = "yo",
['ђ'] = "dj",
['є'] = "ye",
['і'] = "i",
['ї'] = "yi",
['ј'] = "j",
['љ'] = "lj",
['њ'] = "nj",
['ћ'] = "c",
['џ'] = "dz",
['Ґ'] = "G",
['ґ'] = "g",
['฿'] = "baht",
['ა'] = "a",
['ბ'] = "b",
['გ'] = "g",
['დ'] = "d",
['ე'] = "e",
['ვ'] = "v",
['ზ'] = "z",
['თ'] = "t",
['ი'] = "i",
['კ'] = "k",
['ლ'] = "l",
['მ'] = "m",
['ნ'] = "n",
['ო'] = "o",
['პ'] = "p",
['ჟ'] = "zh",
['რ'] = "r",
['ს'] = "s",
['ტ'] = "t",
['უ'] = "u",
['ფ'] = "f",
['ქ'] = "k",
['ღ'] = "gh",
['ყ'] = "q",
['შ'] = "sh",
['ჩ'] = "ch",
['ც'] = "ts",
['ძ'] = "dz",
['წ'] = "ts",
['ჭ'] = "ch",
['ხ'] = "kh",
['ჯ'] = "j",
['ჰ'] = "h",
['ẞ'] = "SS",
['Ạ'] = "A",
['ạ'] = "a",
['Ả'] = "A",
['ả'] = "a",
['Ấ'] = "A",
['ấ'] = "a",
['Ầ'] = "A",
['ầ'] = "a",
['Ẩ'] = "A",
['ẩ'] = "a",
['Ẫ'] = "A",
['ẫ'] = "a",
['Ậ'] = "A",
['ậ'] = "a",
['Ắ'] = "A",
['ắ'] = "a",
['Ằ'] = "A",
['ằ'] = "a",
['Ẳ'] = "A",
['ẳ'] = "a",
['Ẵ'] = "A",
['ẵ'] = "a",
['Ặ'] = "A",
['ặ'] = "a",
['Ẹ'] = "E",
['ẹ'] = "e",
['Ẻ'] = "E",
['ẻ'] = "e",
['Ẽ'] = "E",
['ẽ'] = "e",
['Ế'] = "E",
['ế'] = "e",
['Ề'] = "E",
['ề'] = "e",
['Ể'] = "E",
['ể'] = "e",
['Ễ'] = "E",
['ễ'] = "e",
['Ệ'] = "E",
['ệ'] = "e",
['Ỉ'] = "I",
['ỉ'] = "i",
['Ị'] = "I",
['ị'] = "i",
['Ọ'] = "O",
['ọ'] = "o",
['Ỏ'] = "O",
['ỏ'] = "o",
['Ố'] = "O",
['ố'] = "o",
['Ồ'] = "O",
['ồ'] = "o",
['Ổ'] = "O",
['ổ'] = "o",
['Ỗ'] = "O",
['ỗ'] = "o",
['Ộ'] = "O",
['ộ'] = "o",
['Ớ'] = "O",
['ớ'] = "o",
['Ờ'] = "O",
['ờ'] = "o",
['Ở'] = "O",
['ở'] = "o",
['Ỡ'] = "O",
['ỡ'] = "o",
['Ợ'] = "O",
['ợ'] = "o",
['Ụ'] = "U",
['ụ'] = "u",
['Ủ'] = "U",
['ủ'] = "u",
['Ứ'] = "U",
['ứ'] = "u",
['Ừ'] = "U",
['ừ'] = "u",
['Ử'] = "U",
['ử'] = "u",
['Ữ'] = "U",
['ữ'] = "u",
['Ự'] = "U",
['ự'] = "u",
['Ỳ'] = "Y",
['ỳ'] = "y",
['Ỵ'] = "Y",
['ỵ'] = "y",
['Ỷ'] = "Y",
['ỷ'] = "y",
['Ỹ'] = "Y",
['ỹ'] = "y",
['‘'] = "\'",
['’'] = "\'",
['“'] = "\\\"",
['”'] = "\\\"",
['†'] = "+",
['•'] = "*",
['…'] = "...",
['₠'] = "ecu",
['₢'] = "cruzeiro",
['₣'] = "french franc",
['₤'] = "lira",
['₥'] = "mill",
['₦'] = "naira",
['₧'] = "peseta",
['₨'] = "rupee",
['₩'] = "won",
['₪'] = "new shequel",
['₫'] = "dong",
['€'] = "euro",
['₭'] = "kip",
['₮'] = "tugrik",
['₯'] = "drachma",
['₰'] = "penny",
['₱'] = "peso",
['₲'] = "guarani",
['₳'] = "austral",
['₴'] = "hryvnia",
['₵'] = "cedi",
['₹'] = "indian rupee",
['₽'] = "russian ruble",
['₿'] = "bitcoin",
['℠'] = "sm",
['™'] = "tm",
['∂'] = "d",
['∆'] = "delta",
['∑'] = "sum",
['∞'] = "infinity",
['♥'] = "love",
['元'] = "yuan",
['円'] = "yen",
['﷼'] = "rial"
};
static StringExtensions()
{
LowerCaseDiacritics = Diacritics.ToDictionary(x => x.Key, x => x.Value.ToLowerInvariant());
}
public static bool IsSlug(this string? value)
{
return value != null && SlugRegex.IsMatch(value);
}
public static bool IsEmail(this string? value) public static bool IsEmail(this string? value)
{ {
return value != null && EmailRegex.IsMatch(value); return value != null && EmailRegex.IsMatch(value);
@ -547,229 +32,6 @@ namespace Squidex.Infrastructure
return !string.IsNullOrWhiteSpace(value) ? value.Trim() : fallback; return !string.IsNullOrWhiteSpace(value) ? value.Trim() : fallback;
} }
public static string ToPascalCase(this string value)
{
if (value.Length == 0)
{
return string.Empty;
}
var sb = new StringBuilder(value.Length);
var last = NullChar;
var length = 0;
for (var i = 0; i < value.Length; i++)
{
var c = value[i];
if (c == '-' || c == '_' || c == ' ')
{
if (last != NullChar)
{
sb.Append(char.ToUpperInvariant(last));
}
last = NullChar;
length = 0;
}
else
{
if (length > 1)
{
sb.Append(c);
}
else if (length == 0)
{
last = c;
}
else
{
sb.Append(char.ToUpperInvariant(last));
sb.Append(c);
last = NullChar;
}
length++;
}
}
if (last != NullChar)
{
sb.Append(char.ToUpperInvariant(last));
}
return sb.ToString();
}
public static string ToKebabCase(this string value)
{
if (value.Length == 0)
{
return string.Empty;
}
var sb = new StringBuilder(value.Length);
var length = 0;
for (var i = 0; i < value.Length; i++)
{
var c = value[i];
if (c == '-' || c == '_' || c == ' ')
{
length = 0;
}
else
{
if (length > 0)
{
sb.Append(char.ToLowerInvariant(c));
}
else
{
if (sb.Length > 0)
{
sb.Append('-');
}
sb.Append(char.ToLowerInvariant(c));
}
length++;
}
}
return sb.ToString();
}
public static string ToCamelCase(this string value)
{
if (value.Length == 0)
{
return string.Empty;
}
var sb = new StringBuilder(value.Length);
var last = NullChar;
var length = 0;
for (var i = 0; i < value.Length; i++)
{
var c = value[i];
if (c == '-' || c == '_' || c == ' ')
{
if (last != NullChar)
{
if (sb.Length > 0)
{
sb.Append(char.ToUpperInvariant(last));
}
else
{
sb.Append(char.ToLowerInvariant(last));
}
}
last = NullChar;
length = 0;
}
else
{
if (length > 1)
{
sb.Append(c);
}
else if (length == 0)
{
last = c;
}
else
{
if (sb.Length > 0)
{
sb.Append(char.ToUpperInvariant(last));
}
else
{
sb.Append(char.ToLowerInvariant(last));
}
sb.Append(c);
last = NullChar;
}
length++;
}
}
if (last != NullChar)
{
if (sb.Length > 0)
{
sb.Append(char.ToUpperInvariant(last));
}
else
{
sb.Append(char.ToLowerInvariant(last));
}
}
return sb.ToString();
}
public static string Slugify(this string value, ISet<char>? preserveHash = null, bool singleCharDiactric = false, char separator = '-')
{
var result = new StringBuilder(value.Length);
var lastChar = (char)0;
for (var i = 0; i < value.Length; i++)
{
var character = value[i];
if (preserveHash?.Contains(character) == true)
{
result.Append(character);
}
else if (char.IsLetter(character) || char.IsNumber(character))
{
lastChar = character;
var lower = char.ToLowerInvariant(character);
if (LowerCaseDiacritics.TryGetValue(character, out var replacement))
{
if (singleCharDiactric && replacement.Length == 2)
{
result.Append(replacement[0]);
}
else
{
result.Append(replacement);
}
}
else
{
result.Append(lower);
}
}
else if ((i < value.Length - 1) && (i > 0 && lastChar != separator))
{
lastChar = separator;
result.Append(separator);
}
}
return result.ToString().Trim(separator);
}
public static string BuildFullUrl(this string baseUrl, string path, bool trailingSlash = false) public static string BuildFullUrl(this string baseUrl, string path, bool trailingSlash = false)
{ {
Guard.NotNull(path, nameof(path)); Guard.NotNull(path, nameof(path));

1
backend/src/Squidex.Infrastructure/Translations/LocalizedCompareAttribute.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Squidex.Text;
namespace Squidex.Infrastructure.Translations namespace Squidex.Infrastructure.Translations
{ {

1
backend/src/Squidex.Infrastructure/Translations/LocalizedRequired.cs

@ -7,6 +7,7 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Squidex.Text;
namespace Squidex.Infrastructure.Translations namespace Squidex.Infrastructure.Translations
{ {

1
backend/src/Squidex.Infrastructure/Validation/AbsoluteUrlAttribute.cs

@ -8,6 +8,7 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Text;
namespace Squidex.Infrastructure.Validation namespace Squidex.Infrastructure.Validation
{ {

1
backend/src/Squidex.Infrastructure/Validation/Not.cs

@ -7,6 +7,7 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Text;
namespace Squidex.Infrastructure.Validation namespace Squidex.Infrastructure.Validation
{ {

1
backend/src/Squidex.Web/Services/StringLocalizer.cs

@ -12,6 +12,7 @@ using System.Linq;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Text;
namespace Squidex.Web.Services namespace Squidex.Web.Services
{ {

93
backend/tests/Squidex.Infrastructure.Tests/StringExtensionsTests.cs

@ -5,7 +5,6 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using Xunit; using Xunit;
namespace Squidex.Infrastructure namespace Squidex.Infrastructure
@ -33,98 +32,6 @@ namespace Squidex.Infrastructure
Assert.Equal("fallback", value.Or("fallback")); Assert.Equal("fallback", value.Or("fallback"));
} }
[Theory]
[InlineData("", "")]
[InlineData("m", "m")]
[InlineData("m y", "m-y")]
[InlineData("M Y", "m-y")]
[InlineData("M_Y", "m-y")]
[InlineData("M_Y ", "m-y")]
public void Should_convert_to_kebap_case(string input, string output)
{
Assert.Equal(output, input.ToKebabCase());
}
[Theory]
[InlineData("", "")]
[InlineData("m", "M")]
[InlineData("m-y", "MY")]
[InlineData("my", "My")]
[InlineData("myProperty ", "MyProperty")]
[InlineData("my property", "MyProperty")]
[InlineData("my_property", "MyProperty")]
[InlineData("my-property", "MyProperty")]
public void Should_convert_to_pascal_case(string input, string output)
{
Assert.Equal(output, input.ToPascalCase());
}
[Theory]
[InlineData("", "")]
[InlineData("M", "m")]
[InlineData("My", "my")]
[InlineData("M-y", "mY")]
[InlineData("MyProperty ", "myProperty")]
[InlineData("My property", "myProperty")]
[InlineData("My_property", "myProperty")]
[InlineData("My-property", "myProperty")]
public void Should_convert_to_camel_case(string input, string output)
{
Assert.Equal(output, input.ToCamelCase());
}
[Theory]
[InlineData("Hello World", '-', "hello-world")]
[InlineData("Hello/World", '-', "hello-world")]
[InlineData("Hello World", '_', "hello_world")]
[InlineData("Hello/World", '_', "hello_world")]
[InlineData("Hello World ", '_', "hello_world")]
[InlineData("Hello World-", '_', "hello_world")]
[InlineData("Hello/World_", '_', "hello_world")]
public void Should_replace_special_characters_with_sepator_when_slugifying(string input, char separator, string output)
{
Assert.Equal(output, input.Slugify(separator: separator));
}
[Theory]
[InlineData("ö", "oe")]
[InlineData("ü", "ue")]
[InlineData("ä", "ae")]
public void Should_replace_multi_char_diacritics_when_slugifying(string input, string output)
{
Assert.Equal(output, input.Slugify());
}
[Theory]
[InlineData("ö", "o")]
[InlineData("ü", "u")]
[InlineData("ä", "a")]
public void Should_not_replace_multi_char_diacritics_when_slugifying(string input, string output)
{
Assert.Equal(output, input.Slugify(singleCharDiactric: true));
}
[Theory]
[InlineData("Físh", "fish")]
[InlineData("źish", "zish")]
[InlineData("żish", "zish")]
[InlineData("fórm", "form")]
[InlineData("fòrm", "form")]
[InlineData("fårt", "fart")]
public void Should_replace_single_char_diacritics_when_slugifying(string input, string output)
{
Assert.Equal(output, input.Slugify());
}
[Theory]
[InlineData("Hello my&World ", '_', "hello_my&world")]
[InlineData("Hello my&World-", '_', "hello_my&world")]
[InlineData("Hello my/World_", '_', "hello_my/world")]
public void Should_keep_characters_when_slugifying(string input, char separator, string output)
{
Assert.Equal(output, input.Slugify(new HashSet<char> { '&', '/' }, false, separator));
}
[Fact] [Fact]
public void Should_provide_value() public void Should_provide_value()
{ {

Loading…
Cancel
Save