@vituum/vite-plugin-latte 2.0.0-next.4 → 2.0.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 (234) hide show
  1. package/README.md +1 -1
  2. package/index.js +4 -2
  3. package/package.json +11 -9
  4. package/types/index.d.ts +1 -1
  5. package/vendor/autoload.php +1 -4
  6. package/vendor/composer/InstalledVersions.php +36 -2
  7. package/vendor/composer/autoload_classmap.php +14 -15
  8. package/vendor/composer/autoload_psr4.php +2 -0
  9. package/vendor/composer/autoload_static.php +38 -15
  10. package/vendor/composer/installed.json +32 -22
  11. package/vendor/composer/installed.php +12 -12
  12. package/vendor/composer/platform_check.php +4 -5
  13. package/vendor/latte/latte/bin/latte-lint +10 -3
  14. package/vendor/latte/latte/composer.json +16 -6
  15. package/vendor/latte/latte/src/Bridges/Tracy/BlueScreenPanel.php +13 -38
  16. package/vendor/latte/latte/src/Bridges/Tracy/LattePanel.php +9 -7
  17. package/vendor/latte/latte/src/Bridges/Tracy/TracyExtension.php +2 -4
  18. package/vendor/latte/latte/src/Bridges/Tracy/dist/panel.phtml +94 -0
  19. package/vendor/latte/latte/src/Bridges/Tracy/dist/tab.phtml +10 -0
  20. package/vendor/latte/latte/src/Latte/Compiler/Block.php +4 -6
  21. package/vendor/latte/latte/src/Latte/Compiler/Escaper.php +67 -86
  22. package/vendor/latte/latte/src/Latte/Compiler/Node.php +6 -3
  23. package/vendor/latte/latte/src/Latte/Compiler/NodeHelpers.php +16 -6
  24. package/vendor/latte/latte/src/Latte/Compiler/NodeTraverser.php +25 -12
  25. package/vendor/latte/latte/src/Latte/Compiler/Nodes/AreaNode.php +7 -3
  26. package/vendor/latte/latte/src/Latte/Compiler/Nodes/AuxiliaryNode.php +5 -4
  27. package/vendor/latte/latte/src/Latte/Compiler/Nodes/FragmentNode.php +8 -4
  28. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/AttributeNode.php +7 -15
  29. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/BogusTagNode.php +4 -6
  30. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/CommentNode.php +4 -3
  31. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/ElementNode.php +37 -67
  32. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/ExpressionAttributeNode.php +60 -0
  33. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/TagNode.php +70 -0
  34. package/vendor/latte/latte/src/Latte/Compiler/Nodes/NopNode.php +4 -3
  35. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ArgumentNode.php +4 -3
  36. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ArrayItemNode.php +4 -15
  37. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ClosureUseNode.php +4 -3
  38. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ComplexTypeNode.php +4 -3
  39. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayAccessNode.php +4 -3
  40. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayNode.php +6 -22
  41. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignNode.php +18 -5
  42. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignOpNode.php +18 -7
  43. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AuxiliaryNode.php +5 -4
  44. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/BinaryOpNode.php +38 -9
  45. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/CastNode.php +14 -6
  46. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClassConstantFetchNode.php +4 -3
  47. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/CloneNode.php +12 -4
  48. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClosureNode.php +10 -6
  49. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ConstantFetchNode.php +7 -6
  50. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/EmptyNode.php +4 -3
  51. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FilterCallNode.php +10 -4
  52. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FunctionCallNode.php +14 -5
  53. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/InNode.php +4 -3
  54. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/InstanceofNode.php +14 -5
  55. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/IssetNode.php +6 -3
  56. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MatchNode.php +6 -3
  57. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MethodCallNode.php +18 -5
  58. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/NewNode.php +14 -4
  59. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PostOpNode.php +14 -6
  60. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PreOpNode.php +14 -6
  61. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PropertyFetchNode.php +4 -3
  62. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticMethodCallNode.php +14 -15
  63. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticPropertyFetchNode.php +4 -3
  64. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/TemporaryNode.php +7 -6
  65. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/TernaryNode.php +16 -11
  66. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/UnaryOpNode.php +19 -9
  67. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/VariableNode.php +4 -3
  68. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ExpressionNode.php +4 -3
  69. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/FilterNode.php +33 -8
  70. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/IdentifierNode.php +4 -3
  71. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/InterpolatedStringPartNode.php +4 -3
  72. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/IntersectionTypeNode.php +6 -3
  73. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ListItemNode.php +4 -3
  74. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ListNode.php +4 -3
  75. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/MatchArmNode.php +6 -3
  76. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php +29 -41
  77. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NameNode.php +9 -4
  78. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NullableTypeNode.php +4 -3
  79. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/OperatorNode.php +27 -0
  80. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ParameterNode.php +4 -3
  81. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/BooleanNode.php +4 -3
  82. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/FloatNode.php +9 -6
  83. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/IntegerNode.php +8 -6
  84. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/InterpolatedStringNode.php +9 -5
  85. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/NullNode.php +4 -3
  86. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/StringNode.php +6 -4
  87. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ScalarNode.php +4 -3
  88. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/SuperiorTypeNode.php +4 -3
  89. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/UnionTypeNode.php +6 -3
  90. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/VarLikeIdentifierNode.php +4 -3
  91. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/{Expression/NotNode.php → VariadicPlaceholderNode.php} +9 -9
  92. package/vendor/latte/latte/src/Latte/{Essential → Compiler}/Nodes/PrintNode.php +9 -15
  93. package/vendor/latte/latte/src/Latte/Compiler/Nodes/StatementNode.php +7 -3
  94. package/vendor/latte/latte/src/Latte/Compiler/Nodes/TemplateNode.php +4 -3
  95. package/vendor/latte/latte/src/Latte/Compiler/Nodes/TextNode.php +6 -4
  96. package/vendor/latte/latte/src/Latte/Compiler/PhpHelpers.php +32 -18
  97. package/vendor/latte/latte/src/Latte/Compiler/Position.php +7 -7
  98. package/vendor/latte/latte/src/Latte/Compiler/PrintContext.php +72 -104
  99. package/vendor/latte/latte/src/Latte/Compiler/Tag.php +17 -16
  100. package/vendor/latte/latte/src/Latte/Compiler/TagLexer.php +11 -8
  101. package/vendor/latte/latte/src/Latte/Compiler/TagParser.php +28 -23
  102. package/vendor/latte/latte/src/Latte/Compiler/TagParserData.php +360 -336
  103. package/vendor/latte/latte/src/Latte/Compiler/TemplateGenerator.php +49 -38
  104. package/vendor/latte/latte/src/Latte/Compiler/TemplateLexer.php +37 -12
  105. package/vendor/latte/latte/src/Latte/Compiler/TemplateParser.php +35 -21
  106. package/vendor/latte/latte/src/Latte/Compiler/TemplateParserHtml.php +121 -71
  107. package/vendor/latte/latte/src/Latte/Compiler/Token.php +79 -70
  108. package/vendor/latte/latte/src/Latte/Compiler/TokenStream.php +21 -14
  109. package/vendor/latte/latte/src/Latte/ContentType.php +4 -3
  110. package/vendor/latte/latte/src/Latte/Engine.php +147 -188
  111. package/vendor/latte/latte/src/Latte/Essential/AuxiliaryIterator.php +5 -7
  112. package/vendor/latte/latte/src/Latte/Essential/Blueprint.php +5 -5
  113. package/vendor/latte/latte/src/Latte/Essential/CachingIterator.php +5 -4
  114. package/vendor/latte/latte/src/Latte/Essential/CoreExtension.php +155 -127
  115. package/vendor/latte/latte/src/Latte/Essential/Filters.php +99 -44
  116. package/vendor/latte/latte/src/Latte/Essential/Nodes/BlockNode.php +14 -13
  117. package/vendor/latte/latte/src/Latte/Essential/Nodes/CaptureNode.php +5 -6
  118. package/vendor/latte/latte/src/Latte/Essential/Nodes/ContentTypeNode.php +3 -4
  119. package/vendor/latte/latte/src/Latte/Essential/Nodes/CustomFunctionCallNode.php +46 -0
  120. package/vendor/latte/latte/src/Latte/Essential/Nodes/DebugbreakNode.php +2 -3
  121. package/vendor/latte/latte/src/Latte/Essential/Nodes/DefineNode.php +10 -7
  122. package/vendor/latte/latte/src/Latte/Essential/Nodes/DoNode.php +3 -4
  123. package/vendor/latte/latte/src/Latte/Essential/Nodes/DumpNode.php +2 -3
  124. package/vendor/latte/latte/src/Latte/Essential/Nodes/EmbedNode.php +8 -9
  125. package/vendor/latte/latte/src/Latte/Essential/Nodes/ExtendsNode.php +3 -5
  126. package/vendor/latte/latte/src/Latte/Essential/Nodes/FirstLastSepNode.php +4 -7
  127. package/vendor/latte/latte/src/Latte/Essential/Nodes/ForNode.php +6 -5
  128. package/vendor/latte/latte/src/Latte/Essential/Nodes/ForeachNode.php +7 -7
  129. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfChangedNode.php +4 -5
  130. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfContentNode.php +7 -6
  131. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfNode.php +11 -11
  132. package/vendor/latte/latte/src/Latte/Essential/Nodes/ImportNode.php +5 -6
  133. package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeBlockNode.php +26 -27
  134. package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeFileNode.php +7 -10
  135. package/vendor/latte/latte/src/Latte/Essential/Nodes/IterateWhileNode.php +6 -6
  136. package/vendor/latte/latte/src/Latte/Essential/Nodes/JumpNode.php +4 -8
  137. package/vendor/latte/latte/src/Latte/Essential/Nodes/NAttrNode.php +35 -47
  138. package/vendor/latte/latte/src/Latte/Essential/Nodes/NClassNode.php +4 -5
  139. package/vendor/latte/latte/src/Latte/Essential/Nodes/NElseNode.php +69 -34
  140. package/vendor/latte/latte/src/Latte/Essential/Nodes/NTagNode.php +9 -33
  141. package/vendor/latte/latte/src/Latte/Essential/Nodes/ParametersNode.php +7 -4
  142. package/vendor/latte/latte/src/Latte/Essential/Nodes/RawPhpNode.php +3 -4
  143. package/vendor/latte/latte/src/Latte/Essential/Nodes/RollbackNode.php +2 -3
  144. package/vendor/latte/latte/src/Latte/Essential/Nodes/SpacelessNode.php +4 -5
  145. package/vendor/latte/latte/src/Latte/Essential/Nodes/SwitchNode.php +9 -7
  146. package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplatePrintNode.php +4 -4
  147. package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplateTypeNode.php +3 -4
  148. package/vendor/latte/latte/src/Latte/Essential/Nodes/TraceNode.php +2 -3
  149. package/vendor/latte/latte/src/Latte/Essential/Nodes/TranslateNode.php +5 -5
  150. package/vendor/latte/latte/src/Latte/Essential/Nodes/TryNode.php +4 -5
  151. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarNode.php +10 -6
  152. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarPrintNode.php +2 -3
  153. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarTypeNode.php +3 -4
  154. package/vendor/latte/latte/src/Latte/Essential/Nodes/WhileNode.php +5 -5
  155. package/vendor/latte/latte/src/Latte/Essential/Passes.php +82 -21
  156. package/vendor/latte/latte/src/Latte/Essential/RawPhpExtension.php +2 -4
  157. package/vendor/latte/latte/src/Latte/Essential/RollbackException.php +1 -3
  158. package/vendor/latte/latte/src/Latte/Essential/Tracer.php +24 -28
  159. package/vendor/latte/latte/src/Latte/Essential/TranslatorExtension.php +14 -14
  160. package/vendor/latte/latte/src/Latte/Extension.php +12 -6
  161. package/vendor/latte/latte/src/Latte/Feature.php +24 -0
  162. package/vendor/latte/latte/src/Latte/Helpers.php +65 -15
  163. package/vendor/latte/latte/src/Latte/Loader.php +1 -9
  164. package/vendor/latte/latte/src/Latte/Loaders/FileLoader.php +11 -17
  165. package/vendor/latte/latte/src/Latte/Loaders/StringLoader.php +7 -21
  166. package/vendor/latte/latte/src/Latte/Policy.php +4 -3
  167. package/vendor/latte/latte/src/Latte/Runtime/Block.php +2 -4
  168. package/vendor/latte/latte/src/Latte/Runtime/Cache.php +143 -0
  169. package/vendor/latte/latte/src/Latte/Runtime/FilterExecutor.php +5 -6
  170. package/vendor/latte/latte/src/Latte/Runtime/FilterInfo.php +11 -11
  171. package/vendor/latte/latte/src/Latte/Runtime/FunctionExecutor.php +5 -6
  172. package/vendor/latte/latte/src/Latte/Runtime/Helpers.php +91 -0
  173. package/vendor/latte/latte/src/Latte/Runtime/Html.php +3 -5
  174. package/vendor/latte/latte/src/Latte/Runtime/HtmlHelpers.php +374 -0
  175. package/vendor/latte/latte/src/Latte/Runtime/HtmlStringable.php +1 -3
  176. package/vendor/latte/latte/src/Latte/Runtime/Template.php +162 -182
  177. package/vendor/latte/latte/src/Latte/Runtime/XmlHelpers.php +108 -0
  178. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallNode.php +12 -4
  179. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallNode.php +15 -5
  180. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/PropertyFetchNode.php +4 -3
  181. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/SandboxNode.php +5 -6
  182. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticMethodCallNode.php +14 -4
  183. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticPropertyFetchNode.php +4 -3
  184. package/vendor/latte/latte/src/Latte/Sandbox/RuntimeChecker.php +8 -6
  185. package/vendor/latte/latte/src/Latte/Sandbox/SandboxExtension.php +16 -12
  186. package/vendor/latte/latte/src/Latte/Sandbox/SecurityPolicy.php +18 -16
  187. package/vendor/latte/latte/src/Latte/attributes.php +7 -3
  188. package/vendor/latte/latte/src/Latte/exceptions.php +52 -6
  189. package/vendor/latte/latte/src/Tools/Linter.php +74 -28
  190. package/vendor/latte/latte/src/Tools/LinterExtension.php +176 -0
  191. package/vendor/nette/utils/composer.json +15 -5
  192. package/vendor/nette/utils/readme.md +1 -1
  193. package/vendor/nette/utils/src/HtmlStringable.php +4 -1
  194. package/vendor/nette/utils/src/Iterators/CachingIterator.php +10 -25
  195. package/vendor/nette/utils/src/Iterators/Mapper.php +2 -3
  196. package/vendor/nette/utils/src/SmartObject.php +3 -0
  197. package/vendor/nette/utils/src/StaticClass.php +1 -11
  198. package/vendor/nette/utils/src/Translator.php +1 -1
  199. package/vendor/nette/utils/src/Utils/ArrayHash.php +6 -10
  200. package/vendor/nette/utils/src/Utils/ArrayList.php +8 -12
  201. package/vendor/nette/utils/src/Utils/Arrays.php +38 -18
  202. package/vendor/nette/utils/src/Utils/Callback.php +13 -8
  203. package/vendor/nette/utils/src/Utils/DateTime.php +95 -26
  204. package/vendor/nette/utils/src/Utils/FileInfo.php +6 -7
  205. package/vendor/nette/utils/src/Utils/FileSystem.php +10 -5
  206. package/vendor/nette/utils/src/Utils/Finder.php +31 -12
  207. package/vendor/nette/utils/src/Utils/Floats.php +1 -0
  208. package/vendor/nette/utils/src/Utils/Helpers.php +22 -2
  209. package/vendor/nette/utils/src/Utils/Html.php +130 -127
  210. package/vendor/nette/utils/src/Utils/Image.php +80 -60
  211. package/vendor/nette/utils/src/Utils/ImageColor.php +5 -0
  212. package/vendor/nette/utils/src/Utils/ImageType.php +2 -0
  213. package/vendor/nette/utils/src/Utils/Iterables.php +41 -7
  214. package/vendor/nette/utils/src/Utils/Json.php +2 -0
  215. package/vendor/nette/utils/src/Utils/ObjectHelpers.php +2 -0
  216. package/vendor/nette/utils/src/Utils/Paginator.php +10 -43
  217. package/vendor/nette/utils/src/Utils/Random.php +2 -0
  218. package/vendor/nette/utils/src/Utils/Reflection.php +22 -15
  219. package/vendor/nette/utils/src/Utils/ReflectionMethod.php +6 -1
  220. package/vendor/nette/utils/src/Utils/Strings.php +62 -57
  221. package/vendor/nette/utils/src/Utils/Type.php +91 -42
  222. package/vendor/nette/utils/src/Utils/Validators.php +9 -7
  223. package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.panel.phtml +0 -101
  224. package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.tab.phtml +0 -15
  225. package/vendor/latte/latte/src/Latte/Compiler/ExpressionBuilder.php +0 -129
  226. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ErrorSuppressNode.php +0 -36
  227. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FunctionCallableNode.php +0 -39
  228. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MethodCallableNode.php +0 -42
  229. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticMethodCallableNode.php +0 -57
  230. package/vendor/latte/latte/src/Latte/PositionAwareException.php +0 -47
  231. package/vendor/latte/latte/src/Latte/Runtime/Filters.php +0 -283
  232. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallableNode.php +0 -29
  233. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallableNode.php +0 -30
  234. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticMethodCallableNode.php +0 -30
