@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
@@ -23,6 +23,9 @@ use function is_array, is_string, count, strlen;
23
23
  */
24
24
  final class Filters
25
25
  {
26
+ public ?string $locale = null;
27
+
28
+
26
29
  /**
27
30
  * Converts HTML to plain text.
28
31
  */
@@ -35,7 +38,7 @@ final class Filters
35
38
 
36
39
 
37
40
  /**
38
- * Removes tags from HTML (but remains HTML entites).
41
+ * Removes tags from HTML (but remains HTML entities).
39
42
  */
40
43
  public static function stripTags(FilterInfo $info, $s): string
41
44
  {
@@ -168,14 +171,11 @@ final class Filters
168
171
  */
169
172
  public static function date(string|int|\DateTimeInterface|\DateInterval|null $time, ?string $format = null): ?string
170
173
  {
174
+ $format ??= Latte\Runtime\Filters::$dateFormat;
171
175
  if ($time == null) { // intentionally ==
172
176
  return null;
173
- }
174
-
175
- $format ??= Latte\Runtime\Filters::$dateFormat;
176
- if ($time instanceof \DateInterval) {
177
+ } elseif ($time instanceof \DateInterval) {
177
178
  return $time->format($format);
178
-
179
179
  } elseif (is_numeric($time)) {
180
180
  $time = (new \DateTime)->setTimestamp((int) $time);
181
181
  } elseif (!$time instanceof \DateTimeInterface) {
@@ -194,10 +194,75 @@ final class Filters
194
194
  }
195
195
 
196
196
 
197
+ /**
198
+ * Date/time formatting according to locale.
199
+ */
200
+ public function localDate(
201
+ string|int|\DateTimeInterface|null $value,
202
+ ?string $format = null,
203
+ ?string $date = null,
204
+ ?string $time = null,
205
+ ): ?string
206
+ {
207
+ if ($this->locale === null) {
208
+ throw new Latte\RuntimeException('Filter |localDate requires the locale to be set using Engine::setLocale()');
209
+ } elseif ($value == null) { // intentionally ==
210
+ return null;
211
+ } elseif (is_numeric($value)) {
212
+ $value = (new \DateTime)->setTimestamp((int) $value);
213
+ } elseif (!$value instanceof \DateTimeInterface) {
214
+ $value = new \DateTime($value);
215
+ $errors = \DateTime::getLastErrors();
216
+ if (!empty($errors['warnings'])) {
217
+ throw new \InvalidArgumentException(reset($errors['warnings']));
218
+ }
219
+ }
220
+
221
+ if ($format === null) {
222
+ $xlt = ['' => \IntlDateFormatter::NONE, 'full' => \IntlDateFormatter::FULL, 'long' => \IntlDateFormatter::LONG, 'medium' => \IntlDateFormatter::MEDIUM, 'short' => \IntlDateFormatter::SHORT,
223
+ 'relative-full' => \IntlDateFormatter::RELATIVE_FULL, 'relative-long' => \IntlDateFormatter::RELATIVE_LONG, 'relative-medium' => \IntlDateFormatter::RELATIVE_MEDIUM, 'relative-short' => \IntlDateFormatter::RELATIVE_SHORT];
224
+ $date ??= $time === null ? 'long' : null;
225
+ $formatter = new \IntlDateFormatter($this->locale, $xlt[$date], $xlt[$time]);
226
+ } else {
227
+ $formatter = new \IntlDateFormatter($this->locale, pattern: (new \IntlDatePatternGenerator($this->locale))->getBestPattern($format));
228
+ }
229
+
230
+ $res = $formatter->format($value);
231
+ $res = preg_replace('~(\d\.) ~', "\$1\u{a0}", $res);
232
+ return $res;
233
+ }
234
+
235
+
236
+ /**
237
+ * Formats a number with grouped thousands and optionally decimal digits according to locale.
238
+ */
239
+ public function number(
240
+ float $number,
241
+ string|int $patternOrDecimals = 0,
242
+ string $decimalSeparator = '.',
243
+ string $thousandsSeparator = ',',
244
+ ): string
245
+ {
246
+ if (is_int($patternOrDecimals) && $patternOrDecimals < 0) {
247
+ throw new Latte\RuntimeException('Filter |number: the number of decimal must not be negative');
248
+ } elseif ($this->locale === null || func_num_args() > 2) {
249
+ return number_format($number, $patternOrDecimals, $decimalSeparator, $thousandsSeparator);
250
+ }
251
+
252
+ $formatter = new \NumberFormatter($this->locale, \NumberFormatter::DECIMAL);
253
+ if (is_string($patternOrDecimals)) {
254
+ $formatter->setPattern($patternOrDecimals);
255
+ } else {
256
+ $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $patternOrDecimals);
257
+ }
258
+ return $formatter->format($number);
259
+ }
260
+
261
+
197
262
  /**
198
263
  * Converts to human-readable file size.
199
264
  */
200
- public static function bytes(float $bytes, int $precision = 2): string
265
+ public function bytes(float $bytes, int $precision = 2): string
201
266
  {
202
267
  $bytes = round($bytes);
203
268
  $units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB'];
@@ -209,7 +274,15 @@ final class Filters
209
274
  $bytes /= 1024;
210
275
  }
211
276
 
212
- return round($bytes, $precision) . ' ' . $unit;
277
+ if ($this->locale === null) {
278
+ $bytes = (string) round($bytes, $precision);
279
+ } else {
280
+ $formatter = new \NumberFormatter($this->locale, \NumberFormatter::DECIMAL);
281
+ $formatter->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $precision);
282
+ $bytes = $formatter->format($bytes);
283
+ }
284
+
285
+ return $bytes . ' ' . $unit;
213
286
  }
