Skip to content

feat: add builtin validation rules and filters#1416

Merged
h2zi merged 11 commits into
masterfrom
haozi/validation-rules
Mar 19, 2026
Merged

feat: add builtin validation rules and filters#1416
h2zi merged 11 commits into
masterfrom
haozi/validation-rules

Conversation

@h2zi
Copy link
Copy Markdown
Contributor

@h2zi h2zi commented Mar 17, 2026

Summary

Close goravel/goravel#693

Add all builtin validation rules, filters, and their backward-compatible aliases from the old gookit/validate-based implementation.

This PR also introduces a deprecation plan: all camelCase-named rules and filters (e.g. eq_fieldsame, trimSpacetrim, toIntto_int) are kept as backward-compatible aliases but marked as deprecated. They will be removed in the next major version. Going forward, all rule and filter names follow snake_case convention to stay consistent with Laravel and reduce maintenance overhead.

Validation Rules

New Rules (not in old version)

Rule Description
required_if_accepted Required when another field is accepted
required_if_declined Required when another field is declined
filled Must have a value when present
present Must be present in data
present_if Must be present when condition met
present_unless Must be present unless condition met
present_with Must be present when other field exists
present_with_all Must be present when all other fields exist
missing Must be missing from data
missing_if Must be missing when condition met
missing_unless Must be missing unless condition met
missing_with Must be missing when other field exists
missing_with_all Must be missing when all other fields exist
accepted Must be accepted (true/yes/on/1)
accepted_if Must be accepted when condition met
declined Must be declined (false/no/off/0)
declined_if Must be declined when condition met
prohibited Field is prohibited
prohibited_if Prohibited when condition met
prohibited_unless Prohibited unless condition met
prohibited_if_accepted Prohibited when other field accepted
prohibited_if_declined Prohibited when other field declined
prohibits Prohibits other fields from being present
integer Must be an integer (alias: int)
boolean Must be boolean (alias: bool)
list Must be a list (alias: slice)
size Size must equal value (type-aware)
gte Greater than or equal (type-aware)
lte Less than or equal (type-aware)
digits Must be N digits
digits_between Digits count in range
decimal Must have N decimal places
multiple_of Must be multiple of value
min_digits Minimum digit count
max_digits Maximum digit count
ascii Must be ASCII only
active_url Must be a resolvable URL
mac_address / mac Must be valid MAC address
ulid Must be valid ULID
hex_color Must be valid hex color
not_regex Must not match regex
lowercase Must be lowercase
uppercase Must be uppercase
doesnt_start_with Must not start with value
doesnt_end_with Must not end with value
contains Must contain value
doesnt_contain Must not contain value
confirmed Must have matching confirmation field
same Must match another field
different Must differ from another field
in_array Must exist in another array field
in_array_keys Must contain specified keys
date_format Must match date format
date_equals Must equal date
before Must be before date
before_or_equal Must be before or equal to date
after Must be after date
after_or_equal Must be after or equal to date
timezone Must be valid timezone
exclude Exclude field from validated data
exclude_if Exclude when condition met
exclude_unless Exclude unless condition met
exclude_with Exclude when other field present
exclude_without Exclude when other field missing
mimes Must be file of specified MIME type
mimetypes Must be file of specified MIME type
extensions Must have specified extension
dimensions Image dimension constraints
encoding Must have specified encoding
bail Stop on first failure
nullable Allow null values
sometimes Only validate when present
distinct Array values must be distinct
required_array_keys Array must contain specified keys
exists Must exist in database
unique Must be unique in database

Kept Rules (from old version, same or enhanced)