@@ -1,15 +1,14 @@
1
- <?php
1
+ <?php declare(strict_types=1);
2
2
 
3
3
  /**
4
4
  * This file is part of the Latte (https://latte.nette.org)
5
5
  * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
6
  */
7
7
 
8
- declare(strict_types=1);
9
-
10
8
  namespace Latte\Compiler;
11
9
 
12
10
  use Latte\CompileException;
11
+ use function array_map, count, implode, is_int, is_string, trim;
13
12
 
14
13
 
15
14
  /**
@@ -20,13 +19,12 @@ final class TokenStream
20
19
  {
21
20
  /** @var Token[] */
22
21
  private array $tokens = [];
23
- private \Iterator /*readonly*/ $source;
24
22
  private int $index = 0;
25
23
 
26
24
 
27
- public function __construct(\Iterator $source)
28
- {
29
- $this->source = $source;
25
+ public function __construct(
26
+ private readonly \Iterator $source,
27
+ ) {
30
28
  }
31
29
 
32
30
 
@@ -39,10 +37,19 @@ final class TokenStream
39
37
  }
40
38
 
41
39
 
40
+ /**
41
+ * Gets the token at $offset from the current position or throws.
42
+ */
43
+ public function peek(int $offset = 0): Token
44
+ {
45
+ return $this->tryPeek($offset) ?? throw new CompileException('Unexpected end');
46
+ }
47
+
48
+
42
49
  /**
43
50
  * Gets the token at $offset from the current position.
44
51
  */
