Skip to content

Support for trimming chars from generated slug's start/end.#175

Open
mjamro wants to merge 2 commits intoctolkien:mainfrom
mjamro:main
Open

Support for trimming chars from generated slug's start/end.#175
mjamro wants to merge 2 commits intoctolkien:mainfrom
mjamro:main

Conversation

@mjamro
Copy link

@mjamro mjamro commented Feb 13, 2026

Closes #162

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds support for trimming specific characters from the start and/or end of generated slugs, addressing issue #162 which requested the ability to remove trailing punctuation like dots from slugs.

Changes:

  • Added three new configuration options: TrimChars, TrimEndChars, and TrimStartChars to SlugHelperConfiguration
  • Implemented trimming logic in SlugHelper.GenerateSlug() method
  • Added comprehensive test coverage for the new trimming functionality
  • Updated README.md with documentation and examples

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.

File Description
src/Slugify.Core/SlugHelperConfiguration.cs Added three new char array properties for trimming characters from both ends, end only, or start only
src/Slugify.Core/SlugHelper.cs Implemented trimming operations in the slug generation pipeline
tests/Slugify.Core.Tests/SlugHelperTests.cs Added three test methods to validate the trimming functionality
README.md Added documentation section explaining the new trim options with examples

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +41 to +43
normalizedInput = Config.TrimChars.Length != 0 ? normalizedInput.Trim(Config.TrimChars) : normalizedInput;
normalizedInput = Config.TrimEndChars.Length != 0 ? normalizedInput.TrimEnd(Config.TrimEndChars) : normalizedInput;
normalizedInput = Config.TrimStartChars.Length != 0 ? normalizedInput.TrimStart(Config.TrimStartChars) : normalizedInput;
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trim operations are applied early in the pipeline, before string replacements and character filtering. This means they cannot trim characters that appear at the edges as a result of transformations. For example, if a string replacement adds a dot at the end, or if character filtering removes characters that expose trailing punctuation, the current implementation won't trim them. The MaximumLength feature (lines 92-100) sets a precedent by trimming trailing dashes AFTER all transformations. Consider moving these trim operations to after line 100 (before the return) to trim from the final slug, which would be more consistent and handle more use cases.

Copilot uses AI. Check for mistakes.
Comment on lines +221 to +228
Trim options to remove characters from the input before replacements and character filtering. This is useful to prevent generated slug to start/end with certain characters like dot.

- Options
- `TrimChars` — characters to trim from both ends (behaves like `string.Trim(char[])`).
- `TrimEndChars` — characters to trim from the end (behaves like `string.TrimEnd(char[])`).
- `TrimStartChars` — characters to trim from the start (behaves like `string.TrimStart(char[])`).

- Default value: all three are empty arrays (no extra trimming).
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states these options remove characters "from the input before replacements and character filtering", but issue 162 describes wanting to remove trailing punctuation from the generated slug (i.e., the output). The current implementation trims early in the process, which may not match user expectations. Consider updating the documentation to clarify this behavior, or moving the trim operations to apply to the final slug output instead.

Copilot uses AI. Check for mistakes.
Comment on lines +515 to +528
[Theory]
[MemberData(nameof(GenerateStandardSluggers))]
public void TestTrimmingEndChars(ISlugHelper helper)
{
const string original = "hello._world._";
const string expected = "hello._world";

helper.Config = new SlugHelperConfiguration
{
TrimEndChars = [ '.', '_' ],
};

Assert.Equal(expected, helper.GenerateSlug(original));
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test only validates trimming characters that exist in the original input. Add a test case where trailing characters appear due to transformations, such as: input "test." with StringReplacements of {".": "-"} and TrimEndChars = ['-']. This would expose whether the trim operations correctly handle characters created during the slug generation process. The current implementation would fail such a test because trimming happens before replacements.

Copilot uses AI. Check for mistakes.
normalizedInput = normalizedInput.Normalize(NormalizationForm.FormD);
normalizedInput = Config.TrimWhitespace ? normalizedInput.Trim() : normalizedInput;
normalizedInput = Config.ForceLowerCase ? normalizedInput.ToLowerInvariant() : normalizedInput;
normalizedInput = Config.TrimChars.Length != 0 ? normalizedInput.Trim(Config.TrimChars) : normalizedInput;
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a user sets both TrimChars and TrimEndChars (or TrimStartChars), the operations will be applied sequentially, which could lead to unexpected behavior. For example, if TrimChars = ['.'] and TrimEndChars = ['_'], after TrimChars removes dots from both ends, TrimEndChars would then remove underscores. Consider documenting this interaction, or detecting and warning about conflicting configurations, or applying only the most specific option when multiple are set.

Suggested change
normalizedInput = Config.TrimChars.Length != 0 ? normalizedInput.Trim(Config.TrimChars) : normalizedInput;
normalizedInput = Config.TrimChars.Length != 0 && Config.TrimEndChars.Length == 0 && Config.TrimStartChars.Length == 0
? normalizedInput.Trim(Config.TrimChars)
: normalizedInput;

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +75
/// List of characters to be trimmed (removed from both ends) from generated slug
/// </summary>
public char[] TrimChars { get; set; } = [];

/// <summary>
/// List of characters to be trimmed from end of the generated slug
/// </summary>
public char[] TrimEndChars { get; set; } = [];

/// <summary>
/// List of characters to be trimmed from start of the generated slug
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation says "List of characters to be trimmed (removed from both ends) from generated slug" but the trimming happens on the input, not the generated slug. Consider changing to "from the input string" or "before slug generation" for accuracy. Similarly for TrimEndChars and TrimStartChars documentation.

Suggested change
/// List of characters to be trimmed (removed from both ends) from generated slug
/// </summary>
public char[] TrimChars { get; set; } = [];
/// <summary>
/// List of characters to be trimmed from end of the generated slug
/// </summary>
public char[] TrimEndChars { get; set; } = [];
/// <summary>
/// List of characters to be trimmed from start of the generated slug
/// List of characters to be trimmed (removed from both ends) from the input string before slug generation.
/// </summary>
public char[] TrimChars { get; set; } = [];
/// <summary>
/// List of characters to be trimmed from the end of the input string before slug generation.
/// </summary>
public char[] TrimEndChars { get; set; } = [];
/// <summary>
/// List of characters to be trimmed from the start of the input string before slug generation.

Copilot uses AI. Check for mistakes.

### `TrimChars`, `TrimEndChars`, `TrimStartChars`

Trim options to remove characters from the input before replacements and character filtering. This is useful to prevent generated slug to start/end with certain characters like dot.
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammar issue: "to prevent generated slug to start/end" should be either "to prevent the generated slug from starting/ending" or "to prevent generated slugs from starting/ending".

Suggested change
Trim options to remove characters from the input before replacements and character filtering. This is useful to prevent generated slug to start/end with certain characters like dot.
Trim options to remove characters from the input before replacements and character filtering. This is useful to prevent the generated slug from starting or ending with certain characters like dot.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trailing punctutaion

3 participants