214
287
 
215
288
 
@@ -455,7 +528,7 @@ final class Filters
455
528
  * @param iterable<K, V> $data
456
529
  * @return iterable<K, V>
457
530
  */
458
- public static function sort(
531
+ public function sort(
459
532
  iterable $data,
460
533
  ?\Closure $comparison = null,
461
534
  string|int|\Closure|null $by = null,
@@ -469,7 +542,16 @@ final class Filters
469
542
  $by = $byKey === true ? null : $byKey;
470
543
  }
471
544
 
472
- $comparison ??= fn($a, $b) => $a <=> $b;
545
+ if ($comparison) {
546
+ } elseif ($this->locale === null) {
547
+ $comparison = fn($a, $b) => $a <=> $b;
548
+ } else {
549
+ $collator = new \Collator($this->locale);
550
+ $comparison = fn($a, $b) => is_string($a) && is_string($b)
551
+ ? $collator->compare($a, $b)
552
+ : $a <=> $b;
553
+ }
554
+
473
555
  $comparison = match (true) {
474
556
  $by === null => $comparison,
475
557
  $by instanceof \Closure => fn($a, $b) => $comparison($by($a), $by($b)),
@@ -524,6 +606,24 @@ final class Filters
524
606
  }
525
607
 
526
608
 
609
+ /**
610
+ * Filters elements according to a given $predicate. Maintains original keys.
611
+ * @template K
612
+ * @template V
613
+ * @param iterable<K, V> $iterable
614
+ * @param callable(V, K, iterable<K, V>): bool $predicate
615
+ * @return iterable<K, V>
616
+ */
617
+ public static function filter(iterable $iterable, callable $predicate): iterable
618
+ {
619
+ foreach ($iterable as $k => $v) {
620
+ if ($predicate($v, $k, $iterable)) {
621
+ yield $k => $v;
622
+ }
623
+ }
624
+ }
625
+
626
+
527
627
  /**
528
628
  * Returns value clamped to the inclusive range of min and max.
529
629
  */
@@ -9,6 +9,7 @@ declare(strict_types=1);
9
9
 
10
10
  namespace Latte\Essential\Nodes;
11
11
 
12
+ use Latte\Compiler\Nodes\Php\Expression\ArrayNode;
12
13
  use Latte\Compiler\Nodes\Php\ExpressionNode;
13
14
  use Latte\Compiler\Nodes\StatementNode;
14
15
  use Latte\Compiler\PrintContext;
@@ -16,11 +17,12 @@ use Latte\Compiler\Tag;
16
17
 
17
18
 
18
19
  /**
19
- * {import "file"}
20
+ * {import "file"[, args]}
20
21
  */
21
22
  class ImportNode extends StatementNode
22
23
  {
23
24
  public ExpressionNode $file;
25
+ public ArrayNode $args;
24
26
 
25
27
 
26
28
  public static function create(Tag $tag): static
@@ -28,6 +30,8 @@ class ImportNode extends StatementNode
28
30
  $tag->expectArguments();
29
31
  $node = new static;
30
32
  $node->file = $tag->parser->parseUnquotedStringOrExpression();
33
+ $tag->parser->stream->tryConsume(',');
34
+ $node->args = $tag->parser->parseArguments();
31
35
  return $node;
32
36
  }
33
37
 
@@ -35,8 +39,9 @@ class ImportNode extends StatementNode
35
39
  public function print(PrintContext $context): string
36
40
  {
37
41
  return $context->format(
38
- '$this->createTemplate(%node, $this->params, "import")->render() %line;',
42
+ '$this->createTemplate(%node, %node? + $this->params, "import")->render() %line;',
39
43
  $this->file,
44
+ $this->args,
40
45
  $this->position,
41
46
  );
42
47
  }
@@ -45,5 +50,6 @@ class ImportNode extends StatementNode
45
50
  public function &getIterator(): \Generator
46
51
  {
47
52
  yield $this->file;
53
+ yield $this->args;
48
54
  }
49
55
  }
