From e2a5164343b84a70ba1c73cd3fc11d36dd352413 Mon Sep 17 00:00:00 2001
From: Divyanshu Bhargava
Date: Fri, 15 May 2026 15:32:17 +0530
Subject: [PATCH 1/3] feat: add 21 validators and a sanitizers module for
validator.js parity
Expands the package toward validator.js coverage by adding 21 new
validators (isLowercase, isUppercase, isHexadecimal, isOctal, isDecimal,
isFloat, isMongoId, isMD5, isPort, isSemVer, isSlug, isMACAddress,
isLatLong, isJWT, isFQDN, isBase64, isByteLength, isStrongPassword, isIn,
matches, contains) and a new sanitizers module (trim, ltrim, rtrim,
escape, unescape, blacklist, whitelist, stripLow, normalizeEmail,
toBoolean, toInt, toFloat, toDate).
Each new validator is wired into all three APIs (top-level function,
String extension, Validator form method). Adds test coverage for every
new validator and sanitizer, plus the 38 previously-untested Validator
form methods.
---
CHANGELOG.md | 12 +
README.md | 78 ++++-
lib/flutter_validators.dart | 35 ++-
lib/form_validator.dart | 180 ++++++++++++
lib/sanitizers.dart | 13 +
lib/validators/base64.dart | 34 +++
lib/validators/byte_length.dart | 28 ++
lib/validators/contains.dart | 25 ++
lib/validators/decimal.dart | 28 ++
lib/validators/float.dart | 30 ++
lib/validators/fqdn.dart | 43 +++
lib/validators/hexadecimal.dart | 26 ++
lib/validators/in.dart | 20 ++
lib/validators/ip.dart | 8 +-
lib/validators/jwt.dart | 31 ++
lib/validators/lat_long.dart | 30 ++
lib/validators/lowercase.dart | 25 ++
lib/validators/mac_address.dart | 32 +++
lib/validators/matches.dart | 23 ++
lib/validators/md5.dart | 24 ++
lib/validators/mongo_id.dart | 25 ++
lib/validators/octal.dart | 26 ++
lib/validators/port.dart | 27 ++
lib/validators/sanitizers/blacklist.dart | 35 +++
lib/validators/sanitizers/escape.dart | 52 ++++
.../sanitizers/normalize_email.dart | 42 +++
lib/validators/sanitizers/strip_low.dart | 29 ++
lib/validators/sanitizers/to_boolean.dart | 26 ++
lib/validators/sanitizers/to_number.dart | 46 +++
lib/validators/sanitizers/trim.dart | 62 ++++
lib/validators/semver.dart | 32 +++
lib/validators/slug.dart | 27 ++
lib/validators/strong_password.dart | 69 +++++
lib/validators/uppercase.dart | 25 ++
lib/validators/url.dart | 4 +-
lib/validators/uuid.dart | 4 +-
pubspec.yaml | 2 +-
test/form_validator_test.dart | 267 +++++++++++++++++-
test/validators/base32_test.dart | 2 +-
test/validators/base58_test.dart | 10 +-
test/validators/base64_test.dart | 23 ++
test/validators/byte_length_test.dart | 19 ++
test/validators/contains_test.dart | 26 ++
test/validators/decimal_test.dart | 21 ++
test/validators/float_test.dart | 25 ++
test/validators/fqdn_test.dart | 21 ++
test/validators/hexadecimal_test.dart | 21 ++
test/validators/in_test.dart | 18 ++
test/validators/jwt_test.dart | 20 ++
test/validators/lat_long_test.dart | 22 ++
test/validators/lowercase_test.dart | 20 ++
test/validators/mac_address_test.dart | 21 ++
test/validators/matches_test.dart | 17 ++
test/validators/md5_test.dart | 18 ++
test/validators/mongo_id_test.dart | 19 ++
test/validators/octal_test.dart | 20 ++
test/validators/port_test.dart | 22 ++
.../validators/sanitizers/blacklist_test.dart | 16 ++
test/validators/sanitizers/escape_test.dart | 21 ++
.../sanitizers/normalize_email_test.dart | 20 ++
.../validators/sanitizers/strip_low_test.dart | Bin 0 -> 487 bytes
.../sanitizers/to_boolean_test.dart | 20 ++
.../validators/sanitizers/to_number_test.dart | 25 ++
test/validators/sanitizers/trim_test.dart | 24 ++
test/validators/semver_test.dart | 22 ++
test/validators/slug_test.dart | 22 ++
test/validators/strong_password_test.dart | 38 +++
test/validators/uppercase_test.dart | 20 ++
test/validators/uuid_test.dart | 72 ++++-
69 files changed, 2155 insertions(+), 35 deletions(-)
create mode 100644 lib/sanitizers.dart
create mode 100644 lib/validators/base64.dart
create mode 100644 lib/validators/byte_length.dart
create mode 100644 lib/validators/contains.dart
create mode 100644 lib/validators/decimal.dart
create mode 100644 lib/validators/float.dart
create mode 100644 lib/validators/fqdn.dart
create mode 100644 lib/validators/hexadecimal.dart
create mode 100644 lib/validators/in.dart
create mode 100644 lib/validators/jwt.dart
create mode 100644 lib/validators/lat_long.dart
create mode 100644 lib/validators/lowercase.dart
create mode 100644 lib/validators/mac_address.dart
create mode 100644 lib/validators/matches.dart
create mode 100644 lib/validators/md5.dart
create mode 100644 lib/validators/mongo_id.dart
create mode 100644 lib/validators/octal.dart
create mode 100644 lib/validators/port.dart
create mode 100644 lib/validators/sanitizers/blacklist.dart
create mode 100644 lib/validators/sanitizers/escape.dart
create mode 100644 lib/validators/sanitizers/normalize_email.dart
create mode 100644 lib/validators/sanitizers/strip_low.dart
create mode 100644 lib/validators/sanitizers/to_boolean.dart
create mode 100644 lib/validators/sanitizers/to_number.dart
create mode 100644 lib/validators/sanitizers/trim.dart
create mode 100644 lib/validators/semver.dart
create mode 100644 lib/validators/slug.dart
create mode 100644 lib/validators/strong_password.dart
create mode 100644 lib/validators/uppercase.dart
create mode 100644 test/validators/base64_test.dart
create mode 100644 test/validators/byte_length_test.dart
create mode 100644 test/validators/contains_test.dart
create mode 100644 test/validators/decimal_test.dart
create mode 100644 test/validators/float_test.dart
create mode 100644 test/validators/fqdn_test.dart
create mode 100644 test/validators/hexadecimal_test.dart
create mode 100644 test/validators/in_test.dart
create mode 100644 test/validators/jwt_test.dart
create mode 100644 test/validators/lat_long_test.dart
create mode 100644 test/validators/lowercase_test.dart
create mode 100644 test/validators/mac_address_test.dart
create mode 100644 test/validators/matches_test.dart
create mode 100644 test/validators/md5_test.dart
create mode 100644 test/validators/mongo_id_test.dart
create mode 100644 test/validators/octal_test.dart
create mode 100644 test/validators/port_test.dart
create mode 100644 test/validators/sanitizers/blacklist_test.dart
create mode 100644 test/validators/sanitizers/escape_test.dart
create mode 100644 test/validators/sanitizers/normalize_email_test.dart
create mode 100644 test/validators/sanitizers/strip_low_test.dart
create mode 100644 test/validators/sanitizers/to_boolean_test.dart
create mode 100644 test/validators/sanitizers/to_number_test.dart
create mode 100644 test/validators/sanitizers/trim_test.dart
create mode 100644 test/validators/semver_test.dart
create mode 100644 test/validators/slug_test.dart
create mode 100644 test/validators/strong_password_test.dart
create mode 100644 test/validators/uppercase_test.dart
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 165a771..2732955 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+## 1.2.0
+
+* Added 21 new validators inspired by validator.js: `isLowercase`, `isUppercase`,
+ `isHexadecimal`, `isOctal`, `isDecimal`, `isFloat`, `isMongoId`, `isMD5`,
+ `isPort`, `isSemVer`, `isSlug`, `isMACAddress`, `isLatLong`, `isJWT`, `isFQDN`,
+ `isBase64`, `isByteLength`, `isStrongPassword`, `isIn`, `matches` and `contains`.
+* Added a new sanitizers module (`package:flutter_validators/sanitizers.dart`):
+ `trim`, `ltrim`, `rtrim`, `escape`, `unescape`, `blacklist`, `whitelist`,
+ `stripLow`, `normalizeEmail`, `toBoolean`, `toInt`, `toFloat` and `toDate`.
+* Extended the `Validator` form class with methods for every new validator.
+* Added test coverage for all new validators and sanitizers.
+
## 1.1.0
* Major upgrade! Added 9 new standard validators (URL, UUID, Date, Numeric, Alpha, IP, Hex Color, Credit Card, Length).
diff --git a/README.md b/README.md
index f249ef4..0343d68 100644
--- a/README.md
+++ b/README.md
@@ -18,12 +18,12 @@
- Inspired by validator.js · 20+ validators · Works with Flutter Forms out of the box
+ Inspired by validator.js · 40+ validators & sanitizers · Works with Flutter Forms out of the box
---
-A pure Dart package with 20+ string validators and sanitizers, from emails and URLs to credit cards and UUIDs. Use them as simple functions, convenient `String` extensions, or plug them directly into Flutter's `TextFormField` with the built-in `Validator` class. Zero dependencies, fully tested.
+A pure Dart package with 40+ string validators and sanitizers, from emails and URLs to credit cards, UUIDs and strong-password checks. Use them as simple functions, convenient `String` extensions, or plug them directly into Flutter's `TextFormField` with the built-in `Validator` class. Zero dependencies, fully tested.
---
@@ -31,7 +31,7 @@ A pure Dart package with 20+ string validators and sanitizers, from emails and U
```yaml
dependencies:
- flutter_validators: ^1.1.0
+ flutter_validators: ^1.2.0
```
Then run:
@@ -120,12 +120,63 @@ Every validator is available **both** as a top-level function and as a `String`
| `isBase58(str)` | `str.isBase58` | Base58 encoded |
| `isBoolean(str)` | `str.isBoolean` | Boolean string (`true`/`false`/`1`/`0`) |
| `isHexColor(str)` | `str.isHexColor` | Hex color code (`#fff`, `ff0000`) |
+| `isHexadecimal(str)` | `str.isHexadecimal` | Hexadecimal number |
+| `isOctal(str)` | `str.isOctal` | Octal number |
+| `isDecimal(str)` | `str.isDecimal` | Decimal number |
+| `isFloat(str, {min, max})` | `str.isFloat({min, max})` | Finite float, optionally within range |
| `isPhone(str)` | `str.isPhone` | Valid phone number |
| `isLength(str, min, [max])` | `str.isLength(min, [max])` | Length within range |
+| `isByteLength(str, min, [max])` | `str.isByteLength(min, [max])` | UTF-8 byte length within range |
+| `isBase64(str, {urlSafe})` | `str.isBase64({urlSafe})` | Base64 encoded |
+| `isLowercase(str)` | `str.isLowercase` | Entirely lowercase |
+| `isUppercase(str)` | `str.isUppercase` | Entirely uppercase |
+| `isSlug(str)` | `str.isSlug` | URL slug |
+| `isFQDN(str)` | `str.isFQDN` | Fully qualified domain name |
+| `isMACAddress(str)` | `str.isMACAddress` | MAC address |
+| `isLatLong(str)` | `str.isLatLong` | `latitude,longitude` pair |
+| `isPort(str)` | `str.isPort` | Port number (0–65535) |
+| `isSemVer(str)` | `str.isSemVer` | Semantic version |
+| `isMongoId(str)` | `str.isMongoId` | MongoDB ObjectId |
+| `isMD5(str)` | `str.isMD5` | MD5 hash |
+| `isJWT(str)` | `str.isJWT` | JSON Web Token |
+| `isStrongPassword(str, {...})` | `str.isStrongPassword({...})` | Password meets strength rules |
+| `isIn(str, values)` | `str.isIn(values)` | One of the allowed values |
+| `matches(str, pattern)` | `str.matches(pattern)` | Matches a `Pattern`/`RegExp` |
+| `contains(str, seed, {ignoreCase, minOccurrences})` | — | Contains a substring |
| `equals(str, comparison)` | `str.equals(comparison)` | Exact string match |
---
+## 🧹 Sanitizers
+
+Sanitizers transform or coerce strings. Available both as top-level functions and `String` extensions.
+
+```dart
+trim(' hello '); // 'hello'
+escape('');
+// '<script>alert(1)</script>'
+
+unescape('<b>hi</b>'); // 'hi'
+```
+
+### Character Filtering
+
+| Sanitizer | Extension | Description |
+|---|---|---|
+| `blacklist(str, chars)` | `str.blacklist(chars)` | Remove the listed characters |
+| `whitelist(str, chars)` | `str.whitelist(chars)` | Keep only the listed characters |
+| `stripLow(str, {keepNewLines})` | `str.stripLow({keepNewLines})` | Remove ASCII control characters |
+
+```dart
+blacklist('hello world', 'lo'); // 'he wrd'
+whitelist('a1b2c3', '0123456789'); // '123'
+stripLow('line1\nline2'); // 'line1line2'
+stripLow('line1\nline2', keepNewLines: true); // 'line1\nline2'
+```
+
+### Type Conversion
+
+| Sanitizer | Extension | Returns | Description |
+|---|---|---|---|
+| `toBoolean(str, {strict})` | `str.toBoolean({strict})` | `bool` | Convert to a boolean |
+| `toInt(str, {radix})` | `str.toInt({radix})` | `int?` | Parse to an integer |
+| `toFloat(str)` | `str.toFloat()` | `double?` | Parse to a double |
+| `toDate(str)` | `str.toDate()` | `DateTime?` | Parse to a `DateTime` |
```dart
-trim(' hello '); // 'hello'
-escape('