Skip to content

Comments

Introduce Trimmed validator#1702

Open
alganet wants to merge 1 commit intoRespect:3.0from
alganet:trimmed
Open

Introduce Trimmed validator#1702
alganet wants to merge 1 commit intoRespect:3.0from
alganet:trimmed

Conversation

@alganet
Copy link
Member

@alganet alganet commented Feb 20, 2026

This commit introduces the Trimmed validator that ensures a string cannot start or end with a list of specific values.

The default values used are a selected list of Unicode invisible characters.

To support this change, the StartsWith and EndsWith validators were modified so they can also support multiple values to check for.

While StartsWith and EndsWith are more generic, and also perform start-of-array and end-of-array kinds of checks, Trimmed is more focused on string inputs, which tailors to a more specific use case.

Copy link

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 introduces a new Trimmed validator that ensures string inputs do not start or end with specific values, defaulting to a comprehensive list of Unicode whitespace and zero-width characters. It also extends the StartsWith and EndsWith validators to accept multiple values, enabling more flexible validation patterns.

Changes:

  • Added new Trimmed validator with support for default Unicode invisible characters and custom trim values
  • Modified StartsWith and EndsWith validators to accept multiple values via variadic parameters
  • Updated all mixin interfaces (Builder, Chain, NotBuilder, NotChain, etc.) to reflect new method signatures

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Validators/Trimmed.php New validator that composes StringType, StartsWith, EndsWith, AnyOf, and Not to validate trimmed strings
src/Validators/StartsWith.php Enhanced to support multiple start values with OR logic and new template for multiple values
src/Validators/EndsWith.php Enhanced to support multiple end values with OR logic and new template for multiple values
tests/unit/Validators/TrimmedTest.php Unit tests covering default Unicode characters, custom trim values, and edge cases
tests/feature/Validators/TrimmedTest.php Feature tests for default/inverted templates and custom alternatives
tests/unit/Validators/StartsWithTest.php Additional test cases for multiple value support
tests/unit/Validators/EndsWithTest.php Additional test cases for multiple value support
tests/feature/Validators/StartsWithTest.php Feature tests for multiple value error messages
tests/feature/Validators/EndsWithTest.php Feature tests for multiple value error messages
tests/src/SmokeTestProvider.php Added smoke test entry for Trimmed validator
src/Mixins/*.php Updated method signatures for startsWith, endsWith, and added trimmed methods across all mixin files
docs/validators/Trimmed.md New documentation explaining Trimmed validator usage, templates, and examples
docs/validators/StartsWith.md Updated documentation for multiple values support with examples and new template
docs/validators/EndsWith.md Updated documentation for multiple values support with examples and new template
docs/validators.md Updated validator index to include Trimmed and updated descriptions for StartsWith
Comments suppressed due to low confidence (1)

src/Validators/EndsWith.php:27

  • Missing import for is_string function. This should be added to the use function statements to match the pattern in StartsWith and to support the necessary type safety check on line 75.
use function count;
use function end;
use function is_array;
use function mb_strlen;
use function mb_strrpos;

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

This commit introduces the `Trimmed` validator that ensures a string
cannot start or end with a list of specific values.

The default values used are a selected list of Unicode invisible
characters.

To support this change, the StartsWith and EndsWith validators were
modified so they can also support multiple values to check for.

While StartsWith and EndsWith are more generic, and also perform
start-of-array and end-of-array kinds of checks, Trimmed is more
focused on string inputs, which tailors to a more specific use
case.
@alganet alganet marked this pull request as ready for review February 20, 2026 23:49
@codecov
Copy link

codecov bot commented Feb 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.48%. Comparing base (e1ff5aa) to head (e4ca8d4).

Additional details and impacted files
@@            Coverage Diff            @@
##                3.0    #1702   +/-   ##
=========================================
  Coverage     99.47%   99.48%           
- Complexity      979      994   +15     
=========================================
  Files           193      194    +1     
  Lines          2294     2333   +39     
=========================================
+ Hits           2282     2321   +39     
  Misses           12       12           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member

@henriquemoody henriquemoody left a comment

Choose a reason for hiding this comment

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

I know we want to reuse existing rules, but Trimmed seems excessively complicated to me. If we would leverage mb_trim() in this validator it would have been simpler and more performant. To me, it would make much more sense to have a Trimmed($side, ...$chars), which is similar to the formatter we already created (which we could also leverage).

Apart from that, I can't put my finger on it, but the changes in the StartWith and EndsWith seems off to me. This v::endsWith('ipsum', 'dolor')->assert('lorem dolor') is confusing to me, and if the intend is to check if the input might end with multiple strings, I would rather have v::onOf(v::endsWith('ipsum'), v::endsWith('dolor')). The current state of those those validators are more similar to str_ends_with() and str_starts_with(), which I like.

I won't put against how you're making those changes because they could to me more of a preference of mine than a flaw in the design. I'm not approving it because I want to enquire about the Envelope

);
}

public function evaluate(mixed $input): Result
Copy link
Member

Choose a reason for hiding this comment

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

Couldn't you just extend Envelop instead?

@alganet
Copy link
Member Author

alganet commented Feb 23, 2026

@henriquemoody

I thought about the $side parameter, but that is essentially what notStartsWith and notEndsWith are. That was my rationale for adding multiple alternatives instead of a new validator with $side, it felt more natural.

For the StartsWith and EndsWith multiple parameters, there's a big difference versus oneOf/anyOf: the message. It says Must start with "Mr." or "Ms." (for example) instead of a more verbose "One of the rules: - Must start with "Mr" - Must start with "Ms".

I will work on those scenarios to make them more evident. The lorem ipsum is not making justice to the change!

Regarding mb_trim, it is certainly a possibility. We're doing more than trimming single characters. With the current setup, we can also check for whole strings: v::trimmed('<!--', '-->', '#', '//') and this is not possible with mb_trim. I agree though that it might be a niche case. I wouldn't mind simplifying it.

What set of templates would you use for a v::trimmed($side, ...$chars)? Would you use an Enum for the side or plain string?

@henriquemoody
Copy link
Member

henriquemoody commented Feb 23, 2026

I see. When I read v::trimmed('<!--', '-->', '#', '//') it seemed like another validator, something like a EdgesWith, WrapsWith. Perhaps we're just a bit stuck to "trim" because of familiarity, but in fact, we only care about the "trimming" when that validator handles spaces.

I think we could still have Trimmed, but be that about those trim values. I'm not sure.

What set of templates would you use for a v::trimmed($side, ...$chars)? Would you use an Enum for the side or plain string?

After your last comment, I'm reconsidering the $side, because people could just use StartsWith and EndsWith. I think the message should be more geared towards being wrapped by a value, something like:

{{subject}} must start be wrapped by {{startValue}}

I have to think a bit more about it, though

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.

2 participants