45
- public function peek(int $offset = 0): ?Token
52
+ public function tryPeek(int $offset = 0): ?Token
46
53
  {
47
54
  $pos = $this->index + $offset;
48
55
  while ($pos >= 0 && !isset($this->tokens[$pos]) && $this->source->valid()) {
@@ -81,8 +88,8 @@ final class TokenStream
81
88
  */
82
89
  public function tryConsume(int|string ...$kind): ?Token
83
90
  {
84
- $token = $this->peek();
85
- if (!$token->is(...$kind)) {
91
+ $token = $this->tryPeek();
92
+ if (!$token?->is(...$kind)) {
86
93
  return null;
87
94
  } elseif (!$token->isEnd()) {
88
95
  $this->index++;
@@ -114,11 +121,11 @@ final class TokenStream
114
121
 
115
122
  /**
116
123
  * @throws CompileException
117
- * @return never
124
+ * @param array<string|int> $expected
118
125
  */
119
- public function throwUnexpectedException(array $expected = [], string $addendum = '', string $excerpt = ''): void
126
+ public function throwUnexpectedException(array $expected = [], string $addendum = '', string $excerpt = ''): never
120
127
  {
121
- $token = $this->peek()->text . $excerpt;
128
+ $token = ($this->tryPeek()->text ?? '') . $excerpt;
122
129
  $expected = array_map(fn($item) => is_int($item) ? Token::Names[$item] : $item, $expected);
123
130
  throw new CompileException(
124
131
  'Unexpected '
@@ -129,7 +136,7 @@ final class TokenStream
129
136
  ? ', expecting ' . implode(', ', $expected)
130
137
  : '')
131
138
  . $addendum,
132
- $this->peek()->position,
139
+ $this->tryPeek()?->position,
133
140
  );
134
141
  }
135
142
  }
@@ -1,15 +1,16 @@
1
- <?php
1
+ <?php declare(strict_types=1);
2
2
 
3
3
  /**
4
4
  * This file is part of the Latte (https://latte.nette.org)
5
5
  * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
6
  */
7
7
 
8
- declare(strict_types=1);
9
-
10
8
  namespace Latte;
11
9
 
12
10
 
11
+ /**
12
+ * Content type constants for context-aware escaping.
13
+ */
13
14
  /*enum*/ final class ContentType
14
15
  {
15
16
  public const
@@ -1,15 +1,15 @@
1
- <?php
1
+ <?php declare(strict_types=1);
2
2
 
3
3
  /**
4
4
  * This file is part of the Latte (https://latte.nette.org)
5
5
  * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
6
  */
7
7
 
8
- declare(strict_types=1);
9
-
10
8
  namespace Latte;
11
9
 
12
10
  use Latte\Compiler\Nodes\TemplateNode;
11
+ use function array_map, array_merge, class_exists, extension_loaded, get_debug_type, get_object_vars, is_array, preg_match, serialize, substr;
12
+ use const PHP_VERSION_ID;
13
13
 
14
14
 
15
15
  /**
@@ -17,22 +17,31 @@ use Latte\Compiler\Nodes\TemplateNode;
17
17
  */
18
18
  class Engine
19
19
  {
20
- public const Version = '3.0.20';
21
- public const VersionId = 30020;
20
+ public const Version = '3.1.2';
21
+ public const VersionId = 30102;
22
22
 
23
23
  /** @deprecated use Engine::Version */
24
24
  public const
25
25
  VERSION = self::Version,
26
26
  VERSION_ID = self::VersionId;
27
27
 
28
- /** @deprecated use ContentType::* */
29
- public const
30
- CONTENT_HTML = ContentType::Html,
31
- CONTENT_XML = ContentType::Xml,
32
- CONTENT_JS = ContentType::JavaScript,
33
- CONTENT_CSS = ContentType::Css,
34
- CONTENT_ICAL = ContentType::ICal,
35
- CONTENT_TEXT = ContentType::Text;
28
+ #[\Deprecated('use Latte\ContentType::Html')]
29
+ public const CONTENT_HTML = ContentType::Html;
30
+
31
+ #[\Deprecated('use Latte\ContentType::Xml')]
32
+ public const CONTENT_XML = ContentType::Xml;
33
+
34
+ #[\Deprecated('use Latte\ContentType::JavaScript')]
35
+ public const CONTENT_JS = ContentType::JavaScript;
36
+
37
+ #[\Deprecated('use Latte\ContentType::Css')]
38
+ public const CONTENT_CSS = ContentType::Css;
39
+
40
+ #[\Deprecated('use Latte\ContentType::ICal')]
41
+ public const CONTENT_ICAL = ContentType::ICal;
42
+
43
+ #[\Deprecated('use Latte\ContentType::Text')]
44
+ public const CONTENT_TEXT = ContentType::Text;
36
45
 
37
46
  private ?Loader $loader = null;
38
47
  private Runtime\FilterExecutor $filters;
@@ -42,19 +51,24 @@ class Engine
42
51
  /** @var Extension[] */
43
52
  private array $extensions = [];
44
53
  private string $contentType = ContentType::Html;
45
- private ?string $tempDirectory = null;
46
- private bool $autoRefresh = true;
47
- private bool $strictTypes = false;
48
- private bool $strictParsing = false;
54
+ private Runtime\Cache $cache;
55
+
56
+ /** @var array<string, bool> */
57
+ private array $features = [
58
+ Feature::StrictTypes->name => true,
59
+ ];
60
+
49
61
  private ?Policy $policy = null;
50
62
  private bool $sandboxed = false;
51
63
  private ?string $phpBinary = null;
52
- private ?string $cacheKey;
64
+ private ?string $configurationHash;
53
65
  private ?string $locale = null;
66
+ private ?string $syntax = null;
54
67
 
55
68
 
56
69
  public function __construct()
57
70
  {
71
+ $this->cache = new Runtime\Cache;
58
72
  $this->filters = new Runtime\FilterExecutor;
59
73
  $this->functions = new Runtime\FunctionExecutor;
60
74
  $this->providers = new \stdClass;
@@ -91,14 +105,10 @@ class Engine
91
105
  * Creates template object.
92
106
  * @param mixed[] $params
93
107
  */
94
- public function createTemplate(string $name, array $params = [], $clearCache = true): Runtime\Template
108
+ public function createTemplate(string $name, array $params = [], bool $clearCache = true): Runtime\Template
95
109
  {
96
- $this->cacheKey = $clearCache ? null : $this->cacheKey;
97
- $class = $this->getTemplateClass($name);
98
- if (!class_exists($class, false)) {
99
- $this->loadTemplate($name);
100
- }
101
-
110
+ $this->configurationHash = $clearCache ? null : $this->configurationHash;
111
+ $class = $this->loadTemplate($name);
102
112
  $this->providers->fn = $this->functions;
103
113
  return new $class(
104
114
  $this,
@@ -148,7 +158,8 @@ class Engine
148
158
  public function parse(string $template): TemplateNode
149
159
  {
150
160
  $parser = new Compiler\TemplateParser;
151
- $parser->strict = $this->strictParsing;
161
+ $parser->getLexer()->setSyntax($this->syntax);
162
+ $parser->strict = $this->hasFeature(Feature::StrictParsing);
152
163
 
153
164
  foreach ($this->extensions as $extension) {
154
165
  $extension->beforeCompile($this);
@@ -186,12 +197,8 @@ class Engine
186
197
  public function generate(TemplateNode $node, string $name): string
187
198
  {
188
199
  $generator = new Compiler\TemplateGenerator;
189
- return $generator->generate(
190
- $node,
191
- $this->getTemplateClass($name),
192
- $name,
193
- $this->strictTypes,
194
- );
200
+ $generator->buildClass($node, $this->features);
201
+ return $generator->generateCode($this->getTemplateClass($name), $name, $this->hasFeature(Feature::StrictTypes));
195
202
  }
196
203
 
197
204
 
@@ -201,157 +208,77 @@ class Engine
201
208
  */
202
209
  public function warmupCache(string $name): void
203
210
  {
204
- if (!$this->tempDirectory) {
211
+ if (!$this->cache->directory) {
205
212
  throw new \LogicException('Path to temporary directory is not set.');
206
213
  }
207
214
 
208
- $class = $this->getTemplateClass($name);
209
- if (!class_exists($class, false)) {
210
- $this->loadTemplate($name);
211
- }
215
+ $this->loadTemplate($name);
212
216
  }
213
217
 
214
218
 
215
- private function loadTemplate(string $name): void
219
+ /** @return class-string<Runtime\Template> */
220
+ private function loadTemplate(string $name): string
216
221
  {
217
- if (!$this->tempDirectory) {
222
+ $class = $this->getTemplateClass($name);
223
+ if (class_exists($class, autoload: false)) {
224
+ // nothing
225
+ } elseif ($this->cache->directory) {
226
+ $this->cache->loadOrCreate($this, $name);
227
+ } else {
218
228
  $compiled = $this->compile($name);
219
229
  if (@eval(substr($compiled, 5)) === false) { // @ is escalated to exception, substr removes <?php
220
- throw (new CompileException('Error in template: ' . error_get_last()['message']))
230
+ throw (new CompileException('Error in template: ' . (error_get_last()['message'] ?? '')))
221
231
  ->setSource($compiled, "$name (compiled)");
222
232
  }
223
-
224
- return;
225
- }
226
-
227
- // Solving atomicity to work everywhere is really pain in the ass.
228
- // 1) We want to do as little as possible IO calls on production and also directory and file can be not writable
229
- // so on Linux we include the file directly without shared lock, therefore, the file must be created atomically by renaming.
230
- // 2) On Windows file cannot be renamed-to while is open (ie by include), so we have to acquire a lock.
231
- $cacheFile = $this->getCacheFile($name);
232
- $cacheKey = $this->autoRefresh
233
- ? md5(serialize($this->getCacheSignature($name)))
234
- : null;
235
- $lock = defined('PHP_WINDOWS_VERSION_BUILD') || $this->autoRefresh
236
- ? $this->acquireLock("$cacheFile.lock", LOCK_SH)
237
- : null;
238
-
239
- if (
240
- !($this->autoRefresh && $cacheKey !== stream_get_contents($lock))
241
- && (@include $cacheFile) !== false // @ - file may not exist
242
- ) {
243
- return;
244
- }
245
-
246
- if ($lock) {
247
- flock($lock, LOCK_UN); // release shared lock so we can get exclusive
248
- fseek($lock, 0);
249
- }
250
-
251
- $lock = $this->acquireLock("$cacheFile.lock", LOCK_EX);
252
-
253
- // while waiting for exclusive lock, someone might have already created the cache
254
- if (!is_file($cacheFile) || ($this->autoRefresh && $cacheKey !== stream_get_contents($lock))) {
255
- $compiled = $this->compile($name);
256
- if (
257
- file_put_contents("$cacheFile.tmp", $compiled) !== strlen($compiled)
258
- || !rename("$cacheFile.tmp", $cacheFile)
259
- ) {
260
- @unlink("$cacheFile.tmp"); // @ - file may not exist
261
- throw new RuntimeException("Unable to create '$cacheFile'.");
262
- }
263
-
264
- fseek($lock, 0);
265
- fwrite($lock, $cacheKey ?? md5(serialize($this->getCacheSignature($name))));
266
- ftruncate($lock, ftell($lock));
267
-
268
- if (function_exists('opcache_invalidate')) {
269
- @opcache_invalidate($cacheFile, true); // @ can be restricted
270
- }
271
- }
272
-
273
- if ((include $cacheFile) === false) {
274
- throw new RuntimeException("Unable to load '$cacheFile'.");
275
233
  }
276
-
277
- flock($lock, LOCK_UN);
234
+ return $class;
278
235
  }
279
236
 
280
237
 
281
238
  /**
282
- * @return resource
239
+ * Returns the file path where compiled template will be cached.
283
240
  */
284
- private function acquireLock(string $file, int $mode)
285
- {
286
- $dir = dirname($file);
287
- if (!is_dir($dir) && !@mkdir($dir) && !is_dir($dir)) { // @ - dir may already exist
288
- throw new RuntimeException("Unable to create directory '$dir'. " . error_get_last()['message']);
289
- }
290
-
291
- $handle = @fopen($file, 'c+'); // @ is escalated to exception
292
- if (!$handle) {
293
- throw new RuntimeException("Unable to create file '$file'. " . error_get_last()['message']);
294
- } elseif (!@flock($handle, $mode)) { // @ is escalated to exception
295
- throw new RuntimeException('Unable to acquire ' . ($mode & LOCK_EX ? 'exclusive' : 'shared') . " lock on file '$file'. " . error_get_last()['message']);
296
- }
297
-
298
- return $handle;
299
- }
300
-
301
-
302
241
  public function getCacheFile(string $name): string
303
242
  {
304
- $base = preg_match('#([/\\\\][\w@.-]{3,35}){1,3}$#D', '/' . $name, $m)
305
- ? preg_replace('#[^\w@.-]+#', '-', substr($m[0], 1)) . '--'
306
- : '';
307
- return $this->tempDirectory . '/' . $base . $this->generateCacheHash($name) . '.php';
243
+ return $this->cache->generateFilePath($this, $name);
308
244
  }
309
245
 
310
246
 
247
+ /**
248
+ * Returns the PHP class name for compiled template.
249
+ */
311
250
  public function getTemplateClass(string $name): string
312
251
  {
313
- return 'Template_' . $this->generateCacheHash($name);
314
- }
315
-
316
-
317
- private function generateCacheHash(string $name): string
318
- {
319
- $this->cacheKey ??= md5(serialize($this->getCacheKey()));
320
- $hash = $this->cacheKey . $this->getLoader()->getUniqueId($name);
321
- return substr(md5($hash), 0, 10);
252
+ return 'Template_' . $this->generateTemplateHash($name);
322
253
  }
323
254
 
324
255
 
325
256
  /**
326
- * Values that affect the results of compilation and the name of the cache file.
257
+ * Generates unique hash for template based on current configuration.
258
+ * Used to create isolated cache files for different engine configurations.
259
+ * @internal
327
260
  */
328
- protected function getCacheKey(): array
261
+ public function generateTemplateHash(string $name): string
329
262
  {
330
- return [
331
- $this->contentType,
332
- array_keys($this->getFunctions()),
333
- array_map(
334
- fn($extension) => [
335
- get_debug_type($extension),
336
- $extension->getCacheKey($this),
337
- filemtime((new \ReflectionObject($extension))->getFileName()),
338
- ],
339
- $this->extensions,
340
- ),
341
- ];
263
+ $hash = $this->configurationHash ?? hash('xxh128', serialize($this->generateConfigurationSignature()));
264
+ $hash .= $this->getLoader()->getUniqueId($name);
265
+ return substr(hash('xxh128', $hash), 0, 10);
342
266
  }
343
267
 
344
268
 
345
269
  /**
346
- * Values that check the expiration of the compiled template.
270
+ * Returns values that determine isolation for different configurations.
271
+ * When any of these values change, a new compiled template is created to avoid conflicts.
272
+ * @return list<mixed>
347
273
  */
348
- protected function getCacheSignature(string $name): array
274
+ protected function generateConfigurationSignature(): array
349
275
  {
350
276
  return [
351
- self::Version,
352
- $this->getLoader()->getContent($name),
277
+ $this->contentType,
278
+ $this->features,
279
+ $this->syntax,
353
280
  array_map(
354
- fn($extension) => filemtime((new \ReflectionObject($extension))->getFileName()),
281
+ fn($extension) => [get_debug_type($extension), $extension->getCacheKey($this)],
355
282
  $this->extensions,
356
283
  ),
357
284
  ];
@@ -372,11 +299,10 @@ class Engine
372
299
  }
373
300
 
374
301
 
375
- /**
376
- * Registers filter loader.
377
- */
302
+ #[\Deprecated('Use addFilter() instead.')]
378
303
  public function addFilterLoader(callable $loader): static
379
304
  {
305
+ trigger_error('Filter loader is deprecated, use addFilter() instead.', E_USER_DEPRECATED);
380
306
  $this->filters->add(null, $loader);
381
307
  return $this;
382
308
  }
@@ -384,7 +310,7 @@ class Engine
384
310
 
385
311
  /**
386
312
  * Returns all run-time filters.
387
- * @return callable[]
313
+ * @return array<string, callable>
388
314
  */
389
315
  public function getFilters(): array
390
316
  {
@@ -423,10 +349,10 @@ class Engine
423
349
  }
424
350
 
425
351
 
426
- /** @return Extension[] */
352
+ /** @return list<Extension> */
427
353
  public function getExtensions(): array
428
354
  {
429
- return $this->extensions;
355
+ return array_values($this->extensions);
430
356
  }
431
357
 
432
358
 
@@ -455,7 +381,7 @@ class Engine
455
381
 
456
382
 
457
383
  /**
458
- * @return callable[]
384
+ * @return array<string, callable>
459
385
  */
460
386
  public function getFunctions(): array
461
387
  {
@@ -479,7 +405,7 @@ class Engine
479
405
 
480
406
  /**
481
407
  * Returns all providers.
482
- * @return mixed[]
408
+ * @return array<string, mixed>
483
409
  */
484
410
  public function getProviders(): array
485
411
  {
@@ -504,7 +430,7 @@ class Engine
504
430
 
505
431
  public function setExceptionHandler(callable $handler): static
506
432
  {
507
- $this->providers->coreExceptionHandler = $handler;
433
+ $this->providers->coreExceptionHandler = $handler(...);
508
434
  return $this;
509
435
  }
510
436
 
@@ -524,45 +450,72 @@ class Engine
524
450
 
525
451
 
526
452
  /**
527
- * Sets path to temporary directory.
453
+ * Sets path to cache directory.
528
454
  */
529
- public function setTempDirectory(?string $path): static
455
+ public function setCacheDirectory(?string $path): static
530
456
  {
531
- $this->tempDirectory = $path;
457
+ $this->cache->directory = $path;
532
458
  return $this;
533
459
  }
534
460
 
535
461
 
462
+ /** @deprecated use setCacheDirectory() instead */
463
+ public function setTempDirectory(?string $path): static
464
+ {
465
+ return $this->setCacheDirectory($path);
466
+ }
467
+
468
+
536
469
  /**
537
470
  * Sets auto-refresh mode.
538
471
  */
539
472
  public function setAutoRefresh(bool $state = true): static
540
473
  {
541
- $this->autoRefresh = $state;
474
+ $this->cache->autoRefresh = $state;
475
+ return $this;
476
+ }
477
+
478
+
479
+ /**
480
+ * Enables or disables an engine feature.
481
+ */
482
+ public function setFeature(Feature $feature, bool $state = true): static
483
+ {
484
+ $this->features[$feature->name] = $state;
542
485
  return $this;
543
486
  }
544
487
 
545
488
 
489
+ /**
490
+ * Checks if a feature is enabled.
491
+ */
492
+ public function hasFeature(Feature $feature): bool
493
+ {
494
+ return $this->features[$feature->name] ?? false;
495
+ }
496
+
497
+
546
498
  /**
547
499
  * Enables declare(strict_types=1) in templates.
500
+ * @deprecated use setFeature(Feature::StrictTypes, ...) instead
548
501
  */
549
502
  public function setStrictTypes(bool $state = true): static
550
503
  {
551
- $this->strictTypes = $state;
552
- return $this;
504
+ return $this->setFeature(Feature::StrictTypes, $state);
553
505
  }
554
506
 
555
507
 
508
+ /** @deprecated use setFeature(Feature::StrictParsing, ...) instead */
556
509
  public function setStrictParsing(bool $state = true): static
557
510
  {
558
- $this->strictParsing = $state;
559
- return $this;
511
+ return $this->setFeature(Feature::StrictParsing, $state);
560
512
  }
561
513
 
562
514
 
515
+ /** @deprecated use hasFeature(Feature::StrictParsing) instead */
563
516
  public function isStrictParsing(): bool
564
517
  {
565
- return $this->strictParsing;
518
+ return $this->hasFeature(Feature::StrictParsing);
566
519
  }
567
520
 
568
521
 
@@ -605,9 +558,26 @@ class Engine
605
558
  }
606
559
 
607
560
 
561
+ /**
562
+ * Sets default Latte syntax. Available options: 'single', 'double', 'off'
563
+ */
564
+ public function setSyntax(string $syntax): static
565
+ {
566
+ $this->syntax = $syntax;
567
+ return $this;
568
+ }
569
+
570
+
571
+ /** @deprecated use setFeature(Feature::MigrationWarnings, ...) instead */
572
+ public function setMigrationWarnings(bool $state = true): static
573
+ {
574
+ return $this->setFeature(Feature::MigrationWarnings, $state);
575
+ }
576
+
577
+
608
578
  /**
609
579
  * @param object|mixed[] $params
610
- * @return mixed[]
580
+ * @return array<string, mixed>
611
581
  */
612
582
  private function processParams(object|array $params): array
613
583
  {
@@ -615,39 +585,28 @@ class Engine
615
585
  return $params;
616
586
  }
617
587
 
618
- $methods = (new \ReflectionClass($params))->getMethods(\ReflectionMethod::IS_PUBLIC);
588
+ $rc = new \ReflectionClass($params);
589
+ $methods = $rc->getMethods(\ReflectionMethod::IS_PUBLIC);
619
590
  foreach ($methods as $method) {
620
591
  if ($method->getAttributes(Attributes\TemplateFilter::class)) {
621
- $this->addFilter($method->name, [$params, $method->name]);
592
+ $this->addFilter($method->name, $method->getClosure($params));
622
593
  }
623
594
 
624
595
  if ($method->getAttributes(Attributes\TemplateFunction::class)) {
625
- $this->addFunction($method->name, [$params, $method->name]);
626
- }
627
-
628
- if (strpos((string) $method->getDocComment(), '@filter')) {
629
- trigger_error('Annotation @filter is deprecated, use attribute #[Latte\Attributes\TemplateFilter]', E_USER_DEPRECATED);
630
- $this->addFilter($method->name, [$params, $method->name]);
596
+ $this->addFunction($method->name, $method->getClosure($params));
631
597
  }
598
+ }
632
599
 
633
- if (strpos((string) $method->getDocComment(), '@function')) {
634
- trigger_error('Annotation @function is deprecated, use attribute #[Latte\Attributes\TemplateFunction]', E_USER_DEPRECATED);
635
- $this->addFunction($method->name, [$params, $method->name]);
600
+ $res = get_object_vars($params);
601
+ if (PHP_VERSION_ID >= 80400) {
602
+ foreach ($rc->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
603
+ if ($property->isVirtual() && $property->hasHook(\PropertyHookType::Get)) {
604
+ $name = $property->getName();
605
+ $res[$name] = $params->$name;
606
+ }
636
607
  }
637
608
  }
638
609
 
639
- return array_filter((array) $params, fn($key) => $key[0] !== "\0", ARRAY_FILTER_USE_KEY);
640
- }
641
-
642
-
643
- public function __get(string $name)
644
- {
645
- if ($name === 'onCompile') {
646
- $trace = debug_backtrace(0)[0];
647
- $loc = isset($trace['file'], $trace['line'])
648
- ? ' (in ' . $trace['file'] . ' on ' . $trace['line'] . ')'
649
- : '';
650
- throw new \LogicException('You use Latte 3 together with the code designed for Latte 2' . $loc);
651
- }
610
+ return $res;
652
611
  }
653
612
  }
@@ -1,14 +1,14 @@
1
- <?php
1
+ <?php declare(strict_types=1);
2
2
 
3
3
  /**
4
4
  * This file is part of the Latte (https://latte.nette.org)
5
5
  * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
6
  */
7
7
 
8
- declare(strict_types=1);
9
-
10
8
  namespace Latte\Essential;
11
9
 
10
+ use function count;
11
+
12
12
 
13
13
  /**
14
14
  * Iterates over key-value pairs.
@@ -19,11 +19,9 @@ namespace Latte\Essential;
19
19
  */
20
20
  class AuxiliaryIterator implements \IteratorAggregate, \Countable
21
21
  {
22
- /**
23
- * @param array<array{K, V}> $pairs
24
- */
25
22
  public function __construct(
26
- private array $pairs,
23
+ /** @var array<array{K, V}> */
24
+ private readonly array $pairs,
27
25
  ) {
28
26
  }
29
27