@@ -10,8 +10,10 @@ declare(strict_types=1);
10
10
  namespace Latte\Essential\Nodes;
11
11
 
12
12
  use Latte\Compiler\Nodes\Php\Expression\AssignNode;
13
+ use Latte\Compiler\Nodes\Php\Expression\AssignOpNode;
14
+ use Latte\Compiler\Nodes\Php\Expression\AuxiliaryNode;
15
+ use Latte\Compiler\Nodes\Php\Expression\TernaryNode;
13
16
  use Latte\Compiler\Nodes\Php\Expression\VariableNode;
14
- use Latte\Compiler\Nodes\Php\ExpressionNode;
15
17
  use Latte\Compiler\Nodes\Php\Scalar\NullNode;
16
18
  use Latte\Compiler\Nodes\StatementNode;
17
19
  use Latte\Compiler\PrintContext;
@@ -67,25 +69,19 @@ class VarNode extends StatementNode
67
69
  public function print(PrintContext $context): string
68
70
  {
69
71
  $res = [];
70
- if ($this->default) {
71
- foreach ($this->assignments as $assign) {
72
+ foreach ($this->assignments as $assign) {
73
+ if ($this->default) {
72
74
  assert($assign->var instanceof VariableNode);
73
- if ($assign->var->name instanceof ExpressionNode) {
74
- $var = $assign->var->name->print($context);
75
- } else {
76
- $var = $context->encodeString($assign->var->name);
77
- }
78
- $res[] = $var . ' => ' . $assign->expr->print($context);
75
+ $assign = new AssignOpNode(
76
+ $assign->var,
77
+ '??',
78
+ new TernaryNode(
79
+ new AuxiliaryNode(fn() => 'array_key_exists(' . $context->encodeString($assign->var->name) . ', get_defined_vars())'),
80
+ new NullNode,
81
+ $assign->expr,
82
+ ),
83
+ );
79
84
  }
80
-
81
- return $context->format(
82
- 'extract([%raw], EXTR_SKIP) %line;',
83
- implode(', ', $res),
84
- $this->position,
85
- );
86
- }
87
-
88
- foreach ($this->assignments as $assign) {
89
85
  $res[] = $assign->print($context);
90
86
  }
91
87
 
@@ -50,7 +50,7 @@ final class TranslatorExtension extends Latte\Extension
50
50
  public function getFilters(): array
51
51
  {
52
52
  return [
53
- 'translate' => fn(Latte\Runtime\FilterInfo $fi, ...$args): string => $this->translator
53
+ 'translate' => fn(Latte\Runtime\FilterInfo $fi, ...$args) => $this->translator
54
54
  ? ($this->translator)(...$args)
55
55
  : $args[0],
56
56
  ];
@@ -59,7 +59,7 @@ class FileLoader implements Latte\Loader
59
59
  */
60
60
  public function getReferredName(string $file, string $referringFile): string
61
61
  {
62
- if ($this->baseDir || !preg_match('#/|\\\\|[a-z][a-z0-9+.-]*:#iA', $file)) {
62
+ if ($this->baseDir || !preg_match('#/|\\\\|[a-z]:|phar:#iA', $file)) {
63
63
  $file = $this->normalizePath($referringFile . '/../' . $file);
64
64
  }
65
65
 
@@ -78,15 +78,16 @@ class FileLoader implements Latte\Loader
78
78
 
79
79
  protected static function normalizePath(string $path): string
80
80
  {
81
+ preg_match('#^([a-z]:|phar://.+?/)?(.*)#i', $path, $m);
81
82
  $res = [];
82
- foreach (explode('/', strtr($path, '\\', '/')) as $part) {
83
- if ($part === '..' && $res && end($res) !== '..') {
83
+ foreach (explode('/', strtr($m[2], '\\', '/')) as $part) {
84
+ if ($part === '..' && $res && end($res) !== '..' && end($res) !== '') {
84
85
  array_pop($res);
85
86
  } elseif ($part !== '.') {
86
87
  $res[] = $part;
87
88
  }
88
89
  }
89
90
 
90
- return implode(DIRECTORY_SEPARATOR, $res);
91
+ return $m[1] . implode(DIRECTORY_SEPARATOR, $res);
91
92
  }
92
93
  }
@@ -138,7 +138,7 @@ class Template
138
138
 
139
139
  $params = $this->prepare();
140
140
 
141
- if ($this->parentName === null && isset($this->global->coreParentFinder)) {
141
+ if ($this->parentName === null && !$this->referringTemplate && isset($this->global->coreParentFinder)) {
142
142
  $this->parentName = ($this->global->coreParentFinder)($this);
143
143
  }
144
144
 
@@ -26,6 +26,5 @@ class FunctionCallNode extends Expression\FunctionCallNode
26
26
  return '$this->global->sandbox->call('
27
27
  . $context->memberAsString($this->name) . ', '
28
28
  . $context->argumentsAsArray($this->args) . ')';
29
-
30
29
  }
31
30
  }
@@ -0,0 +1,13 @@
1
+ <?php
2
+
3
+ declare(strict_types=1);
4
+
5
+ namespace PHPSTORM_META;
6
+
7
+ override(\Nette\Utils\Arrays::get(0), elementType(0));
8
+ override(\Nette\Utils\Arrays::getRef(0), elementType(0));
9
+ override(\Nette\Utils\Arrays::grep(0), type(0));
10
+ override(\Nette\Utils\Arrays::toObject(0), type(1));
11
+
12
+ expectedArguments(\Nette\Utils\Image::resize(), 2, \Nette\Utils\Image::ShrinkOnly, \Nette\Utils\Image::Stretch, \Nette\Utils\Image::OrSmaller, \Nette\Utils\Image::OrBigger, \Nette\Utils\Image::Cover);
13
+ expectedArguments(\Nette\Utils\Image::calculateSize(), 4, \Nette\Utils\Image::ShrinkOnly, \Nette\Utils\Image::Stretch, \Nette\Utils\Image::OrSmaller, \Nette\Utils\Image::OrBigger, \Nette\Utils\Image::Cover);
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "nette/utils",
3
+ "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
4
+ "keywords": ["nette", "images", "json", "password", "validation", "utility", "string", "array", "core", "slugify", "utf-8", "unicode", "paginator", "datetime"],
5
+ "homepage": "https://nette.org",
6
+ "license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"],
7
+ "authors": [
8
+ {
9
+ "name": "David Grudl",
10
+ "homepage": "https://davidgrudl.com"
11
+ },
12
+ {
13
+ "name": "Nette Community",
14
+ "homepage": "https://nette.org/contributors"
15
+ }
16
+ ],
17
+ "require": {
18
+ "php": "8.0 - 8.4"
19
+ },
20
+ "require-dev": {
21
+ "nette/tester": "^2.5",
22
+ "tracy/tracy": "^2.9",
23
+ "phpstan/phpstan": "^1.0",
24
+ "jetbrains/phpstorm-attributes": "dev-master"
25
+ },
26
+ "conflict": {
27
+ "nette/finder": "<3",
28
+ "nette/schema": "<1.2.2"
29
+ },
30
+ "suggest": {
31
+ "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
32
+ "ext-json": "to use Nette\\Utils\\Json",
33
+ "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
34
+ "ext-mbstring": "to use Strings::lower() etc...",
35
+ "ext-gd": "to use Image",
36
+ "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
37
+ },
38
+ "autoload": {
39
+ "classmap": ["src/"]
40
+ },
41
+ "minimum-stability": "dev",
42
+ "scripts": {
43
+ "phpstan": "phpstan analyse",
44
+ "tester": "tester tests -s"
45
+ },
46
+ "extra": {
47
+ "branch-alias": {
48
+ "dev-master": "4.0-dev"
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,60 @@
1
+ Licenses
2
+ ========
3
+
4
+ Good news! You may use Nette Framework under the terms of either
5
+ the New BSD License or the GNU General Public License (GPL) version 2 or 3.
6
+
7
+ The BSD License is recommended for most projects. It is easy to understand and it
8
+ places almost no restrictions on what you can do with the framework. If the GPL
9
+ fits better to your project, you can use the framework under this license.
10
+
11
+ You don't have to notify anyone which license you are using. You can freely
12
+ use Nette Framework in commercial projects as long as the copyright header
13
+ remains intact.
14
+
15
+ Please be advised that the name "Nette Framework" is a protected trademark and its
16
+ usage has some limitations. So please do not use word "Nette" in the name of your
17
+ project or top-level domain, and choose a name that stands on its own merits.
18
+ If your stuff is good, it will not take long to establish a reputation for yourselves.
19
+
20
+
21
+ New BSD License
22
+ ---------------
23
+
24
+ Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
25
+ All rights reserved.
26
+
27
+ Redistribution and use in source and binary forms, with or without modification,
28
+ are permitted provided that the following conditions are met:
29
+
30
+ * Redistributions of source code must retain the above copyright notice,
31
+ this list of conditions and the following disclaimer.
32
+
33
+ * Redistributions in binary form must reproduce the above copyright notice,
34
+ this list of conditions and the following disclaimer in the documentation
35
+ and/or other materials provided with the distribution.
36
+
37
+ * Neither the name of "Nette Framework" nor the names of its contributors
38
+ may be used to endorse or promote products derived from this software
39
+ without specific prior written permission.
40
+
41
+ This software is provided by the copyright holders and contributors "as is" and
42
+ any express or implied warranties, including, but not limited to, the implied
43
+ warranties of merchantability and fitness for a particular purpose are
44
+ disclaimed. In no event shall the copyright owner or contributors be liable for
45
+ any direct, indirect, incidental, special, exemplary, or consequential damages
46
+ (including, but not limited to, procurement of substitute goods or services;
47
+ loss of use, data, or profits; or business interruption) however caused and on
48
+ any theory of liability, whether in contract, strict liability, or tort
49
+ (including negligence or otherwise) arising in any way out of the use of this
50
+ software, even if advised of the possibility of such damage.
51
+
52
+
53
+ GNU General Public License
54
+ --------------------------
55
+
56
+ GPL licenses are very very long, so instead of including them here we offer
57
+ you URLs with full text:
58
+
59
+ - [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
60
+ - [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
@@ -0,0 +1,55 @@
1
+ [![Nette Utils](https://github.com/nette/utils/assets/194960/c33fdb74-0652-4cad-ac6e-c1ce0d29e32a)](https://doc.nette.org/en/utils)
2
+
3
+ [![Downloads this Month](https://img.shields.io/packagist/dm/nette/utils.svg)](https://packagist.org/packages/nette/utils)
4
+ [![Tests](https://github.com/nette/utils/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/utils/actions)
5
+ [![Coverage Status](https://coveralls.io/repos/github/nette/utils/badge.svg?branch=master)](https://coveralls.io/github/nette/utils?branch=master)
6
+ [![Latest Stable Version](https://poser.pugx.org/nette/utils/v/stable)](https://github.com/nette/utils/releases)
7
+ [![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/utils/blob/master/license.md)
8
+
9
+
10
+ Introduction
11
+ ------------
12
+
13
+ In package nette/utils you will find a set of useful classes for everyday use:
14
+
15
+ ✅ [Arrays](https://doc.nette.org/utils/arrays)<br>
16
+ ✅ [Callback](https://doc.nette.org/utils/callback) - PHP callbacks<br>
17
+ ✅ [Filesystem](https://doc.nette.org/utils/filesystem) - copying, renaming, …<br>
18
+ ✅ [Finder](https://doc.nette.org/utils/finder) - finds files and directories<br>
19
+ ✅ [Floats](https://doc.nette.org/utils/floats) - floating point numbers<br>
20
+ ✅ [Helper Functions](https://doc.nette.org/utils/helpers)<br>
21
+ ✅ [HTML elements](https://doc.nette.org/utils/html-elements) - generate HTML<br>
22
+ ✅ [Images](https://doc.nette.org/utils/images) - crop, resize, rotate images<br>
23
+ ✅ [Iterables](https://doc.nette.org/utils/iterables) <br>
24
+ ✅ [JSON](https://doc.nette.org/utils/json) - encoding and decoding<br>
25
+ ✅ [Generating Random Strings](https://doc.nette.org/utils/random)<br>
26
+ ✅ [Paginator](https://doc.nette.org/utils/paginator) - pagination math<br>
27
+ ✅ [PHP Reflection](https://doc.nette.org/utils/reflection)<br>
28
+ ✅ [Strings](https://doc.nette.org/utils/strings) - useful text functions<br>
29
+ ✅ [SmartObject](https://doc.nette.org/utils/smartobject) - PHP object enhancements<br>
30
+ ✅ [Type](https://doc.nette.org/utils/type) - PHP data type<br>
31
+ ✅ [Validation](https://doc.nette.org/utils/validators) - validate inputs<br>
32
+
33
+  <!---->
34
+
35
+ Installation
36
+ ------------
37
+
38
+ The recommended way to install is via Composer:
39
+
40
+ ```
41
+ composer require nette/utils
42
+ ```
43
+
44
+ Nette Utils 4.0 is compatible with PHP 8.0 to 8.4.
45
+
46
+  <!---->
47
+
48
+ [Support Me](https://github.com/sponsors/dg)
49
+ --------------------------------------------
50
+
51
+ Do you like Nette Utils? Are you looking forward to the new features?
52
+
53
+ [![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)
54
+
55
+ Thank you!
@@ -0,0 +1,22 @@
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;
11
+
12
+
13
+ interface HtmlStringable
14
+ {
15
+ /**
16
+ * Returns string in HTML format
17
+ */
18
+ function __toString(): string;
19
+ }
20
+
21
+
22
+ interface_exists(Utils\IHtmlString::class);
@@ -0,0 +1,150 @@
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\Iterators;
11
+
12
+ use Nette;
13
+
14
+
15
+ /**
16
+ * Smarter caching iterator.
17
+ *
18
+ * @property-read bool $first
19
+ * @property-read bool $last
20
+ * @property-read bool $empty
21
+ * @property-read bool $odd
22
+ * @property-read bool $even
23
+ * @property-read int $counter
24
+ * @property-read mixed $nextKey
25
+ * @property-read mixed $nextValue
26
+ */
27
+ class CachingIterator extends \CachingIterator implements \Countable
28
+ {
29
+ use Nette\SmartObject;
30
+
31
+ private int $counter = 0;
32
+
33
+
34
+ public function __construct(iterable|\stdClass $iterable)
35
+ {
36
+ $iterable = $iterable instanceof \stdClass
37
+ ? new \ArrayIterator($iterable)
38
+ : Nette\Utils\Iterables::toIterator($iterable);
39
+ parent::__construct($iterable, 0);
40
+ }
41
+
42
+
43
+ /**
44
+ * Is the current element the first one?
45
+ */
46
+ public function isFirst(?int $gridWidth = null): bool
47
+ {
48
+ return $this->counter === 1 || ($gridWidth && $this->counter !== 0 && (($this->counter - 1) % $gridWidth) === 0);
49
+ }
50
+
51
+
52
+ /**
53
+ * Is the current element the last one?
54
+ */
55
+ public function isLast(?int $gridWidth = null): bool
56
+ {
57
+ return !$this->hasNext() || ($gridWidth && ($this->counter % $gridWidth) === 0);
58
+ }
59
+
60
+
61
+ /**
62
+ * Is the iterator empty?
63
+ */
64
+ public function isEmpty(): bool
65
+ {
66
+ return $this->counter === 0;
67
+ }
68
+
69
+
70
+ /**
71
+ * Is the counter odd?
72
+ */
73
+ public function isOdd(): bool
74
+ {
75
+ return $this->counter % 2 === 1;
76
+ }
77
+
78
+
79
+ /**
80
+ * Is the counter even?
81
+ */
82
+ public function isEven(): bool
83
+ {
84
+ return $this->counter % 2 === 0;
85
+ }
86
+
87
+
88
+ /**
89
+ * Returns the counter.
90
+ */
91
+ public function getCounter(): int
92
+ {
93
+ return $this->counter;
94
+ }
95
+
96
+
97
+ /**
98
+ * Returns the count of elements.
99
+ */
100
+ public function count(): int
101
+ {
102
+ $inner = $this->getInnerIterator();
103
+ if ($inner instanceof \Countable) {
104
+ return $inner->count();
105
+
106
+ } else {
107
+ throw new Nette\NotSupportedException('Iterator is not countable.');
108
+ }
109
+ }
110
+
111
+
112
+ /**
113
+ * Forwards to the next element.
114
+ */
115
+ public function next(): void
116
+ {
117
+ parent::next();
118
+ if (parent::valid()) {
119
+ $this->counter++;
120
+ }
121
+ }
122
+
123
+
124
+ /**
125
+ * Rewinds the Iterator.
126
+ */
127
+ public function rewind(): void
128
+ {
129
+ parent::rewind();
130
+ $this->counter = parent::valid() ? 1 : 0;
131
+ }
132
+
133
+
134
+ /**
135
+ * Returns the next key.
136
+ */
137
+ public function getNextKey(): mixed
138
+ {
139
+ return $this->getInnerIterator()->key();
140
+ }
141
+
142
+
143
+ /**
144
+ * Returns the next element.
145
+ */
146
+ public function getNextValue(): mixed
147
+ {
148
+ return $this->getInnerIterator()->current();
149
+ }
150
+ }