New Name Old Name Status Notes
required required ✅ Same -
required_if required_if ✅ Same -
required_unless required_unless ✅ Same -
required_with required_with ✅ Same -
required_with_all required_with_all ✅ Same -
required_without required_without ✅ Same -
required_without_all required_without_all ✅ Same -
string string ✅ Same -
integer / int int ✅ Enhanced Added integer as primary name, int as Go alias
uint uint ✅ Kept Go-specific unsigned integer check
numeric number ⚠️ Renamed Checks if value is numeric
boolean / bool bool ✅ Enhanced Added boolean as primary name
float float ✅ Same -
slice slice ✅ Same Also available as list
array array ✅ Same -
map map ✅ Same -
in in ✅ Same -
not_in not_in ✅ Same -
starts_with starts_with ✅ Same -
ends_with ends_with ✅ Same -
between between ✅ Enhanced Now type-aware (string length / array count / file size)
min min ✅ Enhanced Merged min_len, type-aware
max max ✅ Enhanced Merged max_len, type-aware
size len ⚠️ Renamed lensize (Laravel naming)
gt gt + gt_field ✅ Enhanced Merged, supports field references
gte gte_field ✅ Enhanced Merged, supports field references
lt lt + lt_field ✅ Enhanced Merged, supports field references
lte lte_field ✅ Enhanced Merged, supports field references
eq eq ✅ Kept Check value equals fixed value
ne ne ✅ Kept Check value not equals fixed value
same eq_field ⚠️ Renamed Field-to-field comparison
different ne_field ⚠️ Renamed Field-to-field comparison
email email ✅ Same -
url full_url ⚠️ Renamed Requires scheme
ip ip ✅ Same -
ipv4 ipv4 ✅ Same -
ipv6 ipv6 ✅ Same -
json json ✅ Same -
alpha alpha ✅ Same -
alpha_num alpha_num ✅ Same -
alpha_dash alpha_dash ✅ Same -
regex regex ✅ Same -
uuid uuid ✅ Same -
uuid3 uuid3 ✅ Same -
uuid4 uuid4 ✅ Same -
uuid5 uuid5 ✅ Same -
date date ✅ Same -
after gt_date ⚠️ Renamed Laravel naming
before lt_date ⚠️ Renamed Laravel naming
after_or_equal gte_date ⚠️ Renamed Laravel naming
before_or_equal lte_date ⚠️ Renamed Laravel naming
file file ✅ Same -
image image ✅ Same -

Deprecated Rules (backward-compatible, will be removed next version)

Deprecated Name Use Instead Notes
len size Laravel naming
min_len min Merged into type-aware min
max_len max Merged into type-aware max
eq_field same Laravel naming
ne_field different Laravel naming
gt_field gt Merged into gt
gte_field gte Merged into gte
lt_field lt Merged into lt
lte_field lte Merged into lte
gt_date after Laravel naming
lt_date before Laravel naming
gte_date after_or_equal Laravel naming
lte_date before_or_equal Laravel naming
number numeric Laravel naming
full_url url Laravel naming

Filters

Primary Filters (snake_case)

Filter Description
trim Trim whitespace from both ends
ltrim Trim whitespace from left
rtrim Trim whitespace from right
lower Convert to lowercase
upper Convert to uppercase
title Capitalize first letter of each word
ucfirst Capitalize first character
lcfirst Lowercase first character
camel Convert to camelCase
snake Convert to snake_case
to_int Convert to int
to_int64 Convert to int64
to_uint Convert to uint
to_float Convert to float64
to_bool Convert to bool
to_string Convert to string
to_time Convert to time.Time
strip_tags Strip HTML tags
escape_js Escape JavaScript string
escape_html Escape HTML entities
url_encode URL encode
url_decode URL decode
str_to_ints Split comma-separated string to []int
str_to_array Split comma-separated string to []string
str_to_time Convert date string to time.Time

Short Name Aliases

Alias Maps To
int to_int
int64 to_int64
uint to_uint
float to_float
bool to_bool

Old Filters → New Filters Mapping

Old Name New Name Deprecated?
int / toInt to_int (or int) toInt deprecated
uint / toUint to_uint (or uint) toUint deprecated
int64 / toInt64 to_int64 (or int64) toInt64 deprecated
float / toFloat to_float (or float) toFloat deprecated
bool / toBool to_bool (or bool) toBool deprecated
trim / trimSpace trim trimSpace deprecated
ltrim / trimLeft ltrim trimLeft deprecated
rtrim / trimRight rtrim trimRight deprecated
lower / lowercase lower lowercase deprecated
upper / uppercase upper uppercase deprecated
lcFirst / lowerFirst lcfirst lcFirst / lowerFirst deprecated
ucFirst / upperFirst ucfirst ucFirst / upperFirst deprecated
ucWord / upperWord title ucWord / upperWord deprecated
camel / camelCase camel camelCase deprecated
snake / snakeCase snake snakeCase deprecated
escapeJs / escapeJS escape_js escapeJs / escapeJS deprecated
escapeHtml / escapeHTML escape_html escapeHtml / escapeHTML deprecated
str2ints / strToInts str_to_ints str2ints / strToInts deprecated
str2time / strToTime str_to_time str2time / strToTime deprecated
str2arr / str2array / strToArray str_to_array All deprecated

