Skip to content

Commit dfe2abb

Browse files
committed
Refactor the NotEmoji rule
Since we have the ability to use `not` as a prefix, having rules that validate negative behaviour makes them a bit inflexible, verbose, and harder to understand. This commit will refactor the `NotEmoji` and rename it to `Emoji`. It will no longer check if the string contains emojis, but rather if the string is an emoji or not. I’m also adding support to more emojis, since the rule was a bit outdated. This change will make the validator more strict, but will make it useful in other scenarios. However, later on, I would like to create a rule called `has` which, could use a validator like `Emoji` to check if the input _has_ emojis.
1 parent a37cac7 commit dfe2abb

26 files changed

+344
-394
lines changed

bin/create-mixin

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,31 @@ require __DIR__ . '/../vendor/autoload.php';
88
use Nette\PhpGenerator\InterfaceType;
99
use Nette\PhpGenerator\PhpNamespace;
1010
use Nette\PhpGenerator\Printer;
11-
use Respect\Validation\Exceptions\ValidationException;
12-
use Respect\Validation\Mixins\KeyChain;
13-
use Respect\Validation\Mixins\LengthChain;
14-
use Respect\Validation\Mixins\MaxChain;
15-
use Respect\Validation\Mixins\MinChain;
16-
use Respect\Validation\Mixins\NotChain;
17-
use Respect\Validation\Mixins\NullOrChain;
18-
use Respect\Validation\Mixins\PropertyChain;
19-
use Respect\Validation\Mixins\UndefOrChain;
2011
use Respect\Validation\Mixins\Chain;
2112
use Respect\Validation\Mixins\KeyBuilder;
13+
use Respect\Validation\Mixins\KeyChain;
2214
use Respect\Validation\Mixins\LengthBuilder;
15+
use Respect\Validation\Mixins\LengthChain;
2316
use Respect\Validation\Mixins\MaxBuilder;
17+
use Respect\Validation\Mixins\MaxChain;
2418
use Respect\Validation\Mixins\MinBuilder;
19+
use Respect\Validation\Mixins\MinChain;
2520
use Respect\Validation\Mixins\NotBuilder;
21+
use Respect\Validation\Mixins\NotChain;
2622
use Respect\Validation\Mixins\NullOrBuilder;
23+
use Respect\Validation\Mixins\NullOrChain;
2724
use Respect\Validation\Mixins\PropertyBuilder;
25+
use Respect\Validation\Mixins\PropertyChain;
2826
use Respect\Validation\Mixins\UndefOrBuilder;
29-
use Respect\Validation\Rules\Undef;
30-
use Respect\Validation\Rules\NullOr;
31-
use Respect\Validation\Rules\UndefOr;
27+
use Respect\Validation\Mixins\UndefOrChain;
3228
use Respect\Validation\Rule;
29+
use Respect\Validation\Validator;
3330

