@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,114 @@
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\Bridges\Tracy;
11
+
12
+ use Latte;
13
+ use Tracy;
14
+ use Tracy\BlueScreen;
15
+ use Tracy\Helpers;
16
+
17
+
18
+ /**
19
+ * BlueScreen panels for Tracy 2.x
20
+ */
21
+ class BlueScreenPanel
22
+ {
23
+ public static function initialize(?BlueScreen $blueScreen = null): void
24
+ {
25
+ $blueScreen ??= Tracy\Debugger::getBlueScreen();
26
+ $blueScreen->addPanel([self::class, 'renderError']);
27
+ $blueScreen->addAction([self::class, 'renderUnknownMacro']);
28
+ if (
29
+ version_compare(Tracy\Debugger::VERSION, '2.9.0', '>=')
30
+ && version_compare(Tracy\Debugger::VERSION, '3.0', '<')
31
+ ) {
32
+ Tracy\Debugger::addSourceMapper([self::class, 'mapLatteSourceCode']);
33
+ $blueScreen->addFileGenerator(fn(string $file) => substr($file, -6) === '.latte'
34
+ ? "{block content}\n\$END\$"
35
+ : null);
36
+ }
37
+ }
38
+
39
+
40
+ public static function renderError(?\Throwable $e): ?array
41
+ {
42
+ if ($e instanceof Latte\CompileException && $e->sourceName) {
43
+ return [
44
+ 'tab' => 'Template',
45
+ 'panel' => (preg_match('#\n|\?#', $e->sourceName)
46
+ ? ''
47
+ : '<p>'
48
+ . (@is_file($e->sourceName) // @ - may trigger error
49
+ ? '<b>File:</b> ' . Helpers::editorLink($e->sourceName, $e->position?->line)
50
+ : '<b>' . htmlspecialchars($e->sourceName . ($e->position?->line ? ':' . $e->position->line : '')) . '</b>')
51
+ . '</p>')
52
+ . '<pre class="code tracy-code"><div>'
53
+ . BlueScreen::highlightLine(htmlspecialchars($e->sourceCode, ENT_IGNORE, 'UTF-8'), $e->position->line ?? 0, 15, $e->position->column ?? 0)
54
+ . '</div></pre>',
55
+ ];
56
+
57
+ } elseif (
58
+ $e
59
+ && ($file = $e->getFile())
60
+ && (version_compare(Tracy\Debugger::VERSION, '2.9.0', '<'))
61
+ && ($mapped = self::mapLatteSourceCode($file, $e->getLine()))
62
+ ) {
63
+ return [
64
+ 'tab' => 'Template',
65
+ 'panel' => '<p><b>File:</b> ' . Helpers::editorLink($mapped['file'], $mapped['line']) . '</p>'
66
+ . ($mapped['line']
67
+ ? BlueScreen::highlightFile($mapped['file'], $mapped['line'])
68
+ : ''),
69
+ ];
70
+ }
71
+
72
+ return null;
73
+ }
74
+
75
+
76
+ public static function renderUnknownMacro(?\Throwable $e): ?array
77
+ {
78
+ if (
79
+ $e instanceof Latte\CompileException
80
+ && $e->sourceName
81
+ && @is_file($e->sourceName) // @ - may trigger error
82
+ && (preg_match('#Unknown tag (\{\w+)\}, did you mean (\{\w+)\}\?#A', $e->getMessage(), $m)
83
+ || preg_match('#Unknown attribute (n:\w+), did you mean (n:\w+)\?#A', $e->getMessage(), $m))
84
+ ) {
85
+ return [
86
+ 'link' => Helpers::editorUri($e->sourceName, $e->position?->line, 'fix', $m[1], $m[2]),
87
+ 'label' => 'fix it',
88
+ ];
89
+ }
90
+
91
+ return null;
92
+ }
93
+
94
+
95
+ /** @return array{file: string, line: int, label: string, active: bool} */
96
+ public static function mapLatteSourceCode(string $file, int $line): ?array
97
+ {
98
+ if (!strpos($file, '.latte--')) {
99
+ return null;
100
+ }
101
+
102
+ $lines = file($file);
103
+ if (
104
+ !preg_match('#^/\*\* source: (\S+\.latte)#m', implode('', array_slice($lines, 0, 10)), $m)
105
+ || !@is_file($m[1]) // @ - may trigger error
106
+ ) {
107
+ return null;
108
+ }
109
+
110
+ $file = $m[1];
111
+ $line = $line && preg_match('#/\* line (\d+) \*/#', $lines[$line - 1], $m) ? (int) $m[1] : 0;
112
+ return ['file' => $file, 'line' => $line, 'label' => 'Latte', 'active' => true];
113
+ }
114
+ }
@@ -0,0 +1,99 @@
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\Bridges\Tracy;
11
+
12
+ use Latte\Engine;
13
+ use Latte\Runtime\Template;
14
+ use Tracy;
15
+
16
+
17
+ /**
18
+ * Bar panel for Tracy 2.x
19
+ */
20
+ class LattePanel implements Tracy\IBarPanel
21
+ {
22
+ public bool $dumpParameters = true;
23
+
24
+ /** @var Template[] */
25
+ private array $templates = [];
26
+ private array $list;
27
+ private ?string $name = null;
28
+
29
+
30
+ public static function initialize(Engine $latte, ?string $name = null, ?Tracy\Bar $bar = null): void
31
+ {
32
+ $bar ??= Tracy\Debugger::getBar();
33
+ $bar->addPanel(new self($latte, $name));
34
+ }
35
+
36
+
37
+ public function __construct(Engine $latte, ?string $name = null)
38
+ {
39
+ $this->name = $name;
40
+ $latte->probe = function (Template $template): void {
41
+ $this->templates[] = $template;
42
+ };
43
+ }
44
+
45
+
46
+ /**
47
+ * Renders tab.
48
+ */
49
+ public function getTab(): ?string
50
+ {
51
+ if (!$this->templates) {
52
+ return null;
53
+ }
54
+
55
+ return Tracy\Helpers::capture(function () {
56
+ $name = $this->name ?? basename(reset($this->templates)->getName());
57
+ require __DIR__ . '/templates/LattePanel.tab.phtml';
58
+ });
59
+ }
60
+
61
+
62
+ /**
63
+ * Renders panel.
64
+ */
65
+ public function getPanel(): string
66
+ {
67
+ $this->list = [];
68
+ $this->buildList($this->templates[0]);
69
+
70
+ return Tracy\Helpers::capture(function () {
71
+ $list = $this->list;
72
+ $dumpParameters = $this->dumpParameters;
73
+ require __DIR__ . '/templates/LattePanel.panel.phtml';
74
+ });
75
+ }
76
+
77
+
78
+ private function buildList(Template $template, int $depth = 0, int $count = 1): void
79
+ {
80
+ $this->list[] = (object) [
81
+ 'template' => $template,
82
+ 'depth' => $depth,
83
+ 'count' => $count,
84
+ 'phpFile' => (new \ReflectionObject($template))->getFileName(),
85
+ ];
86
+
87
+ $children = $counter = [];
88
+ foreach ($this->templates as $t) {
89
+ if ($t->getReferringTemplate() === $template) {
90
+ $children[$t->getName()] = $t;
91
+ @$counter[$t->getName()]++;
92
+ }
93
+ }
94
+
95
+ foreach ($children as $name => $t) {
96
+ $this->buildList($t, $depth + 1, $counter[$name]);
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,98 @@
1
+ <?php
2
+ declare(strict_types=1);
3
+
4
+ namespace Latte\Bridges\Tracy;
5
+
6
+ use Latte\Runtime\Template;
7
+ use Tracy\Dumper;
8
+ use Tracy\Helpers;
9
+
10
+ $colors = [
11
+ 'include' => '#00000052',
12
+ 'extends' => '#cd1c1c7d',
13
+ 'import' => '#17c35b8f',
14
+ 'includeblock' => '#17c35b8f',
15
+ 'embed' => '#4f1ccd7d',
16
+ 'sandbox' => 'black',
17
+ ];
18
+
19
+ ?>
20
+
21
+ <style class="tracy-debug">
22
+ #tracy-debug .LattePanel td {
23
+ white-space: nowrap;
24
+ }
25
+
26
+ #tracy-debug .LattePanel-php {
27
+ background: #8993be;
28
+ color: white;
29
+ border-radius: 79px;
30
+ padding: 1px 4px 3px 4px;
31
+ font-size: 75%;
32
+ font-style: italic;
33
+ font-weight: bold;
34
+ vertical-align: text-top;
35
+ opacity: .5;
36
+ margin-left: 2ex;
37
+ }
38
+
39
+ #tracy-debug .LattePanel-type {
40
+ border-radius: 2px;
41
+ padding: 2px 4px;
42
+ font-size: 80%;
43
+ color: white;
44
+ font-weight: bold;
45
+ }
46
+
47
+ #tracy-debug .LattePanel-include {
48
+ background: #00000052;
49
+ }
50
+
51
+ #tracy-debug .LattePanel-extends {
52
+ background: #cd1c1c7d;
53
+ }
54
+
55
+ #tracy-debug .LattePanel-import,
56
+ #tracy-debug .LattePanel-includeblock {
57
+ background: #17c35b8f;
58
+ }
59
+
60
+ #tracy-debug .LattePanel-embed {
61
+ background: #4f1ccd7d;
62
+ }
63
+
64
+ #tracy-debug .LattePanel-sandbox {
65
+ background: black;
66
+ }
67
+ </style>
68
+
69
+ <h1>Rendered Templates</h1>
70
+
71
+ <div class="tracy-inner LattePanel">
72
+ <table>
73
+ <?php foreach ($list as $item): ?>
74
+ <tr>
75
+ <td>
76
+ <?php if ($item->template->getReferenceType()): ?>
77
+ <span style="margin-left: <?= $item->depth * 4 ?>ex"></span>└ 
78
+ <span class="LattePanel-type" style="background: <?= $colors[$item->template->getReferenceType()] ?>"><?= Helpers::escapeHtml($item->template->getReferenceType()) ?></span>
79
+ <?php endif ?>
80
+
81
+ <?= Helpers::editorLink($item->template->getName()) ?>
82
+
83
+ <a href="<?= Helpers::escapeHtml(Helpers::editorUri($item->phpFile)) ?>" class="LattePanel-php">php</a>
84
+ </td>
85
+
86
+ <td><?= $item->count > 1 ? $item->count . '×' : '' ?></td>
87
+ </tr>
88
+ <?php endforeach ?>
89
+ </table>
90
+
91
+ <?php if ($dumpParameters): ?>
92
+ <h2>Parameters</h2>
93
+
94
+ <div class="tracy-inner">
95
+ <?= Dumper::toHtml(reset($list)->template->getParameters(), [Dumper::LIVE => true]); ?>
96
+ </div>
97
+ <?php endif ?>
98
+ </div>
@@ -0,0 +1,15 @@
1
+ <?php
2
+ declare(strict_types=1);
3
+
4
+ namespace Latte\Bridges\Tracy;
5
+
6
+ use Tracy\Helpers;
7
+
8
+ ?>
9
+ <span title="Latte Templates">
10
+ <svg viewBox="0 0 1793.77 1538.57">
11
+ <path fill="#F1A443" d="M934.87 1166.46c41.84,-2.2 75.14,-17.07 99.91,-44.59 24.77,-27.53 37.16,-58.9 37.16,-94.13 0,-38.53 -12.38,-71.01 -37.16,-97.43 -24.77,-26.42 -58.08,-45.14 -99.91,-56.15l0 292.31zm-67.71 -786.08c-40.74,2.2 -72.66,15.41 -95.79,39.63 -23.12,24.22 -34.68,52.29 -34.68,84.22 0,33.03 11.29,63.03 33.86,90 22.57,26.98 54.77,43.21 96.61,48.72l0 -262.58zm0 1013.98l0 -64.41c-61.66,-5.5 -114.22,-15.97 -157.71,-31.38 -43.49,-15.41 -79.27,-37.43 -107.34,-66.06 -28.07,-28.63 -48.72,-64.13 -61.93,-106.52 -13.21,-42.39 -19.82,-92.76 -19.82,-151.11l198.18 0c4.4,35.23 10.18,64.41 17.34,87.53 7.16,23.12 16.51,41.84 28.07,56.15 11.56,14.31 25.6,25.05 42.11,32.2 16.51,7.16 36.88,12.39 61.1,15.69l0 -318.73c-55.05,-14.31 -102.94,-30.55 -143.67,-48.72 -40.74,-18.16 -74.59,-39.63 -101.57,-64.41 -26.97,-24.77 -47.34,-53.4 -61.1,-85.88 -13.76,-32.48 -20.64,-71.29 -20.64,-116.43 0,-42.93 8.26,-83.39 24.77,-121.38 16.51,-37.98 39.36,-71.29 68.53,-99.91 29.18,-28.63 63.58,-51.19 103.22,-67.71 39.63,-16.51 83.12,-25.32 130.46,-26.42l0 -72.67 67.71 0 0 72.67c203.68,6.6 310.47,113.4 320.38,320.38l-194.87 0c-5.5,-59.45 -18.44,-99.91 -38.81,-121.38 -20.37,-21.47 -49.27,-33.31 -86.7,-35.51l0 284.05c73.76,24.22 132.94,47.89 177.53,71.01 44.59,23.12 78.72,47.61 102.39,73.49 23.67,25.87 39.36,54.22 47.07,85.05 7.71,30.83 11.56,66.61 11.56,107.34 0,48.44 -7.98,92.2 -23.94,131.29 -15.97,39.08 -38.81,72.94 -68.54,101.56 -29.72,28.63 -65.5,51.2 -107.34,67.71 -41.84,16.51 -88.08,25.87 -138.72,28.07l0 64.41 -67.71 0z"/>
12
+ <path fill="#5F4D36" d="M462.33 1411.31c-54.32,0 -98.33,-4.78 -132.03,-14.33 -33.7,-9.56 -59.85,-24.14 -78.46,-43.76 -18.61,-19.62 -30.93,-44.51 -36.97,-74.69 -6.04,-30.18 -9.05,-65.38 -9.05,-105.62 0,-9.05 0.5,-22.13 1.51,-39.23 1.01,-17.1 1.76,-35.21 2.27,-54.32 0.5,-19.11 1.26,-36.97 2.26,-53.56 1.01,-16.6 1.51,-28.42 1.51,-35.46 0,-58.34 -8.8,-99.08 -26.41,-122.22 -17.6,-23.13 -50.05,-34.7 -97.33,-34.7l0 -129.76c47.28,0 79.72,-11.82 97.33,-35.46 17.6,-23.64 26.41,-64.63 26.41,-122.97 0,-7.04 -0.5,-18.86 -1.51,-35.46 -1.01,-16.6 -1.76,-33.95 -2.26,-52.06 -0.5,-18.11 -1.26,-35.71 -2.27,-52.81 -1.01,-17.1 -1.51,-30.18 -1.51,-39.23 0,-40.24 3.02,-75.45 9.05,-105.62 6.03,-30.18 18.36,-55.08 36.97,-74.69 18.61,-19.62 44.76,-34.2 78.46,-43.76 33.7,-9.56 77.71,-14.34 132.03,-14.34l55.83 0 0 123.73 -33.2 0c-44.26,0 -74.18,7.04 -89.78,21.12 -15.59,14.08 -23.39,38.73 -23.39,73.94 0,45.27 1.51,90.03 4.53,134.29 3.02,44.26 4.53,89.02 4.53,134.29 0,21.12 -4.53,40.49 -13.58,58.09 -9.05,17.6 -20.87,33.19 -35.46,46.77 -14.59,13.58 -31.69,24.4 -51.3,32.44 -19.62,8.05 -39.98,13.58 -61.11,16.6 21.12,3.02 41.49,8.55 61.11,16.59 19.61,8.05 36.72,18.86 51.3,32.44 14.59,13.58 26.41,29.17 35.46,46.77 9.05,17.6 13.58,36.97 13.58,58.09 0,45.27 -1.51,90.28 -4.53,135.04 -3.02,44.76 -4.53,89.78 -4.53,135.05 0,35.21 7.79,59.85 23.39,73.94 15.59,14.08 45.52,21.12 89.78,21.12l33.2 0 0 123.73 -55.83 0z"/>
13
+ <path fill="#5F4D36" d="M1275.61 1411.31l0 -123.73 33.2 0c44.26,0 74.19,-7.04 89.78,-21.12 15.59,-14.08 23.39,-38.73 23.39,-73.94 0,-45.27 -1.51,-90.28 -4.53,-135.05 -3.02,-44.76 -4.53,-89.78 -4.53,-135.04 0,-21.12 4.53,-40.49 13.58,-58.09 9.05,-17.6 20.87,-33.19 35.46,-46.77 14.59,-13.58 31.69,-24.4 51.3,-32.44 19.61,-8.05 39.98,-13.58 61.11,-16.59 -21.12,-3.02 -41.5,-8.55 -61.11,-16.6 -19.62,-8.05 -36.72,-18.86 -51.3,-32.44 -14.59,-13.58 -26.41,-29.17 -35.46,-46.77 -9.05,-17.6 -13.58,-36.97 -13.58,-58.09 0,-45.27 1.51,-90.03 4.53,-134.29 3.02,-44.26 4.53,-89.02 4.53,-134.29 0,-35.21 -7.8,-59.85 -23.39,-73.94 -15.59,-14.08 -45.52,-21.12 -89.78,-21.12l-33.2 0 0 -123.73 55.83 0c54.32,0 98.33,4.78 132.03,14.34 33.7,9.55 59.85,24.14 78.46,43.76 18.61,19.61 30.93,44.51 36.97,74.69 6.03,30.17 9.05,65.38 9.05,105.62 0,9.05 -0.5,22.13 -1.51,39.23 -1.01,17.1 -1.76,34.7 -2.26,52.81 -0.5,18.11 -1.26,35.46 -2.27,52.06 -1.01,16.59 -1.51,28.41 -1.51,35.46 0,58.34 8.8,99.33 26.41,122.97 17.6,23.64 50.04,35.46 97.32,35.46l0 129.76c-47.28,0 -79.72,11.57 -97.32,34.7 -17.6,23.14 -26.41,63.88 -26.41,122.22 0,7.04 0.5,18.86 1.51,35.46 1.01,16.6 1.76,34.45 2.27,53.56 0.5,19.11 1.26,37.22 2.26,54.32 1.01,17.1 1.51,30.18 1.51,39.23 0,40.24 -3.02,75.44 -9.05,105.62 -6.04,30.18 -18.36,55.07 -36.97,74.69 -18.61,19.61 -44.76,34.2 -78.46,43.76 -33.7,9.55 -77.7,14.33 -132.03,14.33l-55.83 0z"/>
14
+ </svg><span class="tracy-label"><?= Helpers::escapeHtml($name) ?></span>
15
+ </span>
@@ -0,0 +1,44 @@
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\Compiler\Nodes\Php\ExpressionNode;
14
+ use Latte\Compiler\Nodes\Php\ParameterNode;
15
+ use Latte\Compiler\Nodes\Php\Scalar;
16
+
17
+
18
+ /** @internal */
19
+ final class Block
20
+ {
21
+ use Latte\Strict;
22
+
23
+ public string $method;
24
+ public string $content;
25
+ public string $escaping;
26
+
27
+ /** @var ParameterNode[] */
28
+ public array $parameters = [];
29
+
30
+
31
+ public function __construct(
32
+ public /*readonly*/ ExpressionNode $name,
33
+ public /*readonly*/ int|string $layer,
34
+ public /*readonly*/ Tag $tag,
35
+ ) {
36
+ }
37
+
38
+
39
+ public function isDynamic(): bool
40
+ {
41
+ return !$this->name instanceof Scalar\StringNode
42
+ && !$this->name instanceof Scalar\IntegerNode;
43
+ }
44
+ }
@@ -0,0 +1,244 @@
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\Compiler\Nodes\Html\ElementNode;
14
+ use Latte\ContentType;
15
+ use Latte\Runtime\Filters;
16
+
17
+
18
+ /**
19
+ * Context-aware escaping.
20
+ */
21
+ final class Escaper
22
+ {
23
+ use Latte\Strict;
24
+
25
+ public const
26
+ Text = 'text',
27
+ JavaScript = 'js',
28
+ Css = 'css',
29
+ ICal = 'ical',
30
+ Url = 'url';
31
+
32
+ public const
33
+ HtmlText = 'html',
34
+ HtmlComment = 'html/comment',
35
+ HtmlBogusTag = 'html/bogus',
36
+ HtmlCss = 'html/css',
37
+ HtmlJavaScript = 'html/js',
38
+ HtmlTag = 'html/tag',
39
+ HtmlAttribute = 'html/attr';
40
+
41
+ private string $state = '';
42
+ private string $tag = '';
43
+ private string $quote = '';
44
+ private string $subType = '';
45
+
46
+
47
+ public function __construct(
48
+ private string $contentType,
49
+ ) {
50
+ $this->state = $this->contentType;
51
+ }
52
+
53
+
54
+ public function getContentType(): string
55
+ {
56
+ return $this->contentType;
57
+ }
58
+
59
+
60
+ public function getState(): string
61
+ {
62
+ return $this->state;
63
+ }
64
+
65
+
66
+ public function export(): string
67
+ {
68
+ return ($this->state === self::HtmlAttribute && $this->quote === '' ? 'html/unquoted-attr' : $this->state)
69
+ . ($this->subType ? '/' . $this->subType : '');
70
+ }
71
+
72
+
73
+ public function enterContentType(string $type): void
74
+ {
75
+ $this->contentType = $this->state = $type;
76
+ }
77
+
78
+
79
+ public function enterHtmlText(?ElementNode $node): void
80
+ {
81
+ $this->state = self::HtmlText;
82
+ if ($this->contentType === ContentType::Html && $node) {
83
+ $name = strtolower($node->name);
84
+ if (
85
+ ($name === 'script' || $name === 'style')
86
+ && is_string($attr = $node->getAttribute('type') ?? 'css')
87
+ && preg_match('#(java|j|ecma|live)script|module|json|css|plain#i', $attr)
88
+ ) {
89
+ $this->state = $name === 'script'
90
+ ? self::HtmlJavaScript
91
+ : self::HtmlCss;
92
+ }
93
+ }
94
+ }
95
+
96
+
97
+ public function enterHtmlTag(string $name): void
98
+ {
99
+ $this->state = self::HtmlTag;
100
+ $this->tag = strtolower($name);
101
+ }
102
+
103
+
104
+ public function enterHtmlAttribute(?string $name = null, string $quote = ''): void
105
+ {
106
+ $this->state = self::HtmlAttribute;
107
+ $this->quote = $quote;
108
+ $this->subType = '';
109
+
110
+ if ($this->contentType === ContentType::Html && is_string($name)) {
111
+ $name = strtolower($name);
112
+ if (str_starts_with($name, 'on')) {
113
+ $this->subType = self::JavaScript;
114
+ } elseif ($name === 'style') {
115
+ $this->subType = self::Css;
116
+ } elseif ((in_array($name, ['href', 'src', 'action', 'formaction'], true)
117
+ || ($name === 'data' && $this->tag === 'object'))
118
+ ) {
119
+ $this->subType = self::Url;
120
+ }
121
+ }
122
+ }
123
+
124
+
125
+ public function enterHtmlAttributeQuote(string $quote = '"'): void
126
+ {
127
+ $this->quote = $quote;
128
+ }
129
+
130
+
131
+ public function enterHtmlBogusTag(): void
132
+ {
133
+ $this->state = self::HtmlBogusTag;
134
+ }
135
+
136
+
137
+ public function enterHtmlComment(): void
138
+ {
139
+ $this->state = self::HtmlComment;
140
+ }
141
+
142
+
143
+ public function escape(string $str): string
144
+ {
145
+ [$lq, $rq] = $this->state === self::HtmlAttribute && !$this->quote ? ["'\"' . ", " . '\"'"] : ['', ''];
146
+ return match ($this->contentType) {
147
+ ContentType::Html => match ($this->state) {
148
+ self::HtmlText => 'LR\Filters::escapeHtmlText(' . $str . ')',
149
+ self::HtmlTag => 'LR\Filters::escapeHtmlTag(' . $str . ')',
150
+ self::HtmlAttribute => match ($this->subType) {
151
+ '',
152
+ self::Url => $lq . 'LR\Filters::escapeHtmlAttr(' . $str . ')' . $rq,
153
+ self::JavaScript => $lq . 'LR\Filters::escapeHtmlAttr(LR\Filters::escapeJs(' . $str . '))' . $rq,
154
+ self::Css => $lq . 'LR\Filters::escapeHtmlAttr(LR\Filters::escapeCss(' . $str . '))' . $rq,
155
+ },
156
+ self::HtmlComment => 'LR\Filters::escapeHtmlComment(' . $str . ')',
157
+ self::HtmlBogusTag => 'LR\Filters::escapeHtml(' . $str . ')',
158
+ self::HtmlJavaScript => 'LR\Filters::escapeJs(' . $str . ')',
159
+ self::HtmlCss => 'LR\Filters::escapeCss(' . $str . ')',
160
+ default => throw new \LogicException("Unknown context $this->contentType, $this->state."),
161
+ },
162
+ ContentType::Xml => match ($this->state) {
163
+ self::HtmlText,
164
+ self::HtmlBogusTag => 'LR\Filters::escapeXml(' . $str . ')',
165
+ self::HtmlAttribute => $lq . 'LR\Filters::escapeXml(' . $str . ')' . $rq,
166
+ self::HtmlComment => 'LR\Filters::escapeHtmlComment(' . $str . ')',
167
+ self::HtmlTag => 'LR\Filters::escapeXmlAttrUnquoted(' . $str . ')',
168
+ default => throw new \LogicException("Unknown context $this->contentType, $this->state."),
169
+ },
170
+ ContentType::JavaScript => 'LR\Filters::escapeJs(' . $str . ')',
171
+ ContentType::Css => 'LR\Filters::escapeCss(' . $str . ')',
172
+ ContentType::ICal => 'LR\Filters::escapeIcal(' . $str . ')',
173
+ ContentType::Text => $str,
174
+ default => throw new \LogicException("Unknown content-type $this->contentType."),
175
+ };
176
+ }
177
+
178
+
179
+ public function check(string $str): string
180
+ {
181
+ if ($this->state === self::HtmlAttribute && $this->subType === self::Url) {
182
+ $str = 'LR\Filters::safeUrl(' . $str . ')';
183
+ }
184
+ return $str;
185
+ }
186
+
187
+
188
+ public static function getConvertor(string $source, string $dest): ?callable
189
+ {
190
+ $table = [
191
+ self::Text => [
192
+ 'html' => 'escapeHtmlText',
193
+ 'html/attr' => 'escapeHtmlAttr',
194
+ 'html/attr/js' => 'escapeHtmlAttr',
195
+ 'html/attr/css' => 'escapeHtmlAttr',
196
+ 'html/attr/url' => 'escapeHtmlAttr',
197
+ 'html/comment' => 'escapeHtmlComment',
198
+ 'xml' => 'escapeXml',
199
+ 'xml/attr' => 'escapeXml',
200
+ ],
201
+ self::JavaScript => [
202
+ 'html' => 'escapeHtmlText',
203
+ 'html/attr' => 'escapeHtmlAttr',
204
+ 'html/attr/js' => 'escapeHtmlAttr',
205
+ 'html/js' => 'escapeHtmlRawText',
206
+ 'html/comment' => 'escapeHtmlComment',
207
+ ],
208
+ self::Css => [
209
+ 'html' => 'escapeHtmlText',
210
+ 'html/attr' => 'escapeHtmlAttr',
211
+ 'html/attr/css' => 'escapeHtmlAttr',
212
+ 'html/css' => 'escapeHtmlRawText',
213
+ 'html/comment' => 'escapeHtmlComment',
214
+ ],
215
+ 'html' => [
216
+ 'html/attr' => 'convertHtmlToHtmlAttr',
217
+ 'html/attr/js' => 'convertHtmlToHtmlAttr',
218
+ 'html/attr/css' => 'convertHtmlToHtmlAttr',
219
+ 'html/attr/url' => 'convertHtmlToHtmlAttr',
220
+ 'html/comment' => 'escapeHtmlComment',
221
+ 'html/unquoted-attr' => 'convertHtmlToUnquotedAttr',
222
+ ],
223
+ 'html/attr' => [
224
+ 'html' => 'convertHtmlToHtmlAttr',
225
+ 'html/unquoted-attr' => 'convertHtmlAttrToUnquotedAttr',
226
+ ],
227
+ 'html/attr/url' => [
228
+ 'html' => 'convertHtmlToHtmlAttr',
229
+ 'html/attr' => 'nop',
230
+ ],
231
+ 'html/unquoted-attr' => [
232
+ 'html' => 'convertHtmlToHtmlAttr',
233
+ ],
234
+ ];
235
+
236
+ if ($source === $dest) {
237
+ return [Filters::class, 'nop'];
238
+ }
239
+
240
+ return isset($table[$source][$dest])
241
+ ? [Filters::class, $table[$source][$dest]]
242
+ : null;
243
+ }
244
+ }