Commit graph

18 commits

Author SHA1 Message Date
Alexandre Gomes Gaigalas
2600db3c74 Introduce Trimmed validator
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.
2026-02-26 10:34:53 +00:00
Alexandre Gomes Gaigalas
7c8ecfa317 Fix PublicSuffix validator and UpdateDomainSuffixesCommand
- Parce PSL ICANN section into structured sections (rules,
   wildcards, exceptions) according to the format.
 - Updates PublicSuffix semantics for complete application of
   the rules.
 - Includes private domain suffixes now.
 - Refreshes the existing data.
 - Fixes the update-regionals.yml workflow, set it to run
   twice a week.

References: https://github.com/publicsuffix/list/wiki/Format#format
2026-02-23 12:18:57 +00:00
Henrique Moody
6abf3a548c
Remove Masked validator in favor of Formatted
The Masked validator was a proxy for what the new Formatted validator
already does, so it is being removed to reduce redundancy. All tests and
documentation have been updated accordingly.

Assisted-by: OpenCode (ollama-cloud/glm-4.7)
2026-02-06 20:44:26 +01:00
Henrique Moody
dc0c0345c9
Create "Formatted" validator
The Formatted validator decorates another validator to transform how
input values appear in error messages, while still validating the
original unmodified input.

This is useful for improving the readability of error messages by
displaying values in a user-friendly formatd.

The validator accepts any Respect\StringFormatter\Formatter implementation,
allowing direct use of StringFormatter's fluent builder. As StringFormatter
expands with more formatters in future releases, users will automatically
benefit from the full range of formatting options.

Assisted-by: Claude Code (Opus 4.5)
2026-02-06 20:44:26 +01:00
Henrique Moody
b701fac656
Create ShortCircuit validator and ShortCircuitable interface
This commit introduces a mechanism for validators to return early once
the validation outcome is determined, rather than evaluating all child
validators.

The ShortCircuit validator evaluates validators sequentially and stops
at the first failure, similar to how PHP's && operator works. This is
useful when later validators depend on earlier ones passing, or when
you want only the first error message.

The ShortCircuitCapable interface allows composite validators (AllOf,
AnyOf, OneOf, NoneOf, Each, All) to implement their own short-circuit
logic.

Why "ShortCircuit" instead of "FailFast":

The name "FailFast" was initially considered but proved misleading.
While AllOf stops on failure (fail fast), AnyOf stops on success
(succeed fast), and OneOf stops on the second success. The common
behavior is not about failing quickly, but about returning as soon as
the outcome is determined—which is exactly what short-circuit
evaluation means. This terminology is familiar to developers from
boolean operators (&& and ||), making the behavior immediately
understandable.

Co-authored-by: Alexandre Gomes Gaigalas <alganet@gmail.com>
Assisted-by: Claude Code (Opus 4.5)
2026-02-05 17:32:42 +01:00
Alexandre Gomes Gaigalas
e636b63f14 Add v::format() to check if data is already in a specific format
This validator is not so much about how we present the input
during error messages, but in what format data already is formatted.
2026-02-05 16:19:11 +00:00
Valdeir S
570ba481b1 Add Support for Alphanumeric CNPJ
Due to the continuous increase in the number of companies and the
imminent exhaustion of available CNPJs (Brazilian taxpayer
identification numbers), the Brazilian Federal Revenue Service is
instituting the alphanumeric CNPJ. The initiative aims to
facilitate the identification of all companies and improve the
business environment, contributing to the economic and social
development of Brazil.

The alphanumeric CNPJ will be assigned, starting in July 2026,
exclusively to new registrations.

Changes:

- Add support for alphanumeric CNPJ validation
- Format code according to PHPCS standards
- Simplify CNPJ conversion to uppercase character array
- Add documentation about CNPJ structure
2026-02-04 13:20:30 +01:00
Henrique Moody
7c681fec66
Fix SPDX headers in all files
I ran the `bin/console spdx --fix` with different strategies for
different files. For most of the core classes, since they've been
drastically rebuilt, I've run it with the `git-blame` strategy, for for
the `src/Validators`, in which the API changed completely but the logic
remains the same, I use the `git-log` strategy.
2026-02-03 15:23:23 +01:00
Henrique Moody
7db3bea8a6
Enhance LintSpdxCommand with contributor tracking and header normalization
Improves SPDX header linting to ensure consistent license metadata across
the codebase.

Key changes:

- Enforce deterministic tag ordering (License-Identifier, FileCopyrightText,
  FileContributor) to ensure consistency, prevent merge conflicts, and
  simplify code reviews

- Add contributor alias mapping to consolidate contributors with multiple
  emails or name variations (e.g., "nickl-" → "Nick Lombard")

- Add --contributions-strategy option with "blame" (current code authors)
  and "log" (all historical contributors) to support different attribution
  philosophies

- Add optional path argument to lint specific files or directories

- Add --fix option to automatically correct header issues