3431
function addMethodToInterface(
3532
string $originalName,
3633
InterfaceType $interfaceType,
3734
ReflectionClass $reflection,
38-
?string $prefix,
35+
string|null $prefix,
3936
array $allowList,
4037
array $denyList,
4138
): void {
@@ -65,6 +62,7 @@ function addMethodToInterface(
6562
if ($reflrectionConstructor === null) {
6663
return;
6764
}
65+
6866
$commend = $reflrectionConstructor->getDocComment();
6967
if ($commend) {
7068
$method->addComment(preg_replace('@(/\*\* *| +\* +| +\*/)@', '', $commend));
@@ -83,13 +81,15 @@ function addMethodToInterface(
8381
}
8482
} elseif ($type instanceof ReflectionNamedType) {
8583
$types[] = $type->getName();
86-
if ( str_starts_with($type->getName(), 'Sokil')
84+
if (
85+
str_starts_with($type->getName(), 'Sokil')
8786
|| str_starts_with($type->getName(), 'Egulias')
8887
|| $type->getName() === 'finfo'
8988
) {
9089
continue;
9190
}
9291
}
92+
9393
$parameter = $method->addParameter($reflectionParameter->getName());
9494
$parameter->setType(implode('|', $types));
9595

@@ -121,7 +121,7 @@ function overwriteFile(string $content, string $basename): void
121121
{
122122
file_put_contents(sprintf('%s/../library/Mixins/%s.php', __DIR__, $basename), implode(PHP_EOL . PHP_EOL, [
123123
'<?php',
124-
file_get_contents(__DIR__.'/../.docheader'),
124+
file_get_contents(__DIR__ . '/../.docheader'),
125125
'declare(strict_types=1);',
126126
preg_replace('/extends (.+, )+/', 'extends' . PHP_EOL . '\1', $content),
127127
]));
@@ -172,7 +172,7 @@ function overwriteFile(string $content, string $basename): void
172172
['Length', 'length', $numberRelatedRules, []],
173173
['Max', 'max', $numberRelatedRules, []],
174174
['Min', 'min', $numberRelatedRules, []],
175-
['Not', 'not', [], ['Not', 'NotEmpty', 'NotEmoji', 'NullOr', 'UndefOr', 'Attributes', 'Templated', 'Named']],
175+
['Not', 'not', [], ['Not', 'NotEmpty', 'NullOr', 'UndefOr', 'Attributes', 'Templated', 'Named']],
176176
['NullOr', 'nullOr', [], ['NullOr', 'Blank', 'Undef', 'UndefOr', 'Templated', 'Named']],
177177
['Property', 'property', [], $structureRelatedRules],
178178
['UndefOr', 'undefOr', [], ['NullOr', 'Blank', 'Undef', 'UndefOr', 'Attributes', 'Templated', 'Named']],
@@ -190,8 +190,10 @@ function overwriteFile(string $content, string $basename): void
190190
if ($reflection->isAbstract()) {
191191
continue;
192192
}
193+
193194
$names[$reflection->getShortName()] = $reflection;
194195
}
196+
195197
ksort($names);
196198

197199
foreach ($mixins as [$name, $prefix, $allowList, $denyList]) {
@@ -213,7 +215,7 @@ function overwriteFile(string $content, string $basename): void
213215
$chainedInterface->addExtend(NullOrChain::class);
214216
$chainedInterface->addExtend(PropertyChain::class);
215217
$chainedInterface->addExtend(UndefOrChain::class);
216-
$chainedInterface->addComment('@mixin \\' . \Respect\Validation\Validator::class);
218+
$chainedInterface->addComment('@mixin \\' . Validator::class);
217219

218220
$staticInterface->addExtend(KeyBuilder::class);
219221
$staticInterface->addExtend(LengthBuilder::class);
@@ -237,5 +239,5 @@ function overwriteFile(string $content, string $basename): void
237239
overwriteFile($printer->printNamespace($chainedNamespace), $chainedInterface->getName());
238240
}
239241

240-
shell_exec(__DIR__.'/../vendor/bin/phpcbf');
242+
shell_exec(__DIR__ . '/../vendor/bin/phpcbf ' . __DIR__ . '/../library/Mixins');
241243
})();

docs/09-list-of-rules-by-category.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,13 @@
229229
- [ContainsAny](rules/ContainsAny.md)
230230
- [Control](rules/Control.md)
231231
- [Digit](rules/Digit.md)
232+
- [Emoji](rules/Emoji.md)
232233
- [EndsWith](rules/EndsWith.md)
233234
- [Graph](rules/Graph.md)
234235
- [HexRgbColor](rules/HexRgbColor.md)
235236
- [In](rules/In.md)
236237
- [Json](rules/Json.md)
237238
- [Lowercase](rules/Lowercase.md)
238-
- [NotEmoji](rules/NotEmoji.md)
239239
- [Phone](rules/Phone.md)
240240
- [PhpLabel](rules/PhpLabel.md)
241241
- [PostalCode](rules/PostalCode.md)
@@ -344,6 +344,7 @@
344344
- [Domain](rules/Domain.md)
345345
- [Each](rules/Each.md)
346346
- [Email](rules/Email.md)
347+
- [Emoji](rules/Emoji.md)
347348
- [EndsWith](rules/EndsWith.md)
348349
- [Equals](rules/Equals.md)
349350
- [Equivalent](rules/Equivalent.md)
@@ -404,7 +405,6 @@
404405
- [No](rules/No.md)
405406
- [NoneOf](rules/NoneOf.md)
406407
- [Not](rules/Not.md)
407-
- [NotEmoji](rules/NotEmoji.md)
408408
- [NotEmpty](rules/NotEmpty.md)
409409
- [NullOr](rules/NullOr.md)
410410
- [NullType](rules/NullType.md)

docs/rules/Alnum.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ See also:
7070
- [Control](Control.md)
7171
- [Decimal](Decimal.md)
7272
- [Digit](Digit.md)
73+
- [Emoji](Emoji.md)
7374
- [Lowercase](Lowercase.md)
74-
- [NotEmoji](NotEmoji.md)
7575
- [Regex](Regex.md)
7676
- [Spaced](Spaced.md)
7777
- [StringType](StringType.md)

docs/rules/Alpha.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ See also:
6464
- [Consonant](Consonant.md)
6565
- [Decimal](Decimal.md)
6666
- [Digit](Digit.md)
67+
- [Emoji](Emoji.md)
6768
- [Lowercase](Lowercase.md)
68-
- [NotEmoji](NotEmoji.md)
6969
- [Regex](Regex.md)
7070
- [Spaced](Spaced.md)
7171
- [Uppercase](Uppercase.md)

docs/rules/Decimal.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ See also:
5555
- [Alpha](Alpha.md)
5656
- [Consonant](Consonant.md)
5757
- [CreditCard](CreditCard.md)
58+
- [Emoji](Emoji.md)
5859
- [Factor](Factor.md)
5960
- [Finite](Finite.md)
6061
- [Infinite](Infinite.md)
6162
- [IntType](IntType.md)
6263
- [IntVal](IntVal.md)
63-
- [NotEmoji](NotEmoji.md)
6464
- [NumericVal](NumericVal.md)
6565
- [Regex](Regex.md)
6666
- [Uuid](Uuid.md)

docs/rules/Digit.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ See also:
5656
- [Alpha](Alpha.md)
5757
- [Consonant](Consonant.md)
5858
- [CreditCard](CreditCard.md)
59+
- [Emoji](Emoji.md)
5960
- [Factor](Factor.md)
6061
- [Finite](Finite.md)
6162
- [Infinite](Infinite.md)
6263
- [IntType](IntType.md)
6364
- [IntVal](IntVal.md)
64-
- [NotEmoji](NotEmoji.md)
6565
- [NumericVal](NumericVal.md)
6666
- [Regex](Regex.md)
6767
- [Uuid](Uuid.md)

docs/rules/Emoji.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Emoji
2+
3+
- `v::emoji()`
4+
5+
Validates if the input is an emoji or a sequence of emojis.
6+
7+
```php
8+
v::emoji()->isValid('🍕'); // true
9+
v::emoji()->isValid('🎈'); // true
10+
v::emoji()->isValid('⚡'); // true
11+
v::emoji()->isValid('🌊🌊🌊🌊🌊🏄🌊🌊🌊🏖🌴'); // true
12+
v::emoji()->isValid('🇧🇷'); // true (country flag)
13+
v::emoji()->isValid('👨‍👩‍👧‍👦'); // true (ZWJ sequence)
14+
v::emoji()->isValid('👩🏽'); // true (skin tone modifier)
15+
v::emoji()->isValid('1️⃣'); // true (keycap sequence)
16+
v::emoji()->isValid('Hello World'); // false
17+
v::emoji()->isValid('this is a spark ⚡'); // false (mixed content)
18+
```
19+
20+
This validator supports:
21+
22+
- Basic emojis and pictographs
23+
- Skin tone modifiers (Fitzpatrick scale)
24+
- Country flags (regional indicator sequences)
25+
- Subdivision flags (tag sequences like 🏴󠁧󠁢󠁥󠁮󠁧󠁿)
26+
- Keycap sequences (0️⃣-9️⃣, #️⃣, \*️⃣)
27+
- ZWJ (Zero Width Joiner) sequences for families, professions, and combined emojis
28+
- Emojis up to Unicode 17.0 / Emoji 16.0
29+
30+
## Templates
31+
32+
### `Emoji::TEMPLATE_STANDARD`
33+
34+
| Mode | Template |
35+
| ---------- | -------------------------------- |
36+
| `default` | {{subject}} must be an emoji |
37+
| `inverted` | {{subject}} must not be an emoji |
38+
39+
## Template placeholders
40+
41+
| Placeholder | Description |
42+
| ----------- | ---------------------------------------------------------------- |
43+
| `subject` | The validated input or the custom validator name (if specified). |
44+
45+
## Categorization
46+
47+
- Strings
48+
49+
## Changelog
50+
51+
| Version | Description |
52+
| ------: | ------------------------------------------------------------------------ |
53+
| 3.0.0 | Renamed to `Emoji`, changed the behavior, and add support to more emojis |
54+
| 2.0.0 | Created as `NotEmoji` |
55+
56+
---
57+
58+
See also:
59+
60+
- [Alnum](Alnum.md)
61+
- [Alpha](Alpha.md)
62+
- [Decimal](Decimal.md)
63+
- [Digit](Digit.md)

docs/rules/NotEmoji.md

Lines changed: 0 additions & 57 deletions
This file was deleted.

library/Mixins/Builder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ public static function noneOf(Rule $rule1, Rule $rule2, Rule ...$rules): Chain;
242242

243243
public static function not(Rule $rule): Chain;
244244

245-
public static function notEmoji(): Chain;
245+
public static function emoji(): Chain;
246246

247247
public static function notEmpty(): Chain;
248248

library/Mixins/Chain.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ public function noneOf(Rule $rule1, Rule $rule2, Rule ...$rules): Chain;
245245

246246
public function not(Rule $rule): Chain;
247247

248-
public function notEmoji(): Chain;
248+
public function emoji(): Chain;
249249

250250
public function notEmpty(): Chain;
251251

0 commit comments

Comments
 (0)