Test Plan

  • All existing validation tests pass
  • New rule tests: uuid3, uuid4, uuid5, eq, ne, uint
  • Deprecated rule alias tests
  • New filter tests: escape_js, to_int64, str_to_ints, str_to_array, str_to_time
  • Deprecated filter alias tests
  • All short name alias tests

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Expanded built-in filters for data transformation, including string cleaning, case conversions, type conversions, and encoding operations.
    • Added comprehensive validation rules and deprecated aliases for backward compatibility.
    • Extended validation messages for additional rule types including UUID variants and type checks.
  • Tests

    • Added extensive benchmark tests for performance measurement.
    • Introduced comprehensive test coverage for filters and utility functions.

@h2zi h2zi requested a review from a team as a code owner March 17, 2026 21:18
@h2zi
Copy link
Copy Markdown
Contributor Author

h2zi commented Mar 17, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@h2zi
Copy link
Copy Markdown
Contributor Author

h2zi commented Mar 17, 2026

@claude review

@h2zi
Copy link
Copy Markdown
Contributor Author

h2zi commented Mar 17, 2026

@copilot review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 17, 2026

📝 Walkthrough

Walkthrough

This PR implements a comprehensive validation framework by populating rule definitions, filter functions, validation messages, and utility helpers. It includes extensive test coverage through new test files and refactored existing tests, plus integration with the ORM facade. Core validation behavior is preserved with backward compatibility through deprecated rule aliases.

Changes

Cohort / File(s) Summary
Rule Implementation
validation/rules.go
Expands builtinRules from empty to comprehensive registry with ~40+ rule implementations covering existence, type checks, size constraints, string formats, date validations, database operations, file validations, and control rules; includes implicitRules, excludeRules, and numericRuleNames support structures.
Filter Implementation
validation/filters.go
Populates builtinFilters with ~30+ filter functions including string manipulation (trim, case conversion), naming styles (camel, snake), type conversions, encoding/escaping, URL operations, and deprecated aliases for backward compatibility.
Utility Functions
validation/utils.go, validation/utils_test.go
Adds 15+ internal utility helpers (getSize, date parsing, value predicates, string casing, HTML/JS escaping, MIME detection, file handling) and corresponding test coverage; removes isControlRule helper.
Validation Messages
validation/messages.go
Adds message definitions for new rule types (uint, uuid3/4/5 variants), equality aliases (eq, ne), and deprecated aliases (len, min_len, max_len, etc.).
Core Validation Logic
validation/validation.go
Changes control rule handling from dynamic isControlRule check to explicit fixed set (bail, sometimes, nullable).
Service Integration
validation/service_provider.go
Adds orm facade initialization via ormFacade variable and Boot method setup.
Test Infrastructure
validation/benchmark_test.go, validation/filters_test.go, validation/errors_test.go, validation/options_test.go, validation/validator_test.go
Adds comprehensive benchmarks (~11 benchmark functions), filter tests (~6 test functions with wildcard support and mock filters), refactors error tests to table-driven patterns, updates validator tests to use generic any types, and minor cleanup of test helpers.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • hwbrzzl
  • devhaozi

Poem

🐰 Hops through rules, both old and new,
Filters transform each data view,
Tests and benchmarks validate true,
Messages guide the user through,
Validation's journey, fresh as dew! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.34% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: add builtin validation rules and filters' accurately captures the main objective of the pull request, which is to add comprehensive built-in validation rules and filters with backward-compatible aliases.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch haozi/validation-rules
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can disable poems in the walkthrough.

Disable the reviews.poem setting to disable the poems in the walkthrough.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
validation/utils.go (1)

423-435: Potential edge case: non-standard types may unexpectedly match as "declined".

For non-string types, cast.ToInt(val) returns 0 when the value can't be meaningfully converted (e.g., slices, maps, structs). This causes the function to return true, treating arbitrary non-castable values as "declined".

While this is unlikely to affect typical form validation (strings/booleans/integers), it creates an asymmetry with isAcceptedValue which returns false for such types.

Consider adding an explicit boolean type check to match isAcceptedValue's behavior:

