@vituum/vite-plugin-latte 0.1.8

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 (201) hide show
  1. package/README.md +39 -0
  2. package/handler.js +9 -0
  3. package/index.js +138 -0
  4. package/index.php +173 -0
  5. package/latte/AssetFilter.php +11 -0
  6. package/latte/FetchFunction.php +28 -0
  7. package/latte/IconFilter.php +14 -0
  8. package/latte/JsonTag.php +64 -0
  9. package/latte/PlaceholderFunction.php +11 -0
  10. package/latte/RandomColorFunction.php +14 -0
  11. package/latte/TelFilter.php +22 -0
  12. package/package.json +35 -0
  13. package/vendor/autoload.php +7 -0
  14. package/vendor/bin/latte-lint +107 -0
  15. package/vendor/composer/ClassLoader.php +572 -0
  16. package/vendor/composer/InstalledVersions.php +350 -0
  17. package/vendor/composer/LICENSE +21 -0
  18. package/vendor/composer/autoload_classmap.php +183 -0
  19. package/vendor/composer/autoload_namespaces.php +9 -0
  20. package/vendor/composer/autoload_psr4.php +9 -0
  21. package/vendor/composer/autoload_real.php +57 -0
  22. package/vendor/composer/autoload_static.php +193 -0
  23. package/vendor/composer/installed.json +93 -0
  24. package/vendor/composer/installed.php +32 -0
  25. package/vendor/composer/platform_check.php +26 -0
  26. package/vendor/latte/latte/bin/latte-lint +29 -0
  27. package/vendor/latte/latte/composer.json +53 -0
  28. package/vendor/latte/latte/license.md +60 -0
  29. package/vendor/latte/latte/ncs.php +14 -0
  30. package/vendor/latte/latte/ncs.xml +9 -0
  31. package/vendor/latte/latte/readme.md +21 -0
  32. package/vendor/latte/latte/src/Bridges/Tracy/BlueScreenPanel.php +114 -0
  33. package/vendor/latte/latte/src/Bridges/Tracy/LattePanel.php +99 -0
  34. package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.panel.phtml +98 -0
  35. package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.tab.phtml +15 -0
  36. package/vendor/latte/latte/src/Latte/Compiler/Block.php +44 -0
  37. package/vendor/latte/latte/src/Latte/Compiler/Escaper.php +244 -0
  38. package/vendor/latte/latte/src/Latte/Compiler/ExpressionBuilder.php +128 -0
  39. package/vendor/latte/latte/src/Latte/Compiler/Node.php +28 -0
  40. package/vendor/latte/latte/src/Latte/Compiler/NodeHelpers.php +132 -0
  41. package/vendor/latte/latte/src/Latte/Compiler/NodeTraverser.php +77 -0
  42. package/vendor/latte/latte/src/Latte/Compiler/Nodes/AreaNode.php +17 -0
  43. package/vendor/latte/latte/src/Latte/Compiler/Nodes/AuxiliaryNode.php +27 -0
  44. package/vendor/latte/latte/src/Latte/Compiler/Nodes/FragmentNode.php +59 -0
  45. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/AttributeNode.php +48 -0
  46. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/BogusTagNode.php +46 -0
  47. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/CommentNode.php +39 -0
  48. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/ElementNode.php +129 -0
  49. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/QuotedValue.php +53 -0
  50. package/vendor/latte/latte/src/Latte/Compiler/Nodes/NopNode.php +21 -0
  51. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ArgumentNode.php +45 -0
  52. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ComplexTypeNode.php +17 -0
  53. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayAccessNode.php +41 -0
  54. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayItemNode.php +52 -0
  55. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayNode.php +94 -0
  56. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignNode.php +39 -0
  57. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignOpNode.php +45 -0
  58. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/BinaryOpNode.php +65 -0
  59. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/CastNode.php +43 -0
  60. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClassConstantFetchNode.php +42 -0
  61. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/CloneNode.php +36 -0
  62. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClosureNode.php +73 -0
  63. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClosureUseNode.php +37 -0
  64. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ConstantFetchNode.php +37 -0
  65. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/EmptyNode.php +36 -0
  66. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ErrorSuppressNode.php +36 -0
  67. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FilterCallNode.php +39 -0
  68. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FunctionCallNode.php +45 -0
  69. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FunctionCallableNode.php +39 -0
  70. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/InRangeNode.php +42 -0
  71. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/InstanceofNode.php +40 -0
  72. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/IssetNode.php +40 -0
  73. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MatchNode.php +49 -0
  74. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MethodCallNode.php +50 -0
  75. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MethodCallableNode.php +42 -0
  76. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/NewNode.php +45 -0
  77. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/NotNode.php +36 -0
  78. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PostOpNode.php +43 -0
  79. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PreOpNode.php +43 -0
  80. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PropertyFetchNode.php +42 -0
  81. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticCallNode.php +55 -0
  82. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticCallableNode.php +47 -0
  83. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticPropertyFetchNode.php +42 -0
  84. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/TernaryNode.php +50 -0
  85. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/UnaryOpNode.php +45 -0
  86. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/VariableNode.php +40 -0
  87. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ExpressionNode.php +17 -0
  88. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/FilterNode.php +67 -0
  89. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/IdentifierNode.php +36 -0
  90. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/IntersectionTypeNode.php +39 -0
  91. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/MatchArmNode.php +45 -0
  92. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php +107 -0
  93. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NameNode.php +89 -0
  94. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NullableTypeNode.php +35 -0
  95. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ParameterNode.php +54 -0
  96. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/BooleanNode.php +30 -0
  97. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/EncapsedStringNode.php +80 -0
  98. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/EncapsedStringPartNode.php +30 -0
  99. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/FloatNode.php +63 -0
  100. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/IntegerNode.php +70 -0
  101. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/NullNode.php +29 -0
  102. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/StringNode.php +40 -0
  103. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ScalarNode.php +15 -0
  104. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/SuperiorTypeNode.php +29 -0
  105. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/UnionTypeNode.php +39 -0
  106. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/VarLikeIdentifierNode.php +21 -0
  107. package/vendor/latte/latte/src/Latte/Compiler/Nodes/StatementNode.php +15 -0
  108. package/vendor/latte/latte/src/Latte/Compiler/Nodes/TemplateNode.php +34 -0
  109. package/vendor/latte/latte/src/Latte/Compiler/Nodes/TextNode.php +37 -0
  110. package/vendor/latte/latte/src/Latte/Compiler/PhpHelpers.php +227 -0
  111. package/vendor/latte/latte/src/Latte/Compiler/Position.php +43 -0
  112. package/vendor/latte/latte/src/Latte/Compiler/PrintContext.php +334 -0
  113. package/vendor/latte/latte/src/Latte/Compiler/Tag.php +117 -0
  114. package/vendor/latte/latte/src/Latte/Compiler/TagLexer.php +399 -0
  115. package/vendor/latte/latte/src/Latte/Compiler/TagParser.php +388 -0
  116. package/vendor/latte/latte/src/Latte/Compiler/TagParserData.php +580 -0
  117. package/vendor/latte/latte/src/Latte/Compiler/TemplateGenerator.php +206 -0
  118. package/vendor/latte/latte/src/Latte/Compiler/TemplateLexer.php +391 -0
  119. package/vendor/latte/latte/src/Latte/Compiler/TemplateParser.php +448 -0
  120. package/vendor/latte/latte/src/Latte/Compiler/TemplateParserHtml.php +506 -0
  121. package/vendor/latte/latte/src/Latte/Compiler/Token.php +259 -0
  122. package/vendor/latte/latte/src/Latte/Compiler/TokenStream.php +151 -0
  123. package/vendor/latte/latte/src/Latte/ContentType.php +22 -0
  124. package/vendor/latte/latte/src/Latte/Engine.php +591 -0
  125. package/vendor/latte/latte/src/Latte/Essential/Blueprint.php +160 -0
  126. package/vendor/latte/latte/src/Latte/Essential/CachingIterator.php +232 -0
  127. package/vendor/latte/latte/src/Latte/Essential/CoreExtension.php +232 -0
  128. package/vendor/latte/latte/src/Latte/Essential/Filters.php +591 -0
  129. package/vendor/latte/latte/src/Latte/Essential/Nodes/BlockNode.php +161 -0
  130. package/vendor/latte/latte/src/Latte/Essential/Nodes/CaptureNode.php +98 -0
  131. package/vendor/latte/latte/src/Latte/Essential/Nodes/ContentTypeNode.php +74 -0
  132. package/vendor/latte/latte/src/Latte/Essential/Nodes/DebugbreakNode.php +53 -0
  133. package/vendor/latte/latte/src/Latte/Essential/Nodes/DefineNode.php +134 -0
  134. package/vendor/latte/latte/src/Latte/Essential/Nodes/DoNode.php +49 -0
  135. package/vendor/latte/latte/src/Latte/Essential/Nodes/DumpNode.php +58 -0
  136. package/vendor/latte/latte/src/Latte/Essential/Nodes/EmbedNode.php +125 -0
  137. package/vendor/latte/latte/src/Latte/Essential/Nodes/ExtendsNode.php +60 -0
  138. package/vendor/latte/latte/src/Latte/Essential/Nodes/FirstLastSepNode.php +81 -0
  139. package/vendor/latte/latte/src/Latte/Essential/Nodes/ForNode.php +91 -0
  140. package/vendor/latte/latte/src/Latte/Essential/Nodes/ForeachNode.php +155 -0
  141. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfChangedNode.php +141 -0
  142. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfContentNode.php +82 -0
  143. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfNode.php +180 -0
  144. package/vendor/latte/latte/src/Latte/Essential/Nodes/ImportNode.php +49 -0
  145. package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeBlockNode.php +140 -0
  146. package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeFileNode.php +81 -0
  147. package/vendor/latte/latte/src/Latte/Essential/Nodes/IterateWhileNode.php +94 -0
  148. package/vendor/latte/latte/src/Latte/Essential/Nodes/NAttrNode.php +105 -0
  149. package/vendor/latte/latte/src/Latte/Essential/Nodes/NClassNode.php +54 -0
  150. package/vendor/latte/latte/src/Latte/Essential/Nodes/NTagNode.php +79 -0
  151. package/vendor/latte/latte/src/Latte/Essential/Nodes/ParametersNode.php +84 -0
  152. package/vendor/latte/latte/src/Latte/Essential/Nodes/PrintNode.php +70 -0
  153. package/vendor/latte/latte/src/Latte/Essential/Nodes/RawPhpNode.php +46 -0
  154. package/vendor/latte/latte/src/Latte/Essential/Nodes/RollbackNode.php +37 -0
  155. package/vendor/latte/latte/src/Latte/Essential/Nodes/SkipNode.php +71 -0
  156. package/vendor/latte/latte/src/Latte/Essential/Nodes/SpacelessNode.php +62 -0
  157. package/vendor/latte/latte/src/Latte/Essential/Nodes/SwitchNode.php +118 -0
  158. package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplatePrintNode.php +39 -0
  159. package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplateTypeNode.php +38 -0
  160. package/vendor/latte/latte/src/Latte/Essential/Nodes/TraceNode.php +35 -0
  161. package/vendor/latte/latte/src/Latte/Essential/Nodes/TranslateNode.php +104 -0
  162. package/vendor/latte/latte/src/Latte/Essential/Nodes/TryNode.php +75 -0
  163. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarNode.php +106 -0
  164. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarPrintNode.php +40 -0
  165. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarTypeNode.php +36 -0
  166. package/vendor/latte/latte/src/Latte/Essential/Nodes/WhileNode.php +81 -0
  167. package/vendor/latte/latte/src/Latte/Essential/Passes.php +115 -0
  168. package/vendor/latte/latte/src/Latte/Essential/RawPhpExtension.php +28 -0
  169. package/vendor/latte/latte/src/Latte/Essential/RollbackException.php +16 -0
  170. package/vendor/latte/latte/src/Latte/Essential/Tracer.php +117 -0
  171. package/vendor/latte/latte/src/Latte/Essential/TranslatorExtension.php +101 -0
  172. package/vendor/latte/latte/src/Latte/Extension.php +97 -0
  173. package/vendor/latte/latte/src/Latte/Helpers.php +96 -0
  174. package/vendor/latte/latte/src/Latte/Loader.php +37 -0
  175. package/vendor/latte/latte/src/Latte/Loaders/FileLoader.php +95 -0
  176. package/vendor/latte/latte/src/Latte/Loaders/StringLoader.php +76 -0
  177. package/vendor/latte/latte/src/Latte/Policy.php +24 -0
  178. package/vendor/latte/latte/src/Latte/PositionAwareException.php +50 -0
  179. package/vendor/latte/latte/src/Latte/Runtime/Block.php +24 -0
  180. package/vendor/latte/latte/src/Latte/Runtime/FilterExecutor.php +151 -0
  181. package/vendor/latte/latte/src/Latte/Runtime/FilterInfo.php +39 -0
  182. package/vendor/latte/latte/src/Latte/Runtime/Filters.php +234 -0
  183. package/vendor/latte/latte/src/Latte/Runtime/Html.php +35 -0
  184. package/vendor/latte/latte/src/Latte/Runtime/HtmlStringable.php +17 -0
  185. package/vendor/latte/latte/src/Latte/Runtime/Template.php +381 -0
  186. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallNode.php +30 -0
  187. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallableNode.php +29 -0
  188. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallNode.php +32 -0
  189. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallableNode.php +30 -0
  190. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/PropertyFetchNode.php +32 -0
  191. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/SandboxNode.php +73 -0
  192. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticCallNode.php +31 -0
  193. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticCallableNode.php +30 -0
  194. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticPropertyFetchNode.php +32 -0
  195. package/vendor/latte/latte/src/Latte/Sandbox/RuntimeChecker.php +116 -0
  196. package/vendor/latte/latte/src/Latte/Sandbox/SandboxExtension.php +132 -0
  197. package/vendor/latte/latte/src/Latte/Sandbox/SecurityPolicy.php +185 -0
  198. package/vendor/latte/latte/src/Latte/Strict.php +101 -0
  199. package/vendor/latte/latte/src/Latte/attributes.php +24 -0
  200. package/vendor/latte/latte/src/Latte/exceptions.php +69 -0
  201. package/vendor/latte/latte/src/Tools/Linter.php +175 -0
