@vituum/vite-plugin-latte 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/package.json +6 -6
  2. package/vendor/autoload.php +1 -1
  3. package/vendor/composer/autoload_classmap.php +49 -0
  4. package/vendor/composer/autoload_real.php +4 -4
  5. package/vendor/composer/autoload_static.php +51 -2
  6. package/vendor/composer/installed.json +102 -12
  7. package/vendor/composer/installed.php +14 -5
  8. package/vendor/latte/latte/composer.json +6 -5
  9. package/vendor/latte/latte/readme.md +27 -9
  10. package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.panel.phtml +4 -1
  11. package/vendor/latte/latte/src/Latte/Compiler/TagLexer.php +1 -1
  12. package/vendor/latte/latte/src/Latte/Compiler/TagParserData.php +129 -129
  13. package/vendor/latte/latte/src/Latte/Compiler/TemplateGenerator.php +1 -1
  14. package/vendor/latte/latte/src/Latte/Compiler/TemplateParser.php +1 -1
  15. package/vendor/latte/latte/src/Latte/Engine.php +22 -2
  16. package/vendor/latte/latte/src/Latte/Essential/CachingIterator.php +2 -3
  17. package/vendor/latte/latte/src/Latte/Essential/CoreExtension.php +9 -1
  18. package/vendor/latte/latte/src/Latte/Essential/Filters.php +110 -10
  19. package/vendor/latte/latte/src/Latte/Essential/Nodes/ImportNode.php +8 -2
  20. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarNode.php +14 -18
  21. package/vendor/latte/latte/src/Latte/Essential/TranslatorExtension.php +1 -1
  22. package/vendor/latte/latte/src/Latte/Loaders/FileLoader.php +5 -4
  23. package/vendor/latte/latte/src/Latte/Runtime/Template.php +1 -1
  24. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallNode.php +0 -1
  25. package/vendor/nette/utils/.phpstorm.meta.php +13 -0
  26. package/vendor/nette/utils/composer.json +51 -0
  27. package/vendor/nette/utils/license.md +60 -0
  28. package/vendor/nette/utils/readme.md +55 -0
  29. package/vendor/nette/utils/src/HtmlStringable.php +22 -0
  30. package/vendor/nette/utils/src/Iterators/CachingIterator.php +150 -0
  31. package/vendor/nette/utils/src/Iterators/Mapper.php +33 -0
  32. package/vendor/nette/utils/src/SmartObject.php +140 -0
  33. package/vendor/nette/utils/src/StaticClass.php +34 -0
  34. package/vendor/nette/utils/src/Translator.php +25 -0
  35. package/vendor/nette/utils/src/Utils/ArrayHash.php +106 -0
  36. package/vendor/nette/utils/src/Utils/ArrayList.php +136 -0
  37. package/vendor/nette/utils/src/Utils/Arrays.php +553 -0
  38. package/vendor/nette/utils/src/Utils/Callback.php +137 -0
  39. package/vendor/nette/utils/src/Utils/DateTime.php +140 -0
  40. package/vendor/nette/utils/src/Utils/FileInfo.php +69 -0
  41. package/vendor/nette/utils/src/Utils/FileSystem.php +326 -0
  42. package/vendor/nette/utils/src/Utils/Finder.php +510 -0
  43. package/vendor/nette/utils/src/Utils/Floats.php +107 -0
  44. package/vendor/nette/utils/src/Utils/Helpers.php +104 -0
  45. package/vendor/nette/utils/src/Utils/Html.php +839 -0
  46. package/vendor/nette/utils/src/Utils/Image.php +831 -0
  47. package/vendor/nette/utils/src/Utils/ImageColor.php +75 -0
  48. package/vendor/nette/utils/src/Utils/ImageType.php +25 -0
  49. package/vendor/nette/utils/src/Utils/Iterables.php +238 -0
  50. package/vendor/nette/utils/src/Utils/Json.php +84 -0
  51. package/vendor/nette/utils/src/Utils/ObjectHelpers.php +229 -0
  52. package/vendor/nette/utils/src/Utils/Paginator.php +245 -0
  53. package/vendor/nette/utils/src/Utils/Random.php +52 -0
  54. package/vendor/nette/utils/src/Utils/Reflection.php +322 -0
  55. package/vendor/nette/utils/src/Utils/ReflectionMethod.php +36 -0
  56. package/vendor/nette/utils/src/Utils/Strings.php +728 -0
  57. package/vendor/nette/utils/src/Utils/Type.php +267 -0
  58. package/vendor/nette/utils/src/Utils/Validators.php +416 -0
  59. package/vendor/nette/utils/src/Utils/exceptions.php +50 -0
  60. package/vendor/nette/utils/src/compatibility.php +32 -0
  61. package/vendor/nette/utils/src/exceptions.php +109 -0