♻️ Proposed fix to add explicit boolean handling
 func isDeclinedValue(val any) bool {
 	if val == nil {
 		return false
 	}
 	switch v := val.(type) {
 	case string:
 		v = strings.ToLower(strings.TrimSpace(v))
 		return v == "no" || v == "off" || v == "0" || v == "false"
+	case bool:
+		return !v
 	}
 	v := cast.ToInt(val)
 	return v == 0
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@validation/utils.go` around lines 423 - 435, isDeclinedValue currently treats
any non-string, non-bool/castable value as declined because cast.ToInt returns 0
for non-castable types; update isDeclinedValue to mirror isAcceptedValue's type
handling: add an explicit type switch to handle bool (return true for false),
numeric types (int/float -> compare to 0), and for any other non-castable types
return false instead of using cast.ToInt blindly; reference the isDeclinedValue
function and align behavior with isAcceptedValue to avoid treating
slices/maps/structs as "declined".
validation/rules.go (1)

973-985: Document the DNS lookup behavior of the active_url rule to inform users of I/O implications.

ruleActiveUrl performs a synchronous DNS lookup via resolver.LookupHost(). This blocking I/O operation can introduce latency on validation hot paths, potentially causing request timeouts if DNS resolution is slow. Consider adding documentation or code comments explaining this behavior so users understand the performance characteristics when using the active_url rule.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@validation/rules.go` around lines 973 - 985, The ruleActiveUrl function
performs a synchronous DNS lookup using net.Resolver.LookupHost which is
blocking I/O and can add latency to validation hot paths; add a clear code
comment above ruleActiveUrl describing that it performs a blocking DNS
resolution (via resolver.LookupHost / u.Hostname()), may block request handling,
can cause timeouts, and suggest alternatives (e.g., async/timeout-wrapped
validation, caching, or a non-networking variant) so callers are aware of the
performance implications.
validation/errors_test.go (1)

189-229: Consider adding a test case for Has() returning false on a non-existent field.

The current test only verifies Has("a") returns true when errors exist. Adding a case that checks Has("nonexistent") returns false would improve coverage.

💡 Suggested additional test case
 		{
 			describe:  "errors isn't empty",
 			data:      map[string]any{"c": "cc"},
 			rules:     map[string]any{"a": "required", "b": "required"},
 			filters:   map[string]any{"a": "trim", "b": "trim"},
 			expectRes: true,
 		},
+		{
+			describe:  "Has returns false for non-existent field",
+			data:      map[string]any{"c": "cc"},
+			rules:     map[string]any{"a": "required"},
+			filters:   map[string]any{"a": "trim"},
+			expectRes: true,
+		},
 	}

Then in the loop, add a check:

// Also verify Has returns false for non-existent field
assert.False(t, errors.Has("nonexistent"), test.describe)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@validation/errors_test.go` around lines 189 - 229, Add an assertion in
TestHas to verify that Errors().Has returns false for a non-existent field:
after creating the validator via NewValidation().Make and obtaining errors :=
validator.Errors(), keep the existing NotNil/Has("a") checks and also assert
that errors.Has("nonexistent") is false (or use assert.False) for the same test
cases where errors are present; this should reference the TestHas function, the
validator variable from Make, and the Errors().Has method so the new assertion
is added inside the t.Run subtest after errors is obtained.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@validation/errors_test.go`:
- Around line 189-229: Add an assertion in TestHas to verify that Errors().Has
returns false for a non-existent field: after creating the validator via
NewValidation().Make and obtaining errors := validator.Errors(), keep the
existing NotNil/Has("a") checks and also assert that errors.Has("nonexistent")
is false (or use assert.False) for the same test cases where errors are present;
this should reference the TestHas function, the validator variable from Make,
and the Errors().Has method so the new assertion is added inside the t.Run
subtest after errors is obtained.

In `@validation/rules.go`:
- Around line 973-985: The ruleActiveUrl function performs a synchronous DNS
lookup using net.Resolver.LookupHost which is blocking I/O and can add latency
to validation hot paths; add a clear code comment above ruleActiveUrl describing
that it performs a blocking DNS resolution (via resolver.LookupHost /
u.Hostname()), may block request handling, can cause timeouts, and suggest
alternatives (e.g., async/timeout-wrapped validation, caching, or a
non-networking variant) so callers are aware of the performance implications.

In `@validation/utils.go`:
- Around line 423-435: isDeclinedValue currently treats any non-string,
non-bool/castable value as declined because cast.ToInt returns 0 for
non-castable types; update isDeclinedValue to mirror isAcceptedValue's type
handling: add an explicit type switch to handle bool (return true for false),
numeric types (int/float -> compare to 0), and for any other non-castable types
return false instead of using cast.ToInt blindly; reference the isDeclinedValue
function and align behavior with isAcceptedValue to avoid treating
slices/maps/structs as "declined".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 352e082b-4f47-40c1-b900-404a39e90d84

📥 Commits

Reviewing files that changed from the base of the PR and between c0f099a and e52ab0e.