@@ -0,0 +1,206 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Latte (https://latte.nette.org)
5
+ * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Latte\Compiler;
11
+
12
+ use Latte;
13
+ use Latte\ContentType;
14
+
15
+
16
+ /**
17
+ * Template code generator.
18
+ */
19
+ final class TemplateGenerator
20
+ {
21
+ use Latte\Strict;
22
+
23
+ /** @var array<string, ?array{body: string, arguments: string, returns: string, comment: ?string}> */
24
+ private array $methods = [];
25
+
26
+ /** @var array<string, mixed> */
27
+ private array $properties = [];
28
+
29
+ /** @var array<string, mixed> */
30
+ private array $constants = [];
31
+
32
+
33
+ /**
34
+ * Compiles nodes to PHP file
35
+ */
36
+ public function generate(
37
+ Nodes\TemplateNode $node,
38
+ string $className,
39
+ ?string $comment = null,
40
+ bool $strictMode = false,
41
+ ): string {
42
+ $context = new PrintContext($node->contentType);
43
+ $code = $node->main->print($context);
44
+ $code = self::buildParams($code, [], '$ʟ_args', $context);
45
+ $this->addMethod('main', $code, 'array $ʟ_args');
46
+
47
+ $head = (new NodeTraverser)->traverse($node->head, fn(Node $node) => $node instanceof Nodes\TextNode ? new Nodes\NopNode : $node);
48
+ $code = $head->print($context);
49
+ if ($code || $context->paramsExtraction) {
50
+ $code .= 'return get_defined_vars();';
51
+ $code = self::buildParams($code, $context->paramsExtraction, '$this->params', $context);
52
+ $this->addMethod('prepare', $code, '', 'array');
53
+ }
54
+
55
+ if ($node->contentType !== ContentType::Html) {
56
+ $this->addConstant('ContentType', $node->contentType);
57
+ }
58
+
59
+ $this->generateBlocks($context->blocks, $context);
60
+
61
+ $members = [];
62
+ foreach ($this->constants as $name => $value) {
63
+ $members[] = "\tpublic const $name = " . PhpHelpers::dump($value, true) . ';';
64
+ }
65
+
66
+ foreach ($this->properties as $name => $value) {
67
+ $members[] = "\tpublic $$name = " . PhpHelpers::dump($value, true) . ';';
68
+ }
69
+
70
+ foreach (array_filter($this->methods) as $name => $method) {
71
+ $members[] = ($method['comment'] === null ? '' : "\n\t/** " . str_replace('*/', '* /', $method['comment']) . ' */')
72
+ . "\n\tpublic function $name($method[arguments])"
73
+ . ($method['returns'] ? ': ' . $method['returns'] : '')
74
+ . "\n\t{\n"
75
+ . ($method['body'] ? "\t\t$method[body]\n" : '') . "\t}";
76
+ }
77
+
78
+ $code = "<?php\n\n"
79
+ . ($strictMode ? "declare(strict_types=1);\n\n" : '')
80
+ . "use Latte\\Runtime as LR;\n\n"
81
+ . ($comment === null ? '' : '/** ' . str_replace('*/', '* /', $comment) . " */\n")
82
+ . "final class $className extends Latte\\Runtime\\Template\n{\n"
83
+ . implode("\n\n", $members)
84
+ . "\n}\n";
85
+
86
+ $code = PhpHelpers::optimizeEcho($code);
87
+ $code = PhpHelpers::reformatCode($code);
88
+ return $code;
89
+ }
90
+
91
+
92
+ /** @param Block[] $blocks */
93
+ private function generateBlocks(array $blocks, PrintContext $context): void
94
+ {
95
+ $contentType = $context->getEscaper()->getContentType();
96
+ foreach ($blocks as $block) {
97
+ if (!$block->isDynamic()) {
98
+ $meta[$block->layer][$block->name->value] = $contentType === $block->escaping
99
+ ? $block->method
100
+ : [$block->method, $block->escaping];
101
+ }
102
+
103
+ $body = $this->buildParams($block->content, $block->parameters, '$ʟ_args', $context);
104
+ if (!$block->isDynamic() && str_contains($body, '$')) {
105
+ $embedded = $block->tag->name === 'block' && is_int($block->layer) && $block->layer;
106
+ $body = 'extract(' . ($embedded ? 'end($this->varStack)' : '$this->params') . ');' . $body;
107
+ }
108
+
109
+ $this->addMethod(
110
+ $block->method,
111
+ $body,
112
+ 'array $ʟ_args',
113
+ 'void',
114
+ $block->tag->getNotation(true) . ' on line ' . $block->tag->position->line,
115
+ );
116
+ }
117
+
118
+ if (isset($meta)) {
119
+ $this->addConstant('Blocks', $meta);
120
+ }
121
+ }
122
+
123
+
124
+ private function buildParams(string $body, array $params, string $cont, PrintContext $context): string
125
+ {
126
+ if (!str_contains($body, '$') && !str_contains($body, 'get_defined_vars()')) {
127
+ return $body;
128
+ }
129
+
130
+ $res = [];
131
+ foreach ($params as $i => $param) {
132
+ $res[] = $context->format(
133
+ '%node = %raw[%dump] ?? %raw[%dump] ?? %node;',
134
+ $param->var,
135
+ $cont,
136
+ $i,
137
+ $cont,
138
+ $param->var->name,
139
+ $param->default,
140
+ );
141
+ }
142
+
143
+ $extract = $params
144
+ ? implode('', $res) . 'unset($ʟ_args);'
145
+ : "extract($cont);" . (str_contains($cont, '$this') ? '' : "unset($cont);");
146
+ return $extract . "\n\n" . $body;
147
+ }
148
+
149
+
150
+ /**
151
+ * Adds custom method to template.
152
+ * @internal
153
+ */
154
+ public function addMethod(
155
+ string $name,
156
+ string $body,
157
+ string $arguments = '',
158
+ string $returns = 'void',
159
+ ?string $comment = null,
160
+ ): void {
161
+ $body = trim($body);
162
+ $this->methods[$name] = compact('body', 'arguments', 'returns', 'comment');
163
+ }
164
+
165
+
166
+ /**
167
+ * Returns custom methods.
168
+ * @return array<string, ?array{body: string, arguments: string, returns: string, comment: ?string}>
169
+ * @internal
170
+ */
171
+ public function getMethods(): array
172
+ {
173
+ return $this->methods;
174
+ }
175
+
176
+
177
+ /**
178
+ * Adds custom property to template.
179
+ * @internal
180
+ */
181
+ public function addProperty(string $name, mixed $value): void
182
+ {
183
+ $this->properties[$name] = $value;
184
+ }
185
+
186
+
187
+ /**
188
+ * Returns custom properites.
189
+ * @return array<string, mixed>
190
+ * @internal
191
+ */
192
+ public function getProperties(): array
193
+ {
194
+ return $this->properties;
195
+ }
196
+
197
+
198
+ /**
199
+ * Adds custom constant to template.
200
+ * @internal
201
+ */
202
+ public function addConstant(string $name, mixed $value): void
203
+ {
204
+ $this->constants[$name] = $value;
205
+ }
206
+ }
@@ -0,0 +1,391 @@
1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the Latte (https://latte.nette.org)
5
+ * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace Latte\Compiler;
11
+
12
+ use Latte;
13
+ use Latte\CompileException;
14
+ use Latte\ContentType;
15
+ use Latte\RegexpException;
16
+
17
+
18
+ final class TemplateLexer
19
+ {
20
+ use Latte\Strict;
21
+
22
+ /** HTML tag name for Latte needs (actually is [a-zA-Z][^\s/>]*) */
23
+ public const ReTagName = '[a-zA-Z][a-zA-Z0-9:_.-]*';
24
+
25
+ /** special HTML attribute prefix */
26
+ public const NPrefix = 'n:';
27
+
28
+ /** HTML attribute name/value (\p{C} means \x00-\x1F except space) */
29
+ private const ReHtmlName = '[^\p{C} "\'<>=`/{}]+';
30
+ private const ReHtmlValue = '[^\p{C} "\'<>=`{}]+';
31
+ private const StateEnd = 'end';
32
+
33
+ public string $openDelimiter;
34
+ public string $closeDelimiter;
35
+ private TagLexer $tagLexer;
36
+
37
+ /** @var array<array{name: string, args: mixed[]}> */
38
+ private array $states;
39
+ private string $input;
40
+ private Position $position;
41
+ private bool $xmlMode;
42
+
43
+
44
+ /** @return \Generator<Token> */
45
+ public function tokenize(string $template, string $contentType = ContentType::Html): \Generator
46
+ {
47
+ $this->position = new Position(1, 1, 0);
48
+ $this->input = $this->normalize($template);
49
+ $this->states = [];
50
+ $this->setContentType($contentType);
51
+ $this->setSyntax(null);
52
+ $this->tagLexer = new TagLexer;
53
+
54
+ do {
55
+ $state = $this->states[0];
56
+ yield from $this->{$state['name']}(...$state['args']);
57
+ } while ($this->states[0]['name'] !== self::StateEnd);
58
+
59
+ if ($this->position->offset < strlen($this->input)) {
60
+ throw new CompileException("Unexpected '" . substr($this->input, $this->position->offset, 10) . "'", $this->position);
61
+ }
62
+
63
+ yield new Token(Token::End, '', $this->position);
64
+ }
65
+
66
+
67
+ private function statePlain(): \Generator
68
+ {
69
+ $m = yield from $this->match('~
70
+ (?<Text>.+?)??
71
+ (?<Indentation>(?<=\n|^)[ \t]+)?
72
+ (
73
+ (?<Latte_TagOpen>' . $this->openDelimiter . '(?!\*))| # {tag
74
+ (?<Latte_CommentOpen>' . $this->openDelimiter . '\*)| # {* comment
75
+ $
76
+ )
77
+ ~xsiAuD');
78
+
79
+ if (isset($m['Latte_TagOpen'])) {
80
+ $this->pushState('stateLatteTag');
81
+ } elseif (isset($m['Latte_CommentOpen'])) {
82
+ $this->pushState('stateLatteComment');
83
+ } else {
84
+ $this->setState(self::StateEnd);
85
+ }
86
+ }
87
+
88
+
89
+ private function stateLatteTag(): \Generator
90
+ {
91
+ $this->popState();
92
+ yield from $this->match('~
93
+ (?<Slash>/)?
94
+ (?<Latte_Name> = | _(?!_) | [a-z]\w*+(?:[.:-]\w+)*+(?!::|\(|\\\\))? # name, /name, but not function( or class:: or namespace\
95
+ ~xsiAu');
96
+
97
+ yield from $this->tagLexer->tokenizePartially($this->input, $this->position);
98
+
99
+ yield from $this->match('~
100
+ (?<Slash>/)?
101
+ (?<Latte_TagClose>' . $this->closeDelimiter . ')
102
+ (?<Newline>[ \t]*\R)?
103
+ ~xsiAu');
104
+ }
105
+
106
+
107
+ private function stateLatteComment(): \Generator
108
+ {
109
+ $this->popState();
110
+ yield from $this->match('~
111
+ (?<Text>.+?)??
112
+ (?<Latte_CommentClose>\*' . $this->closeDelimiter . ')
113
+ (?<Newline>[ \t]*\R{1,2})?
114
+ ~xsiAu');
115
+ }
116
+
117
+
118
+ private function stateHtmlText(): \Generator
119
+ {
120
+ $m = yield from $this->match('~(?J)
121
+ (?<Text>.+?)??
122
+ (
123
+ (?<Indentation>(?<=\n|^)[ \t]+)?(?<Html_TagOpen><)(?<Slash>/)?(?<Html_Name>' . self::ReTagName . ')| # <tag </tag
124
+ (?<Html_CommentOpen><!--(?!>|->))| # <!-- comment
125
+ (?<Html_BogusOpen><[/?!])| # <!doctype <?xml or error
126
+ (?<Indentation>(?<=\n|^)[ \t]+)?(?<Latte_TagOpen>' . $this->openDelimiter . '(?!\*))| # {tag
127
+ (?<Indentation>(?<=\n|^)[ \t]+)?(?<Latte_CommentOpen>' . $this->openDelimiter . '\*)| # {* comment
128
+ $
129
+ )
130
+ ~xsiAuD');
131
+
132
+ if (isset($m['Html_TagOpen'])) {
133
+ $tagName = isset($m['Slash']) ? null : strtolower($m['Html_Name']);
134
+ $this->setState('stateHtmlTag', $tagName);
135
+ } elseif (isset($m['Html_CommentOpen'])) {
136
+ $this->setState('stateHtmlComment');
137
+ } elseif (isset($m['Html_BogusOpen'])) {
138
+ $this->setState('stateHtmlBogus');
139
+ } elseif (isset($m['Latte_TagOpen'])) {
140
+ $this->pushState('stateLatteTag');
141
+ } elseif (isset($m['Latte_CommentOpen'])) {
142
+ $this->pushState('stateLatteComment');
143
+ } else {
144
+ $this->setState(self::StateEnd);
145
+ }
146
+ }
147
+
148
+
149
+ private function stateHtmlTag(?string $tagName = null, ?string $attrName = null): \Generator
150
+ {
151
+ $m = yield from $this->match('~
152
+ (?<Whitespace>\s+)| # whitespace
153
+ (?<Equals>=)|
154
+ (?<Quote>["\'])|
155
+ (?<Slash>/)?(?<Html_TagClose>>)(?<Newline>[ \t]*\R)?| # > />
156
+ (?<Html_Name>' . self::ReHtmlName . ')| # HTML attribute name/value
157
+ (?<Latte_TagOpen>' . $this->openDelimiter . '(?!\*))| # {tag
158
+ (?<Latte_CommentOpen>' . $this->openDelimiter . '\*) # {* comment
159
+ ~xsiAu');
160
+
161
+ if (isset($m['Html_Name'])) {
162
+ $this->states[0]['args'][1] = $m['Html_Name'];
163
+ } elseif (isset($m['Equals'])) {
164
+ yield from $this->match('~
165
+ (?<Whitespace>\s+)? # whitespace
166
+ (?<Html_Name>' . self::ReHtmlValue . ') # HTML attribute name/value
167
+ ~xsiAu');
168
+ } elseif (isset($m['Whitespace'])) {
169
+ } elseif (isset($m['Quote'])) {
170
+ $this->pushState(str_starts_with($attrName, self::NPrefix)
171
+ ? 'stateHtmlQuotedNAttrValue'
172
+ : 'stateHtmlQuotedValue', $m['Quote']);
173
+ } elseif (
174
+ isset($m['Html_TagClose'])
175
+ && !$this->xmlMode
176
+ && !isset($m['Slash'])
177
+ && in_array($tagName, ['script', 'style'], true)
178
+ ) {
179
+ $this->setState('stateHtmlRCData', $tagName);
180
+ } elseif (isset($m['Html_TagClose'])) {
181
+ $this->setState('stateHtmlText');
182
+ } elseif (isset($m['Latte_TagOpen'])) {
183
+ $this->pushState('stateLatteTag');
184
+ } elseif (isset($m['Latte_CommentOpen'])) {
185
+ $this->pushState('stateLatteComment');
186
+ } else {
187
+ $this->setState(self::StateEnd);
188
+ }
189
+ }
190
+
191
+
192
+ private function stateHtmlQuotedValue(string $quote): \Generator
193
+ {
194
+ $m = yield from $this->match('~
195
+ (?<Text>.+?)??(
196
+ (?<Quote>' . $quote . ')|
197
+ (?<Latte_TagOpen>' . $this->openDelimiter . '(?!\*))| # {tag
198
+ (?<Latte_CommentOpen>' . $this->openDelimiter . '\*) # {* comment
199
+ )
200
+ ~xsiAu');
201
+
202
+ if (isset($m['Quote'])) {
203
+ $this->popState();
204
+ } elseif (isset($m['Latte_TagOpen'])) {
205
+ $this->pushState('stateLatteTag');
206
+ } elseif (isset($m['Latte_CommentOpen'])) {
207
+ $this->pushState('stateLatteComment');
208
+ } else {
209
+ $this->setState(self::StateEnd);
210
+ }
211
+ }
212
+
213
+
214
+ private function stateHtmlQuotedNAttrValue(string $quote): \Generator
215
+ {
216
+ $m = yield from $this->match('~
217
+ (?<Text>.+?)??(?<Quote>' . $quote . ')|
218
+ ~xsiAu');
219
+
220
+ if (isset($m['Quote'])) {
221
+ $this->popState();
222
+ } else {
223
+ $this->setState(self::StateEnd);
224
+ }
225
+ }
226
+
227
+
228
+ private function stateHtmlRCData(string $tagName): \Generator
229
+ {
230
+ $m = yield from $this->match('~
231
+ (?<Text>.+?)??
232
+ (?<Indentation>(?<=\n|^)[ \t]+)?
233
+ (
234
+ (?<Html_TagOpen><)(?<Slash>/)(?<Html_Name>' . preg_quote($tagName, '~') . ')| # </tag
235
+ (?<Latte_TagOpen>' . $this->openDelimiter . '(?!\*))| # {tag
236
+ (?<Latte_CommentOpen>' . $this->openDelimiter . '\*)| # {* comment
237
+ $
238
+ )
239
+ ~xsiAu');
240
+
241
+ if (isset($m['Html_TagOpen'])) {
242
+ $this->setState('stateHtmlTag');
243
+ } elseif (isset($m['Latte_TagOpen'])) {
244
+ $this->pushState('stateLatteTag');
245
+ } elseif (isset($m['Latte_CommentOpen'])) {
246
+ $this->pushState('stateLatteComment');
247
+ } else {
248
+ $this->setState(self::StateEnd);
249
+ }
250
+ }
251
+
252
+
253
+ private function stateHtmlComment(): \Generator
254
+ {
255
+ $m = yield from $this->match('~(?J)
256
+ (?<Text>.+?)??
257
+ (
258
+ (?<Html_CommentClose>-->)| # -->
259
+ (?<Indentation>(?<=\n|^)[ \t]+)?(?<Latte_TagOpen>' . $this->openDelimiter . '(?!\*))| # {tag
260
+ (?<Indentation>(?<=\n|^)[ \t]+)?(?<Latte_CommentOpen>' . $this->openDelimiter . '\*) # {* comment
261
+ )
262
+ ~xsiAu');
263
+
264
+ if (isset($m['Html_CommentClose'])) {
265
+ $this->setState('stateHtmlText');
266
+ } elseif (isset($m['Latte_TagOpen'])) {
267
+ $this->pushState('stateLatteTag');
268
+ } elseif (isset($m['Latte_CommentOpen'])) {
269
+ $this->pushState('stateLatteComment');
270
+ } else {
271
+ $this->setState(self::StateEnd);
272
+ }
273
+ }
274
+
275
+
276
+ private function stateHtmlBogus(): \Generator
277
+ {
278
+ $m = yield from $this->match('~
279
+ (?<Text>.+?)??(
280
+ (?<Html_TagClose>>)| # >
281
+ (?<Latte_TagOpen>' . $this->openDelimiter . '(?!\*))| # {tag
282
+ (?<Latte_CommentOpen>' . $this->openDelimiter . '\*) # {* comment
283
+ )
284
+ ~xsiAu');
285
+
286
+ if (isset($m['Html_TagClose'])) {
287
+ $this->setState('stateHtmlText');
288
+ } elseif (isset($m['Latte_TagOpen'])) {
289
+ $this->pushState('stateLatteTag');
290
+ } elseif (isset($m['Latte_CommentOpen'])) {
291
+ $this->pushState('stateLatteComment');
292
+ } else {
293
+ $this->setState(self::StateEnd);
294
+ }
295
+ }
296
+
297
+
298
+ /**
299
+ * Matches next token.
300
+ */
301
+ private function match(string $re): \Generator
302
+ {
303
+ if (!preg_match($re, $this->input, $matches, PREG_UNMATCHED_AS_NULL, $this->position->offset)) {
304
+ if (preg_last_error()) {
305
+ throw new RegexpException;
306
+ }
307
+
308
+ return [];
309
+ }
310
+
311
+ foreach ($matches as $k => $v) {
312
+ if ($v !== null && !\is_int($k)) {
313
+ yield new Token(\constant(Token::class . '::' . $k), $v, $this->position);
314
+ $this->position = $this->position->advance($v);
315
+ }
316
+ }
317
+
318
+ return $matches;
319
+ }
320
+
321
+
322
+ public function setContentType(string $type): static
323
+ {
324
+ if ($type === ContentType::Html || $type === ContentType::Xml) {
325
+ $this->setState('stateHtmlText');
326
+ $this->xmlMode = $type === ContentType::Xml;
327
+ } else {
328
+ $this->setState('statePlain');
329
+ }
330
+
331
+ return $this;
332
+ }
333
+
334
+
335
+ private function setState(string $state, ...$args): void
336
+ {
337
+ $this->states[0] = ['name' => $state, 'args' => $args];
338
+ }
339
+
340
+
341
+ private function pushState(string $state, ...$args): void
342
+ {
343
+ array_unshift($this->states, null);
344
+ $this->setState($state, ...$args);
345
+ }
346
+
347
+
348
+ private function popState(): void
349
+ {
350
+ array_shift($this->states);
351
+ }
352
+
353
+
354
+ /**
355
+ * Changes tag delimiters.
356
+ */
357
+ public function setSyntax(?string $type, ?string $endTag = null): static
358
+ {
359
+ $left = '\{(?![\s\'"{}])';
360
+ $end = $endTag ? '\{/' . preg_quote($endTag, '~') . '\}' : null;
361
+
362
+ [$this->openDelimiter, $this->closeDelimiter] = match ($type) {
363
+ null => [$left, '\}'], // {...}
364
+ 'off' => [$endTag ? '(?=' . $end . ')\{' : '(?!x)x', '\}'],
365
+ 'double' => $endTag // {{...}}
366
+ ? ['(?:\{' . $left . '|(?=' . $end . ')\{)', '\}(?:\}|(?<=' . $end . '))']
367
+ : ['\{' . $left, '\}\}'],
368
+ default => throw new \InvalidArgumentException("Unknown syntax '$type'"),
369
+ };
370
+ return $this;
371
+ }
372
+
373
+
374
+ private function normalize(string $str): string
375
+ {
376
+ if (str_starts_with($str, "\u{FEFF}")) { // BOM
377
+ $str = substr($str, 3);
378
+ }
379
+
380
+ $str = str_replace("\r\n", "\n", $str);
381
+
382
+ if (!preg_match('##u', $str)) {
383
+ preg_match('#(?:[\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})*+#A', $str, $m);
384
+ throw new CompileException('Template is not valid UTF-8 stream.', $this->position->advance($m[0]));
385
+
386
+ } elseif (preg_match('#(.*?)([\x00-\x08\x0B\x0C\x0E-\x1F\x7F])#s', $str, $m)) {
387
+ throw new CompileException('Template contains control character \x' . dechex(ord($m[2])), $this->position->advance($m[1]));
388
+ }
389
+ return $str;
390
+ }
391
+ }