@@ -0,0 +1,267 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Nette Framework (https://nette.org)
5
+ * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Nette\Utils;
11
+
12
+ use Nette;
13
+
14
+
15
+ /**
16
+ * PHP type reflection.
17
+ */
18
+ final class Type
19
+ {
20
+ /** @var array<int, string|self> */
21
+ private array $types;
22
+ private bool $simple;
23
+ private string $kind; // | &
24
+
25
+
26
+ /**
27
+ * Creates a Type object based on reflection. Resolves self, static and parent to the actual class name.
28
+ * If the subject has no type, it returns null.
29
+ */
30
+ public static function fromReflection(
31
+ \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection,
32
+ ): ?self
33
+ {
34
+ $type = $reflection instanceof \ReflectionFunctionAbstract
35
+ ? $reflection->getReturnType() ?? (PHP_VERSION_ID >= 80100 && $reflection instanceof \ReflectionMethod ? $reflection->getTentativeReturnType() : null)
36
+ : $reflection->getType();
37
+
38
+ return $type ? self::fromReflectionType($type, $reflection, asObject: true) : null;
39
+ }
40
+
41
+
42
+ private static function fromReflectionType(\ReflectionType $type, $of, bool $asObject): self|string
43
+ {
44
+ if ($type instanceof \ReflectionNamedType) {
45
+ $name = self::resolve($type->getName(), $of);
46
+ return $asObject
47
+ ? new self($type->allowsNull() && $name !== 'mixed' ? [$name, 'null'] : [$name])
48
+ : $name;
49
+
50
+ } elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) {
51
+ return new self(
52
+ array_map(fn($t) => self::fromReflectionType($t, $of, asObject: false), $type->getTypes()),
53
+ $type instanceof \ReflectionUnionType ? '|' : '&',
54
+ );
55
+
56
+ } else {
57
+ throw new Nette\InvalidStateException('Unexpected type of ' . Reflection::toString($of));
58
+ }
59
+ }
60
+
61
+
62
+ /**
63
+ * Creates the Type object according to the text notation.
64
+ */
65
+ public static function fromString(string $type): self
66
+ {
67
+ if (!Validators::isTypeDeclaration($type)) {
68
+ throw new Nette\InvalidArgumentException("Invalid type '$type'.");
69
+ }
70
+
71
+ if ($type[0] === '?') {
72
+ return new self([substr($type, 1), 'null']);
73
+ }
74
+
75
+ $unions = [];
76
+ foreach (explode('|', $type) as $part) {
77
+ $part = explode('&', trim($part, '()'));
78
+ $unions[] = count($part) === 1 ? $part[0] : new self($part, '&');
79
+ }
80
+
81
+ return count($unions) === 1 && $unions[0] instanceof self
82
+ ? $unions[0]
83
+ : new self($unions);
84
+ }
85
+
86
+
87
+ /**
88
+ * Resolves 'self', 'static' and 'parent' to the actual class name.
89
+ */
90
+ public static function resolve(
91
+ string $type,
92
+ \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $of,
93
+ ): string
94
+ {
95
+ $lower = strtolower($type);
96
+ if ($of instanceof \ReflectionFunction) {
97
+ return $type;
98
+ } elseif ($lower === 'self') {
99
+ return $of->getDeclaringClass()->name;
100
+ } elseif ($lower === 'static') {
101
+ return ($of instanceof ReflectionMethod ? $of->getOriginalClass() : $of->getDeclaringClass())->name;
102
+ } elseif ($lower === 'parent' && $of->getDeclaringClass()->getParentClass()) {
103
+ return $of->getDeclaringClass()->getParentClass()->name;
104
+ } else {
105
+ return $type;
106
+ }
107
+ }
108
+
109
+
110
+ private function __construct(array $types, string $kind = '|')
111
+ {
112
+ $o = array_search('null', $types, strict: true);
113
+ if ($o !== false) { // null as last
114
+ array_splice($types, $o, 1);
115
+ $types[] = 'null';
116
+ }
117
+
118
+ $this->types = $types;
119
+ $this->simple = is_string($types[0]) && ($types[1] ?? 'null') === 'null';
120
+ $this->kind = count($types) > 1 ? $kind : '';
121
+ }
122
+
123
+
124
+ public function __toString(): string
125
+ {
126
+ $multi = count($this->types) > 1;
127
+ if ($this->simple) {
128
+ return ($multi ? '?' : '') . $this->types[0];
129
+ }
130
+
131
+ $res = [];
132
+ foreach ($this->types as $type) {
133
+ $res[] = $type instanceof self && $multi ? "($type)" : $type;
134
+ }
135
+ return implode($this->kind, $res);
136
+ }
137
+
138
+
139
+ /**
140
+ * Returns the array of subtypes that make up the compound type as strings.
141
+ * @return array<int, string|string[]>
142
+ */
143
+ public function getNames(): array
144
+ {
145
+ return array_map(fn($t) => $t instanceof self ? $t->getNames() : $t, $this->types);
146
+ }
147
+
148
+
149
+ /**
150
+ * Returns the array of subtypes that make up the compound type as Type objects:
151
+ * @return self[]
152
+ */
153
+ public function getTypes(): array
154
+ {
155
+ return array_map(fn($t) => $t instanceof self ? $t : new self([$t]), $this->types);
156
+ }
157
+
158
+
159
+ /**
160
+ * Returns the type name for simple types, otherwise null.
161
+ */
162
+ public function getSingleName(): ?string
163
+ {
164
+ return $this->simple
165
+ ? $this->types[0]
166
+ : null;
167
+ }
168
+
169
+
170
+ /**
171
+ * Returns true whether it is a union type.
172
+ */
173
+ public function isUnion(): bool
174
+ {
175
+ return $this->kind === '|';
176
+ }
177
+
178
+
179
+ /**
180
+ * Returns true whether it is an intersection type.
181
+ */
182
+ public function isIntersection(): bool
183
+ {
184
+ return $this->kind === '&';
185
+ }
186
+
187
+
188
+ /**
189
+ * Returns true whether it is a simple type. Single nullable types are also considered to be simple types.
190
+ */
191
+ public function isSimple(): bool
192
+ {
193
+ return $this->simple;
194
+ }
195
+
196
+
197
+ /** @deprecated use isSimple() */
198
+ public function isSingle(): bool
199
+ {
200
+ return $this->simple;
201
+ }
202
+
203
+
204
+ /**
205
+ * Returns true whether the type is both a simple and a PHP built-in type.
206
+ */
207
+ public function isBuiltin(): bool
208
+ {
209
+ return $this->simple && Validators::isBuiltinType($this->types[0]);
210
+ }
211
+
212
+
213
+ /**
214
+ * Returns true whether the type is both a simple and a class name.
215
+ */
216
+ public function isClass(): bool
217
+ {
218
+ return $this->simple && !Validators::isBuiltinType($this->types[0]);
219
+ }
220
+
221
+
222
+ /**
223
+ * Determines if type is special class name self/parent/static.
224
+ */
225
+ public function isClassKeyword(): bool
226
+ {
227
+ return $this->simple && Validators::isClassKeyword($this->types[0]);
228
+ }
229
+
230
+
231
+ /**
232
+ * Verifies type compatibility. For example, it checks if a value of a certain type could be passed as a parameter.
233
+ */
234
+ public function allows(string $subtype): bool
235
+ {
236
+ if ($this->types === ['mixed']) {
237
+ return true;
238
+ }
239
+
240
+ $subtype = self::fromString($subtype);
241
+ return $subtype->isUnion()
242
+ ? Arrays::every($subtype->types, fn($t) => $this->allows2($t instanceof self ? $t->types : [$t]))
243
+ : $this->allows2($subtype->types);
244
+ }
245
+
246
+
247
+ private function allows2(array $subtypes): bool
248
+ {
249
+ return $this->isUnion()
250
+ ? Arrays::some($this->types, fn($t) => $this->allows3($t instanceof self ? $t->types : [$t], $subtypes))
251
+ : $this->allows3($this->types, $subtypes);
252
+ }
253
+
254
+
255
+ private function allows3(array $types, array $subtypes): bool
256
+ {
257
+ return Arrays::every(
258
+ $types,
259
+ fn($type) => Arrays::some(
260
+ $subtypes,
261
+ fn($subtype) => Validators::isBuiltinType($type)
262
+ ? strcasecmp($type, $subtype) === 0
263
+ : is_a($subtype, $type, allow_string: true)
264
+ )
265
+ );
266
+ }
267
+ }
@@ -0,0 +1,416 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Nette Framework (https://nette.org)
5
+ * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Nette\Utils;
11
+
12
+ use Nette;
13
+
14
+
15
+ /**
16
+ * Validation utilities.
17
+ */
18
+ class Validators
19
+ {
20
+ use Nette\StaticClass;
21
+
22
+ private const BuiltinTypes = [
23
+ 'string' => 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1,
24
+ 'callable' => 1, 'iterable' => 1, 'void' => 1, 'null' => 1, 'mixed' => 1, 'false' => 1,
25
+ 'never' => 1, 'true' => 1,
26
+ ];
27
+
28
+ /** @var array<string,?callable> */
29
+ protected static $validators = [
30
+ // PHP types
31
+ 'array' => 'is_array',
32
+ 'bool' => 'is_bool',
33
+ 'boolean' => 'is_bool',
34
+ 'float' => 'is_float',
35
+ 'int' => 'is_int',
36
+ 'integer' => 'is_int',
37
+ 'null' => 'is_null',
38
+ 'object' => 'is_object',
39
+ 'resource' => 'is_resource',
40
+ 'scalar' => 'is_scalar',
41
+ 'string' => 'is_string',
42
+
43
+ // pseudo-types
44
+ 'callable' => [self::class, 'isCallable'],
45
+ 'iterable' => 'is_iterable',
46
+ 'list' => [Arrays::class, 'isList'],
47
+ 'mixed' => [self::class, 'isMixed'],
48
+ 'none' => [self::class, 'isNone'],
49
+ 'number' => [self::class, 'isNumber'],
50
+ 'numeric' => [self::class, 'isNumeric'],
51
+ 'numericint' => [self::class, 'isNumericInt'],
52
+
53
+ // string patterns
54
+ 'alnum' => 'ctype_alnum',
55
+ 'alpha' => 'ctype_alpha',
56
+ 'digit' => 'ctype_digit',
57
+ 'lower' => 'ctype_lower',
58
+ 'pattern' => null,
59
+ 'space' => 'ctype_space',
60
+ 'unicode' => [self::class, 'isUnicode'],
61
+ 'upper' => 'ctype_upper',
62
+ 'xdigit' => 'ctype_xdigit',
63
+
64
+ // syntax validation
65
+ 'email' => [self::class, 'isEmail'],
66
+ 'identifier' => [self::class, 'isPhpIdentifier'],
67
+ 'uri' => [self::class, 'isUri'],
68
+ 'url' => [self::class, 'isUrl'],
69
+
70
+ // environment validation
71
+ 'class' => 'class_exists',
72
+ 'interface' => 'interface_exists',
73
+ 'directory' => 'is_dir',
74
+ 'file' => 'is_file',
75
+ 'type' => [self::class, 'isType'],
76
+ ];
77
+
78
+ /** @var array<string,callable> */
79
+ protected static $counters = [
80
+ 'string' => 'strlen',
81
+ 'unicode' => [Strings::class, 'length'],
82
+ 'array' => 'count',
83
+ 'list' => 'count',
84
+ 'alnum' => 'strlen',
85
+ 'alpha' => 'strlen',
86
+ 'digit' => 'strlen',
87
+ 'lower' => 'strlen',
88
+ 'space' => 'strlen',
89
+ 'upper' => 'strlen',
90
+ 'xdigit' => 'strlen',
91
+ ];
92
+
93
+
94
+ /**
95
+ * Verifies that the value is of expected types separated by pipe.
96
+ * @throws AssertionException
97
+ */
98
+ public static function assert(mixed $value, string $expected, string $label = 'variable'): void
99
+ {
100
+ if (!static::is($value, $expected)) {
101
+ $expected = str_replace(['|', ':'], [' or ', ' in range '], $expected);
102
+ $translate = ['boolean' => 'bool', 'integer' => 'int', 'double' => 'float', 'NULL' => 'null'];
103
+ $type = $translate[gettype($value)] ?? gettype($value);
104
+ if (is_int($value) || is_float($value) || (is_string($value) && strlen($value) < 40)) {
105
+ $type .= ' ' . var_export($value, return: true);
106
+ } elseif (is_object($value)) {
107
+ $type .= ' ' . $value::class;
108
+ }
109
+
110
+ throw new AssertionException("The $label expects to be $expected, $type given.");
111
+ }
112
+ }
113
+
114
+
115
+ /**
116
+ * Verifies that element $key in array is of expected types separated by pipe.
117
+ * @param mixed[] $array
118
+ * @throws AssertionException
119
+ */
120
+ public static function assertField(
121
+ array $array,
122
+ $key,
123
+ ?string $expected = null,
124
+ string $label = "item '%' in array",
125
+ ): void
126
+ {
127
+ if (!array_key_exists($key, $array)) {
128
+ throw new AssertionException('Missing ' . str_replace('%', $key, $label) . '.');
129
+
130
+ } elseif ($expected) {
131
+ static::assert($array[$key], $expected, str_replace('%', $key, $label));
132
+ }
133
+ }
134
+
135
+
136
+ /**
137
+ * Verifies that the value is of expected types separated by pipe.
138
+ */
139
+ public static function is(mixed $value, string $expected): bool
140
+ {
141
+ foreach (explode('|', $expected) as $item) {
142
+ if (str_ends_with($item, '[]')) {
143
+ if (is_iterable($value) && self::everyIs($value, substr($item, 0, -2))) {
144
+ return true;
145
+ }
146
+
147
+ continue;
148
+ } elseif (str_starts_with($item, '?')) {
149
+ $item = substr($item, 1);
150
+ if ($value === null) {
151
+ return true;
152
+ }
153
+ }
154
+
155
+ [$type] = $item = explode(':', $item, 2);
156
+ if (isset(static::$validators[$type])) {
157
+ try {
158
+ if (!static::$validators[$type]($value)) {
159
+ continue;
160
+ }
161
+ } catch (\TypeError $e) {
162
+ continue;
163
+ }
164
+ } elseif ($type === 'pattern') {
165
+ if (Strings::match($value, '|^' . ($item[1] ?? '') . '$|D')) {
166
+ return true;
167
+ }
168
+
169
+ continue;
170
+ } elseif (!$value instanceof $type) {
171
+ continue;
172
+ }
173
+
174
+ if (isset($item[1])) {
175
+ $length = $value;
176
+ if (isset(static::$counters[$type])) {
177
+ $length = static::$counters[$type]($value);
178
+ }
179
+
180
+ $range = explode('..', $item[1]);
181
+ if (!isset($range[1])) {
182
+ $range[1] = $range[0];
183
+ }
184
+
185
+ if (($range[0] !== '' && $length < $range[0]) || ($range[1] !== '' && $length > $range[1])) {
186
+ continue;
187
+ }
188
+ }
189
+
190
+ return true;
191
+ }
192
+
193
+ return false;
194
+ }
195
+
196
+
197
+ /**
198
+ * Finds whether all values are of expected types separated by pipe.
199
+ * @param mixed[] $values
200
+ */
201
+ public static function everyIs(iterable $values, string $expected): bool
202
+ {
203
+ foreach ($values as $value) {
204
+ if (!static::is($value, $expected)) {
205
+ return false;
206
+ }
207
+ }
208
+
209
+ return true;
210
+ }
211
+
212
+
213
+ /**
214
+ * Checks if the value is an integer or a float.
215
+ * @return ($value is int|float ? true : false)
216
+ */
217
+ public static function isNumber(mixed $value): bool
218
+ {
219
+ return is_int($value) || is_float($value);
220
+ }
221
+
222
+
223
+ /**
224
+ * Checks if the value is an integer or a integer written in a string.
225
+ * @return ($value is non-empty-string ? bool : ($value is int ? true : false))
226
+ */
227
+ public static function isNumericInt(mixed $value): bool
228
+ {
229
+ return is_int($value) || (is_string($value) && preg_match('#^[+-]?[0-9]+$#D', $value));
230
+ }
231
+
232
+
233
+ /**
234
+ * Checks if the value is a number or a number written in a string.
235
+ * @return ($value is non-empty-string ? bool : ($value is int|float ? true : false))
236
+ */
237
+ public static function isNumeric(mixed $value): bool
238
+ {
239
+ return is_float($value) || is_int($value) || (is_string($value) && preg_match('#^[+-]?([0-9]++\.?[0-9]*|\.[0-9]+)$#D', $value));
240
+ }
241
+
242
+
243
+ /**
244
+ * Checks if the value is a syntactically correct callback.
245
+ */
246
+ public static function isCallable(mixed $value): bool
247
+ {
248
+ return $value && is_callable($value, syntax_only: true);
249
+ }
250
+
251
+
252
+ /**
253
+ * Checks if the value is a valid UTF-8 string.
254
+ */
255
+ public static function isUnicode(mixed $value): bool
256
+ {
257
+ return is_string($value) && preg_match('##u', $value);
258
+ }
259
+
260
+
261
+ /**
262
+ * Checks if the value is 0, '', false or null.
263
+ * @return ($value is 0|''|false|null ? true : false)
264
+ */
265
+ public static function isNone(mixed $value): bool
266
+ {
267
+ return $value == null; // intentionally ==
268
+ }
269
+
270
+
271
+ /** @internal */
272
+ public static function isMixed(): bool
273
+ {
274
+ return true;
275
+ }
276
+
277
+
278
+ /**
279
+ * Checks if a variable is a zero-based integer indexed array.
280
+ * @deprecated use Nette\Utils\Arrays::isList
281
+ * @return ($value is list ? true : false)
282
+ */
283
+ public static function isList(mixed $value): bool
284
+ {
285
+ return Arrays::isList($value);
286
+ }
287
+
288
+
289
+ /**
290
+ * Checks if the value is in the given range [min, max], where the upper or lower limit can be omitted (null).
291
+ * Numbers, strings and DateTime objects can be compared.
292
+ */
293
+ public static function isInRange(mixed $value, array $range): bool
294
+ {
295
+ if ($value === null || !(isset($range[0]) || isset($range[1]))) {
296
+ return false;
297
+ }
298
+
299
+ $limit = $range[0] ?? $range[1];
300
+ if (is_string($limit)) {
301
+ $value = (string) $value;
302
+ } elseif ($limit instanceof \DateTimeInterface) {
303
+ if (!$value instanceof \DateTimeInterface) {
304
+ return false;
305
+ }
306
+ } elseif (is_numeric($value)) {
307
+ $value *= 1;
308
+ } else {
309
+ return false;
310
+ }
311
+
312
+ return (!isset($range[0]) || ($value >= $range[0])) && (!isset($range[1]) || ($value <= $range[1]));
313
+ }
314
+
315
+
316
+ /**
317
+ * Checks if the value is a valid email address. It does not verify that the domain actually exists, only the syntax is verified.
318
+ */
319
+ public static function isEmail(string $value): bool
320
+ {
321
+ $atom = "[-a-z0-9!#$%&'*+/=?^_`{|}~]"; // RFC 5322 unquoted characters in local-part
322
+ $alpha = "a-z\x80-\xFF"; // superset of IDN
323
+ return (bool) preg_match(<<<XX
324
+ (^(?n)
325
+ ("([ !#-[\\]-~]*|\\\\[ -~])+"|$atom+(\\.$atom+)*) # quoted or unquoted
326
+ @
327
+ ([0-9$alpha]([-0-9$alpha]{0,61}[0-9$alpha])?\\.)+ # domain - RFC 1034
328
+ [$alpha]([-0-9$alpha]{0,17}[$alpha])? # top domain
329
+ $)Dix
330
+ XX, $value);
331
+ }
332
+
333
+
334
+ /**
335
+ * Checks if the value is a valid URL address.
336
+ */
337
+ public static function isUrl(string $value): bool
338
+ {
339
+ $alpha = "a-z\x80-\xFF";
340
+ return (bool) preg_match(<<<XX
341
+ (^(?n)
342
+ https?://(
343
+ (([-_0-9$alpha]+\\.)* # subdomain
344
+ [0-9$alpha]([-0-9$alpha]{0,61}[0-9$alpha])?\\.)? # domain
345
+ [$alpha]([-0-9$alpha]{0,17}[$alpha])? # top domain
346
+ |\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3} # IPv4
347
+ |\\[[0-9a-f:]{3,39}\\] # IPv6
348
+ )(:\\d{1,5})? # port
349
+ (/\\S*)? # path
350
+ (\\?\\S*)? # query
351
+ (\\#\\S*)? # fragment
352
+ $)Dix
353
+ XX, $value);
354
+ }
355
+
356
+
357
+ /**
358
+ * Checks if the value is a valid URI address, that is, actually a string beginning with a syntactically valid schema.
359
+ */
360
+ public static function isUri(string $value): bool
361
+ {
362
+ return (bool) preg_match('#^[a-z\d+\.-]+:\S+$#Di', $value);
363
+ }
364
+
365
+
366
+ /**
367
+ * Checks whether the input is a class, interface or trait.
368
+ * @deprecated
369
+ */
370
+ public static function isType(string $type): bool
371
+ {
372
+ return class_exists($type) || interface_exists($type) || trait_exists($type);
373
+ }
374
+
375
+
376
+ /**
377
+ * Checks whether the input is a valid PHP identifier.
378
+ */
379
+ public static function isPhpIdentifier(string $value): bool
380
+ {
381
+ return preg_match('#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#D', $value) === 1;
382
+ }
383
+
384
+
385
+ /**
386
+ * Determines if type is PHP built-in type. Otherwise, it is the class name.
387
+ */
388
+ public static function isBuiltinType(string $type): bool
389
+ {
390
+ return isset(self::BuiltinTypes[strtolower($type)]);
391
+ }
392
+
393
+
394
+ /**
395
+ * Determines if type is special class name self/parent/static.
396
+ */
397
+ public static function isClassKeyword(string $name): bool
398
+ {
399
+ return (bool) preg_match('#^(self|parent|static)$#Di', $name);
400
+ }
401
+
402
+
403
+ /**
404
+ * Checks whether the given type declaration is syntactically valid.
405
+ */
406
+ public static function isTypeDeclaration(string $type): bool
407
+ {
408
+ return (bool) preg_match(<<<'XX'
409
+ ~((?n)
410
+ \?? (?<type> \\? (?<name> [a-zA-Z_\x7f-\xff][\w\x7f-\xff]*) (\\ (?&name))* ) |
411
+ (?<intersection> (?&type) (& (?&type))+ ) |
412
+ (?<upart> (?&type) | \( (?&intersection) \) ) (\| (?&upart))+
413
+ )$~xAD
414
+ XX, $type);
415
+ }
416
+ }