📒 Files selected for processing (14)
  • validation/benchmark_test.go
  • validation/errors_test.go
  • validation/filters.go
  • validation/filters_test.go
  • validation/messages.go
  • validation/options_test.go
  • validation/rules.go
  • validation/rules_test.go
  • validation/service_provider.go
  • validation/utils.go
  • validation/utils_test.go
  • validation/validation.go
  • validation/validation_test.go
  • validation/validator_test.go

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 17, 2026

Codecov Report

❌ Patch coverage is 74.62451% with 321 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.82%. Comparing base (c0f099a) to head (0057053).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
validation/rules.go 70.45% 196 Missing and 98 partials ⚠️
validation/utils.go 89.86% 12 Missing and 3 partials ⚠️
validation/filters.go 93.61% 3 Missing and 3 partials ⚠️
validation/engine.go 80.76% 5 Missing ⚠️
validation/service_provider.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1416      +/-   ##
==========================================
+ Coverage   65.94%   67.82%   +1.87%     
==========================================
  Files         353      354       +1     
  Lines       26083    27345    +1262     
==========================================
+ Hits        17201    18546    +1345     
+ Misses       8141     7952     -189     
- Partials      741      847     +106     

☔ 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
Copy Markdown
Contributor

@hwbrzzl hwbrzzl left a comment

Choose a reason for hiding this comment

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

Thanks, awesome. Only a few questions.

Comment thread validation/rules.go
}
}
}
return false
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How about []int, []float, etc.?

Copy link
Copy Markdown
Contributor Author

@h2zi h2zi Mar 19, 2026

Choose a reason for hiding this comment

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

ruleArray 使用 reflect.ValueOf(val).Kind(), 所以 []int, []float64, []string 之类的会返回 reflect.Slice,已经支持了。

reflect.ValueOf([]int{1,2}).Kind()     // reflect.Slice ✓
reflect.ValueOf([]float64{}).Kind()    // reflect.Slice ✓
reflect.ValueOf([3]int{}).Kind()       // reflect.Array ✓

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

已有 []int, []string 的测试用例,补充了 []float64, []bool, [3]int(固定长度数组)的 case,全部通过。

ruleArray 使用 reflect.ValueOf(val).Kind(),Go 的所有切片类型([]int, []float64, []bool 等)Kind 都是 reflect.Slice,固定数组 [N]T 的 Kind 是 reflect.Array,都已覆盖。

Comment thread validation/rules.go
// numericRuleNames are rules that indicate a field should be treated as numeric for size rules.
var numericRuleNames = map[string]bool{}
var numericRuleNames = map[string]bool{
"numeric": true, "integer": true, "decimal": true,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

numeric alias rules are incomplete for size/type resolution (int, uint, float are missing from numericRuleNames), so size/comparison rules can be evaluated as string-length instead of numeric value when alias rules are used with string inputs.

Example impact: int|max:3 with "42" can pass via string length (2 <= 3) instead of failing numerically (42 <= 3).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch! 已将 int, uint, float 加入 numericRuleNames,并补充了 TestNumericAliasesWithSizeRules 测试覆盖这个场景。

关键 case: int|max:3 + "42" 现在正确按数值 42 > 3 判断失败,而不是按字符串长度 2 <= 3 通过。

Comment thread validation/rules_test.go Outdated
rules map[string]any
fails bool
}{
{"pass_google", map[string]any{"u": "https://google.com"}, map[string]any{"u": "active_url"}, false},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

https://goravel.dev can be used here instead of https://google.com, given google can't be visit in Mainland China.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, 已改为 https://goravel.dev

h2zi and others added 3 commits March 19, 2026 14:50
- Add int, uint, float to numericRuleNames for correct size resolution
- Replace google.com with goravel.dev in active_url test
- Add explicit bool handling in isAcceptedValue/isDeclinedValue
- Add DNS lookup comment on ruleActiveUrl
- Add Has("nonexistent") assertion in TestHas

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verify int, uint, float aliases resolve size rules as numeric values
instead of string length (e.g. int|max:3 with "42" correctly fails).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover []float64, []bool, and [N]int fixed array types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@h2zi h2zi enabled auto-merge (squash) March 19, 2026 06:56
Copy link
Copy Markdown
Contributor

@hwbrzzl hwbrzzl left a comment

Choose a reason for hiding this comment

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

LGTM, could you help optimize goravel/gin and goravel/fiber as well? And FYI, I created a PR to test the original validation, and will test the new one using the test cases once goravel/gin and goravel/fiber are completed: goravel/example#111

@h2zi h2zi merged commit 7cd523f into master Mar 19, 2026
18 checks passed
@h2zi h2zi deleted the haozi/validation-rules branch March 19, 2026 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ensure Full Compatibility with Laravel Validation API

2 participants