Assisted-by: Claude Code (claude-opus-4-5-20251101)
2026-02-03 15:23:20 +01:00
Henrique Moody
63f7753e43
Rename "Call" validator to "After"
The previous name was confusing as it focused on the implementation
detail (calling a callable) rather than what the validator actually
does. The new name "After" better conveys the validator's purpose:
validating the input after applying a transformation.

Assisted-by: Claude Code (Opus 4.5)
2026-02-02 01:46:12 +01:00
Henrique Moody
92d53f096d
Rename "Callback" validator to "Satisfies"
The previous name was confusing as it focused on the implementation
detail (receiving a callback) rather than what the validator actually
does. The new name "Satisfies" better conveys the validator's purpose:
checking whether the input satisfies a given condition.

Assisted-by: Claude Code (Opus 4.5)
2026-02-02 01:40:14 +01:00
Henrique Moody
f822ed0298
Rename "Lazy" validator to "Factory"
The name "Factory" better conveys the validator's purpose: dynamically
creating a validator at runtime based on the input value. "Lazy" was
misleading as it suggested simple deferred evaluation rather than
input-dependent validator construction.

Also renamed the constructor argument from `$validatorCreator` to
`$factory` for improved expressiveness.

Assisted-by: Claude Code (Opus 4.5)
2026-02-02 01:40:14 +01:00
Alexandre Gomes Gaigalas
a64e33168f Improve Url validator to be more strict
Previously, the URL validator accepted all kinds of URLs.

Combining it with other validators like `Domain` and `Ip` manually
is clumbersome, since the rules are extensive and require small
tweaks such as understanding bracketed IP addresses.

This change makes that composition built-in. The validator still
uses the FILTER_VALIDATE_URL from PHP, but now it also goes deeper
and validate portions of the URL that other validators support.

Changes to `Call` were made so that it can be serialized under
certain circumstances (when invoking a static method call), making
it more flexible.

A static internal method helper for trimming the IP was added to
the Url validator class and marked as internal, as it cannot be
both private, serializable and accessible to the `Call` instance
all at the same time. The `@internal` annotation should advise
users that it's not a public API according to phpdoc conventions.
2026-02-02 00:26:40 +00:00
Alexandre Gomes Gaigalas
bcc60ec035 Allow empty values in iterables for All, Each, Max, Min
Now empty values are again allowed in FilteredArray-style
validators.

To solve the issue with negation, a Result attribute was
added to signal indeciseveness (when a result cannot be
reliably inverted). On such cases, we consider that result
to be valid.

For example, `v::not(v::min(v::equals(10)))` says "The
lowest value of the iterable input should not be equal 10".

If the input is empty, we cannot decide whether its minimum
is equal to 10 or not, so the validator essentially becomes
a null-op.

Users that want to ensure these validators have a valid
decidable target must use it in combination with `Length`
or other similar validators to achieve the same result.
2026-01-30 21:27:16 +00:00
Henrique Moody
882f24b6b8
Create "Masked" validator
The Masked validator decorates other validators to mask sensitive input
values in error messages while still validating the original unmasked
data.

This validator is essential for applications handling sensitive
information such as passwords, credit cards, or email addresses. Without
it, users would need to implement a custom layer between Validation and
the end user to prevent PII from appearing in error messages or logs.

With Masked, sensitive data protection is built directly into the
validation workflow with no additional abstraction required.

Assisted-by: Claude Code (Opus 4.5)
2026-01-30 21:06:36 +01:00
Alexandre Gomes Gaigalas
47f8f82d7f Remove mathematical, niche and deprecated validators
This commit removes validators described in #1642, refactoring
to clean up after their removal.

 - Url was refactored to use the function `filter_var` instead.
 - tests/bootstrap.php is no longer needed and was removed.
 - Updated migration guide with recommendations for replacements.
2026-01-30 16:08:27 +00:00
Alexandre Gomes Gaigalas
2a7f345e32 Streamline validators.md index
Makes it so the index looks more like a cheatsheet, condensing
information instead of making long lists that require lots of
scrolling to explore.

Additionally, the happy path for each validator was also
added, providing a quick reference use for comparison.

The direct markdown links were replaced by titled markdown
references, offering mouse-over tooltips over links that
display the validator one-line description.

To ensure a proper source of truth for these new index
goodies, the AssertionMessageLinter was modified to
verify that the first assertion in each doc is a
single-line validator that passes (a happy path), further
making our documentation conventions more solid.
2026-01-28 12:47:08 +00:00
Henrique Moody
d1d8980ff9
Use awesome-pages to customize the menus
We tried using `mkdocs-nav-weight` but it turned out quiet limited. Not
only we have to add specific frontmatter to the Markdown files, but we
could also not hide and sort directories.

This commit introduces awesome-pages, which allows us to customize the
order of pages and not list the content of the "validators" directory in
the left menu.
2026-01-26 12:26:06 +01:00