@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,75 @@
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
+ * Represent RGB color (0..255) with opacity (0..1).
17
+ */
18
+ class ImageColor
19
+ {
20
+ public static function rgb(int $red, int $green, int $blue, float $opacity = 1): self
21
+ {
22
+ return new self($red, $green, $blue, $opacity);
23
+ }
24
+
25
+
26
+ /**
27
+ * Accepts formats #RRGGBB, #RRGGBBAA, #RGB, #RGBA
28
+ */
29
+ public static function hex(string $hex): self
30
+ {
31
+ $hex = ltrim($hex, '#');
32
+ $len = strlen($hex);
33
+ if ($len === 3 || $len === 4) {
34
+ return new self(
35
+ (int) hexdec($hex[0]) * 17,
36
+ (int) hexdec($hex[1]) * 17,
37
+ (int) hexdec($hex[2]) * 17,
38
+ (int) hexdec($hex[3] ?? 'F') * 17 / 255,
39
+ );
40
+ } elseif ($len === 6 || $len === 8) {
41
+ return new self(
42
+ (int) hexdec($hex[0] . $hex[1]),
43
+ (int) hexdec($hex[2] . $hex[3]),
44
+ (int) hexdec($hex[4] . $hex[5]),
45
+ (int) hexdec(($hex[6] ?? 'F') . ($hex[7] ?? 'F')) / 255,
46
+ );
47
+ } else {
48
+ throw new Nette\InvalidArgumentException('Invalid hex color format.');
49
+ }
50
+ }
51
+
52
+
53
+ private function __construct(
54
+ public int $red,
55
+ public int $green,
56
+ public int $blue,
57
+ public float $opacity = 1,
58
+ ) {
59
+ $this->red = max(0, min(255, $red));
60
+ $this->green = max(0, min(255, $green));
61
+ $this->blue = max(0, min(255, $blue));
62
+ $this->opacity = max(0, min(1, $opacity));
63
+ }
64
+
65
+
66
+ public function toRGBA(): array
67
+ {
68
+ return [
69
+ max(0, min(255, $this->red)),
70
+ max(0, min(255, $this->green)),
71
+ max(0, min(255, $this->blue)),
72
+ max(0, min(127, (int) round(127 - $this->opacity * 127))),
73
+ ];
74
+ }
75
+ }
@@ -0,0 +1,25 @@
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
+
13
+ /**
14
+ * Type of image file.
15
+ */
16
+ /*enum*/ final class ImageType
17
+ {
18
+ public const
19
+ JPEG = IMAGETYPE_JPEG,
20
+ PNG = IMAGETYPE_PNG,
21
+ GIF = IMAGETYPE_GIF,
22
+ WEBP = IMAGETYPE_WEBP,
23
+ AVIF = 19, // IMAGETYPE_AVIF,
24
+ BMP = IMAGETYPE_BMP;
25
+ }
@@ -0,0 +1,238 @@
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
+ * Utilities for iterables.
17
+ */
18
+ final class Iterables
19
+ {
20
+ use Nette\StaticClass;
21
+
22
+ /**
23
+ * Tests for the presence of value.
24
+ */
25
+ public static function contains(iterable $iterable, mixed $value): bool
26
+ {
27
+ foreach ($iterable as $v) {
28
+ if ($v === $value) {
29
+ return true;
30
+ }
31
+ }
32
+ return false;
33
+ }
34
+
35
+
36
+ /**
37
+ * Tests for the presence of key.
38
+ */
39
+ public static function containsKey(iterable $iterable, mixed $key): bool
40
+ {
41
+ foreach ($iterable as $k => $v) {
42
+ if ($k === $key) {
43
+ return true;
44
+ }
45
+ }
46
+ return false;
47
+ }
48
+
49
+
50
+ /**
51
+ * Returns the first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
52
+ * @template K
53
+ * @template V
54
+ * @param iterable<K, V> $iterable
55
+ * @param ?callable(V, K, iterable<K, V>): bool $predicate
56
+ * @return ?V
57
+ */
58
+ public static function first(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed
59
+ {
60
+ foreach ($iterable as $k => $v) {
61
+ if (!$predicate || $predicate($v, $k, $iterable)) {
62
+ return $v;
63
+ }
64
+ }
65
+ return $else ? $else() : null;
66
+ }
67
+
68
+
69
+ /**
70
+ * Returns the key of first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
71
+ * @template K
72
+ * @template V
73
+ * @param iterable<K, V> $iterable
74
+ * @param ?callable(V, K, iterable<K, V>): bool $predicate
75
+ * @return ?K
76
+ */
77
+ public static function firstKey(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed
78
+ {
79
+ foreach ($iterable as $k => $v) {
80
+ if (!$predicate || $predicate($v, $k, $iterable)) {
81
+ return $k;
82
+ }
83
+ }
84
+ return $else ? $else() : null;
85
+ }
86
+
87
+
88
+ /**
89
+ * Tests whether at least one element in the iterator passes the test implemented by the provided function.
90
+ * @template K
91
+ * @template V
92
+ * @param iterable<K, V> $iterable
93
+ * @param callable(V, K, iterable<K, V>): bool $predicate
94
+ */
95
+ public static function some(iterable $iterable, callable $predicate): bool
96
+ {
97
+ foreach ($iterable as $k => $v) {
98
+ if ($predicate($v, $k, $iterable)) {
99
+ return true;
100
+ }
101
+ }
102
+ return false;
103
+ }
104
+
105
+
106
+ /**
107
+ * Tests whether all elements in the iterator pass the test implemented by the provided function.
108
+ * @template K
109
+ * @template V
110
+ * @param iterable<K, V> $iterable
111
+ * @param callable(V, K, iterable<K, V>): bool $predicate
112
+ */
113
+ public static function every(iterable $iterable, callable $predicate): bool
114
+ {
115
+ foreach ($iterable as $k => $v) {
116
+ if (!$predicate($v, $k, $iterable)) {
117
+ return false;
118
+ }
119
+ }
120
+ return true;
121
+ }
122
+
123
+
124
+ /**
125
+ * Iterator that filters elements according to a given $predicate. Maintains original keys.
126
+ * @template K
127
+ * @template V
128
+ * @param iterable<K, V> $iterable
129
+ * @param callable(V, K, iterable<K, V>): bool $predicate
130
+ * @return \Generator<K, V>
131
+ */
132
+ public static function filter(iterable $iterable, callable $predicate): \Generator
133
+ {
134
+ foreach ($iterable as $k => $v) {
135
+ if ($predicate($v, $k, $iterable)) {
136
+ yield $k => $v;
137
+ }
138
+ }
139
+ }
140
+
141
+
142
+ /**
143
+ * Iterator that transforms values by calling $transformer. Maintains original keys.
144
+ * @template K
145
+ * @template V
146
+ * @template R
147
+ * @param iterable<K, V> $iterable
148
+ * @param callable(V, K, iterable<K, V>): R $transformer
149
+ * @return \Generator<K, R>
150
+ */
151
+ public static function map(iterable $iterable, callable $transformer): \Generator
152
+ {
153
+ foreach ($iterable as $k => $v) {
154
+ yield $k => $transformer($v, $k, $iterable);
155
+ }
156
+ }
157
+
158
+
159
+ /**
160
+ * Iterator that transforms keys and values by calling $transformer. If it returns null, the element is skipped.
161
+ * @template K
162
+ * @template V
163
+ * @template ResV
164
+ * @template ResK
165
+ * @param iterable<K, V> $iterable
166
+ * @param callable(V, K, iterable<K, V>): ?array{ResV, ResK} $transformer
167
+ * @return \Generator<ResV, ResK>
168
+ */
169
+ public static function mapWithKeys(iterable $iterable, callable $transformer): \Generator
170
+ {
171
+ foreach ($iterable as $k => $v) {
172
+ $pair = $transformer($v, $k, $iterable);
173
+ if ($pair) {
174
+ yield $pair[0] => $pair[1];
175
+ }
176
+ }
177
+ }
178
+
179
+
180
+ /**
181
+ * Wraps around iterator and caches its keys and values during iteration.
182
+ * This allows the data to be re-iterated multiple times.
183
+ * @template K
184
+ * @template V
185
+ * @param iterable<K, V> $iterable
186
+ * @return \IteratorAggregate<K, V>
187
+ */
188
+ public static function memoize(iterable $iterable): iterable
189
+ {
190
+ return new class (self::toIterator($iterable)) implements \IteratorAggregate {
191
+ public function __construct(
192
+ private \Iterator $iterator,
193
+ private array $cache = [],
194
+ ) {
195
+ }
196
+
197
+
198
+ public function getIterator(): \Generator
199
+ {
200
+ if (!$this->cache) {
201
+ $this->iterator->rewind();
202
+ }
203
+ $i = 0;
204
+ while (true) {
205
+ if (isset($this->cache[$i])) {
206
+ [$k, $v] = $this->cache[$i];
207
+ } elseif ($this->iterator->valid()) {
208
+ $k = $this->iterator->key();
209
+ $v = $this->iterator->current();
210
+ $this->iterator->next();
211
+ $this->cache[$i] = [$k, $v];
212
+ } else {
213
+ break;
214
+ }
215
+ yield $k => $v;
216
+ $i++;
217
+ }
218
+ }
219
+ };
220
+ }
221
+
222
+
223
+ /**
224
+ * Creates an iterator from anything that is iterable.
225
+ * @template K
226
+ * @template V
227
+ * @param iterable<K, V> $iterable
228
+ * @return \Iterator<K, V>
229
+ */
230
+ public static function toIterator(iterable $iterable): \Iterator
231
+ {
232
+ return match (true) {
233
+ $iterable instanceof \Iterator => $iterable,
234
+ $iterable instanceof \IteratorAggregate => self::toIterator($iterable->getIterator()),
235
+ is_array($iterable) => new \ArrayIterator($iterable),
236
+ };
237
+ }
238
+ }
@@ -0,0 +1,84 @@
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
+ * JSON encoder and decoder.
17
+ */
18
+ final class Json
19
+ {
20
+ use Nette\StaticClass;
21
+
22
+ /** @deprecated use Json::decode(..., forceArrays: true) */
23
+ public const FORCE_ARRAY = JSON_OBJECT_AS_ARRAY;
24
+
25
+ /** @deprecated use Json::encode(..., pretty: true) */
26
+ public const PRETTY = JSON_PRETTY_PRINT;
27
+
28
+ /** @deprecated use Json::encode(..., asciiSafe: true) */
29
+ public const ESCAPE_UNICODE = 1 << 19;
30
+
31
+
32
+ /**
33
+ * Converts value to JSON format. Use $pretty for easier reading and clarity, $asciiSafe for ASCII output
34
+ * and $htmlSafe for HTML escaping, $forceObjects enforces the encoding of non-associateve arrays as objects.
35
+ * @throws JsonException
36
+ */
37
+ public static function encode(
38
+ mixed $value,
39
+ bool|int $pretty = false,
40
+ bool $asciiSafe = false,
41
+ bool $htmlSafe = false,
42
+ bool $forceObjects = false,
43
+ ): string
44
+ {
45
+ if (is_int($pretty)) { // back compatibility
46
+ $flags = ($pretty & self::ESCAPE_UNICODE ? 0 : JSON_UNESCAPED_UNICODE) | ($pretty & ~self::ESCAPE_UNICODE);
47
+ } else {
48
+ $flags = ($asciiSafe ? 0 : JSON_UNESCAPED_UNICODE)
49
+ | ($pretty ? JSON_PRETTY_PRINT : 0)
50
+ | ($forceObjects ? JSON_FORCE_OBJECT : 0)
51
+ | ($htmlSafe ? JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG : 0);
52
+ }
53
+
54
+ $flags |= JSON_UNESCAPED_SLASHES
55
+ | (defined('JSON_PRESERVE_ZERO_FRACTION') ? JSON_PRESERVE_ZERO_FRACTION : 0); // since PHP 5.6.6 & PECL JSON-C 1.3.7
56
+
57
+ $json = json_encode($value, $flags);
58
+ if ($error = json_last_error()) {
59
+ throw new JsonException(json_last_error_msg(), $error);
60
+ }
61
+
62
+ return $json;
63
+ }
64
+
65
+
66
+ /**
67
+ * Parses JSON to PHP value. The $forceArrays enforces the decoding of objects as arrays.
68
+ * @throws JsonException
69
+ */
70
+ public static function decode(string $json, bool|int $forceArrays = false): mixed
71
+ {
72
+ $flags = is_int($forceArrays) // back compatibility
73
+ ? $forceArrays
74
+ : ($forceArrays ? JSON_OBJECT_AS_ARRAY : 0);
75
+ $flags |= JSON_BIGINT_AS_STRING;
76
+
77
+ $value = json_decode($json, flags: $flags);
78
+ if ($error = json_last_error()) {
79
+ throw new JsonException(json_last_error_msg(), $error);
80
+ }
81
+
82
+ return $value;
83
+ }
84
+ }
@@ -0,0 +1,229 @@
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
+ use Nette\MemberAccessException;
14
+
15
+
16
+ /**
17
+ * Nette\SmartObject helpers.
18
+ * @internal
19
+ */
20
+ final class ObjectHelpers
21
+ {
22
+ use Nette\StaticClass;
23
+
24
+ /**
25
+ * @return never
26
+ * @throws MemberAccessException
27
+ */
28
+ public static function strictGet(string $class, string $name): void
29
+ {
30
+ $rc = new \ReflectionClass($class);
31
+ $hint = self::getSuggestion(array_merge(
32
+ array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), fn($p) => !$p->isStatic()),
33
+ self::parseFullDoc($rc, '~^[ \t*]*@property(?:-read)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m'),
34
+ ), $name);
35
+ throw new MemberAccessException("Cannot read an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.'));
36
+ }
37
+
38
+
39
+ /**
40
+ * @return never
41
+ * @throws MemberAccessException
42
+ */
43
+ public static function strictSet(string $class, string $name): void
44
+ {
45
+ $rc = new \ReflectionClass($class);
46
+ $hint = self::getSuggestion(array_merge(
47
+ array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), fn($p) => !$p->isStatic()),
48
+ self::parseFullDoc($rc, '~^[ \t*]*@property(?:-write)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m'),
49
+ ), $name);
50
+ throw new MemberAccessException("Cannot write to an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.'));
51
+ }
52
+
53
+
54
+ /**
55
+ * @return never
56
+ * @throws MemberAccessException
57
+ */
58
+ public static function strictCall(string $class, string $method, array $additionalMethods = []): void
59
+ {
60
+ $trace = debug_backtrace(0, 3); // suppose this method is called from __call()
61
+ $context = ($trace[1]['function'] ?? null) === '__call'
62
+ ? ($trace[2]['class'] ?? null)
63
+ : null;
64
+
65
+ if ($context && is_a($class, $context, true) && method_exists($context, $method)) { // called parent::$method()
66
+ $class = get_parent_class($context);
67
+ }
68
+
69
+ if (method_exists($class, $method)) { // insufficient visibility
70
+ $rm = new \ReflectionMethod($class, $method);
71
+ $visibility = $rm->isPrivate()
72
+ ? 'private '
73
+ : ($rm->isProtected() ? 'protected ' : '');
74
+ throw new MemberAccessException("Call to {$visibility}method $class::$method() from " . ($context ? "scope $context." : 'global scope.'));
75
+
76
+ } else {
77
+ $hint = self::getSuggestion(array_merge(
78
+ get_class_methods($class),
79
+ self::parseFullDoc(new \ReflectionClass($class), '~^[ \t*]*@method[ \t]+(?:static[ \t]+)?(?:\S+[ \t]+)??(\w+)\(~m'),
80
+ $additionalMethods,
81
+ ), $method);
82
+ throw new MemberAccessException("Call to undefined method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.'));
83
+ }
84
+ }
85
+
86
+
87
+ /**
88
+ * @return never
89
+ * @throws MemberAccessException
90
+ */
91
+ public static function strictStaticCall(string $class, string $method): void
92
+ {
93
+ $trace = debug_backtrace(0, 3); // suppose this method is called from __callStatic()
94
+ $context = ($trace[1]['function'] ?? null) === '__callStatic'
95
+ ? ($trace[2]['class'] ?? null)
96
+ : null;
97
+
98
+ if ($context && is_a($class, $context, true) && method_exists($context, $method)) { // called parent::$method()
99
+ $class = get_parent_class($context);
100
+ }
101
+
102
+ if (method_exists($class, $method)) { // insufficient visibility
103
+ $rm = new \ReflectionMethod($class, $method);
104
+ $visibility = $rm->isPrivate()
105
+ ? 'private '
106
+ : ($rm->isProtected() ? 'protected ' : '');
107
+ throw new MemberAccessException("Call to {$visibility}method $class::$method() from " . ($context ? "scope $context." : 'global scope.'));
108
+
109
+ } else {
110
+ $hint = self::getSuggestion(
111
+ array_filter((new \ReflectionClass($class))->getMethods(\ReflectionMethod::IS_PUBLIC), fn($m) => $m->isStatic()),
112
+ $method,
113
+ );
114
+ throw new MemberAccessException("Call to undefined static method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.'));
115
+ }
116
+ }
117
+
118
+
119
+ /**
120
+ * Returns array of magic properties defined by annotation @property.
121
+ * @return array of [name => bit mask]
122
+ * @internal
123
+ */
124
+ public static function getMagicProperties(string $class): array
125
+ {
126
+ static $cache;
127
+ $props = &$cache[$class];
128
+ if ($props !== null) {
129
+ return $props;
130
+ }
131
+
132
+ $rc = new \ReflectionClass($class);
133
+ preg_match_all(
134
+ '~^ [ \t*]* @property(|-read|-write|-deprecated) [ \t]+ [^\s$]+ [ \t]+ \$ (\w+) ()~mx',
135
+ (string) $rc->getDocComment(),
136
+ $matches,
137
+ PREG_SET_ORDER,
138
+ );
139
+
140
+ $props = [];
141
+ foreach ($matches as [, $type, $name]) {
142
+ $uname = ucfirst($name);
143
+ $write = $type !== '-read'
144
+ && $rc->hasMethod($nm = 'set' . $uname)
145
+ && ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic();
146
+ $read = $type !== '-write'
147
+ && ($rc->hasMethod($nm = 'get' . $uname) || $rc->hasMethod($nm = 'is' . $uname))
148
+ && ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic();
149
+
150
+ if ($read || $write) {
151
+ $props[$name] = $read << 0 | ($nm[0] === 'g') << 1 | $rm->returnsReference() << 2 | $write << 3 | ($type === '-deprecated') << 4;
152
+ }
153
+ }
154
+
155
+ foreach ($rc->getTraits() as $trait) {
156
+ $props += self::getMagicProperties($trait->name);
157
+ }
158
+
159
+ if ($parent = get_parent_class($class)) {
160
+ $props += self::getMagicProperties($parent);
161
+ }
162
+
163
+ return $props;
164
+ }
165
+
166
+
167
+ /**
168
+ * Finds the best suggestion (for 8-bit encoding).
169
+ * @param (\ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionClass|\ReflectionProperty|string)[] $possibilities
170
+ * @internal
171
+ */
172
+ public static function getSuggestion(array $possibilities, string $value): ?string
173
+ {
174
+ $norm = preg_replace($re = '#^(get|set|has|is|add)(?=[A-Z])#', '+', $value);
175
+ $best = null;
176
+ $min = (strlen($value) / 4 + 1) * 10 + .1;
177
+ foreach (array_unique($possibilities, SORT_REGULAR) as $item) {
178
+ $item = $item instanceof \Reflector ? $item->name : $item;
179
+ if ($item !== $value && (
180
+ ($len = levenshtein($item, $value, 10, 11, 10)) < $min
181
+ || ($len = levenshtein(preg_replace($re, '*', $item), $norm, 10, 11, 10)) < $min
182
+ )) {
183
+ $min = $len;
184
+ $best = $item;
185
+ }
186
+ }
187
+
188
+ return $best;
189
+ }
190
+
191
+
192
+ private static function parseFullDoc(\ReflectionClass $rc, string $pattern): array
193
+ {
194
+ do {
195
+ $doc[] = $rc->getDocComment();
196
+ $traits = $rc->getTraits();
197
+ while ($trait = array_pop($traits)) {
198
+ $doc[] = $trait->getDocComment();
199
+ $traits += $trait->getTraits();
200
+ }
201
+ } while ($rc = $rc->getParentClass());
202
+
203
+ return preg_match_all($pattern, implode('', $doc), $m) ? $m[1] : [];
204
+ }
205
+
206
+
207
+ /**
208
+ * Checks if the public non-static property exists.
209
+ * Returns 'event' if the property exists and has event like name
210
+ * @internal
211
+ */
212
+ public static function hasProperty(string $class, string $name): bool|string
213
+ {
214
+ static $cache;
215
+ $prop = &$cache[$class][$name];
216
+ if ($prop === null) {
217
+ $prop = false;
218
+ try {
219
+ $rp = new \ReflectionProperty($class, $name);
220
+ if ($rp->isPublic() && !$rp->isStatic()) {
221
+ $prop = $name >= 'onA' && $name < 'on_' ? 'event' : true;
222
+ }
223
+ } catch (\ReflectionException $e) {
224
+ }
225
+ }
226
+
227
+ return $prop;
228
+ }
229
+ }