@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.
- package/README.md +39 -0
- package/handler.js +9 -0
- package/index.js +138 -0
- package/index.php +173 -0
- package/latte/AssetFilter.php +11 -0
- package/latte/FetchFunction.php +28 -0
- package/latte/IconFilter.php +14 -0
- package/latte/JsonTag.php +64 -0
- package/latte/PlaceholderFunction.php +11 -0
- package/latte/RandomColorFunction.php +14 -0
- package/latte/TelFilter.php +22 -0
- package/package.json +35 -0
- package/vendor/autoload.php +7 -0
- package/vendor/bin/latte-lint +107 -0
- package/vendor/composer/ClassLoader.php +572 -0
- package/vendor/composer/InstalledVersions.php +350 -0
- package/vendor/composer/LICENSE +21 -0
- package/vendor/composer/autoload_classmap.php +183 -0
- package/vendor/composer/autoload_namespaces.php +9 -0
- package/vendor/composer/autoload_psr4.php +9 -0
- package/vendor/composer/autoload_real.php +57 -0
- package/vendor/composer/autoload_static.php +193 -0
- package/vendor/composer/installed.json +93 -0
- package/vendor/composer/installed.php +32 -0
- package/vendor/composer/platform_check.php +26 -0
- package/vendor/latte/latte/bin/latte-lint +29 -0
- package/vendor/latte/latte/composer.json +53 -0
- package/vendor/latte/latte/license.md +60 -0
- package/vendor/latte/latte/ncs.php +14 -0
- package/vendor/latte/latte/ncs.xml +9 -0
- package/vendor/latte/latte/readme.md +21 -0
- package/vendor/latte/latte/src/Bridges/Tracy/BlueScreenPanel.php +114 -0
- package/vendor/latte/latte/src/Bridges/Tracy/LattePanel.php +99 -0
- package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.panel.phtml +98 -0
- package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.tab.phtml +15 -0
- package/vendor/latte/latte/src/Latte/Compiler/Block.php +44 -0
- package/vendor/latte/latte/src/Latte/Compiler/Escaper.php +244 -0
- package/vendor/latte/latte/src/Latte/Compiler/ExpressionBuilder.php +128 -0
- package/vendor/latte/latte/src/Latte/Compiler/Node.php +28 -0
- package/vendor/latte/latte/src/Latte/Compiler/NodeHelpers.php +132 -0
- package/vendor/latte/latte/src/Latte/Compiler/NodeTraverser.php +77 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/AreaNode.php +17 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/AuxiliaryNode.php +27 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/FragmentNode.php +59 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/AttributeNode.php +48 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/BogusTagNode.php +46 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/CommentNode.php +39 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/ElementNode.php +129 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/QuotedValue.php +53 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/NopNode.php +21 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ArgumentNode.php +45 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ComplexTypeNode.php +17 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayAccessNode.php +41 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayItemNode.php +52 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayNode.php +94 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignNode.php +39 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignOpNode.php +45 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/BinaryOpNode.php +65 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/CastNode.php +43 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClassConstantFetchNode.php +42 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/CloneNode.php +36 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClosureNode.php +73 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClosureUseNode.php +37 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ConstantFetchNode.php +37 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/EmptyNode.php +36 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ErrorSuppressNode.php +36 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FilterCallNode.php +39 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FunctionCallNode.php +45 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/FunctionCallableNode.php +39 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/InRangeNode.php +42 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/InstanceofNode.php +40 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/IssetNode.php +40 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MatchNode.php +49 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MethodCallNode.php +50 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/MethodCallableNode.php +42 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/NewNode.php +45 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/NotNode.php +36 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PostOpNode.php +43 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PreOpNode.php +43 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PropertyFetchNode.php +42 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticCallNode.php +55 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticCallableNode.php +47 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/StaticPropertyFetchNode.php +42 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/TernaryNode.php +50 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/UnaryOpNode.php +45 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/VariableNode.php +40 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ExpressionNode.php +17 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/FilterNode.php +67 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/IdentifierNode.php +36 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/IntersectionTypeNode.php +39 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/MatchArmNode.php +45 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php +107 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NameNode.php +89 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NullableTypeNode.php +35 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ParameterNode.php +54 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/BooleanNode.php +30 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/EncapsedStringNode.php +80 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/EncapsedStringPartNode.php +30 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/FloatNode.php +63 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/IntegerNode.php +70 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/NullNode.php +29 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/StringNode.php +40 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ScalarNode.php +15 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/SuperiorTypeNode.php +29 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/UnionTypeNode.php +39 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/VarLikeIdentifierNode.php +21 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/StatementNode.php +15 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/TemplateNode.php +34 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/TextNode.php +37 -0
- package/vendor/latte/latte/src/Latte/Compiler/PhpHelpers.php +227 -0
- package/vendor/latte/latte/src/Latte/Compiler/Position.php +43 -0
- package/vendor/latte/latte/src/Latte/Compiler/PrintContext.php +334 -0
- package/vendor/latte/latte/src/Latte/Compiler/Tag.php +117 -0
- package/vendor/latte/latte/src/Latte/Compiler/TagLexer.php +399 -0
- package/vendor/latte/latte/src/Latte/Compiler/TagParser.php +388 -0
- package/vendor/latte/latte/src/Latte/Compiler/TagParserData.php +580 -0
- package/vendor/latte/latte/src/Latte/Compiler/TemplateGenerator.php +206 -0
- package/vendor/latte/latte/src/Latte/Compiler/TemplateLexer.php +391 -0
- package/vendor/latte/latte/src/Latte/Compiler/TemplateParser.php +448 -0
- package/vendor/latte/latte/src/Latte/Compiler/TemplateParserHtml.php +506 -0
- package/vendor/latte/latte/src/Latte/Compiler/Token.php +259 -0
- package/vendor/latte/latte/src/Latte/Compiler/TokenStream.php +151 -0
- package/vendor/latte/latte/src/Latte/ContentType.php +22 -0
- package/vendor/latte/latte/src/Latte/Engine.php +591 -0
- package/vendor/latte/latte/src/Latte/Essential/Blueprint.php +160 -0
- package/vendor/latte/latte/src/Latte/Essential/CachingIterator.php +232 -0
- package/vendor/latte/latte/src/Latte/Essential/CoreExtension.php +232 -0
- package/vendor/latte/latte/src/Latte/Essential/Filters.php +591 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/BlockNode.php +161 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/CaptureNode.php +98 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ContentTypeNode.php +74 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/DebugbreakNode.php +53 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/DefineNode.php +134 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/DoNode.php +49 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/DumpNode.php +58 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/EmbedNode.php +125 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ExtendsNode.php +60 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/FirstLastSepNode.php +81 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ForNode.php +91 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ForeachNode.php +155 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IfChangedNode.php +141 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IfContentNode.php +82 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IfNode.php +180 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ImportNode.php +49 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeBlockNode.php +140 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeFileNode.php +81 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IterateWhileNode.php +94 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/NAttrNode.php +105 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/NClassNode.php +54 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/NTagNode.php +79 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ParametersNode.php +84 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/PrintNode.php +70 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/RawPhpNode.php +46 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/RollbackNode.php +37 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/SkipNode.php +71 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/SpacelessNode.php +62 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/SwitchNode.php +118 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplatePrintNode.php +39 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplateTypeNode.php +38 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/TraceNode.php +35 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/TranslateNode.php +104 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/TryNode.php +75 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/VarNode.php +106 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/VarPrintNode.php +40 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/VarTypeNode.php +36 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/WhileNode.php +81 -0
- package/vendor/latte/latte/src/Latte/Essential/Passes.php +115 -0
- package/vendor/latte/latte/src/Latte/Essential/RawPhpExtension.php +28 -0
- package/vendor/latte/latte/src/Latte/Essential/RollbackException.php +16 -0
- package/vendor/latte/latte/src/Latte/Essential/Tracer.php +117 -0
- package/vendor/latte/latte/src/Latte/Essential/TranslatorExtension.php +101 -0
- package/vendor/latte/latte/src/Latte/Extension.php +97 -0
- package/vendor/latte/latte/src/Latte/Helpers.php +96 -0
- package/vendor/latte/latte/src/Latte/Loader.php +37 -0
- package/vendor/latte/latte/src/Latte/Loaders/FileLoader.php +95 -0
- package/vendor/latte/latte/src/Latte/Loaders/StringLoader.php +76 -0
- package/vendor/latte/latte/src/Latte/Policy.php +24 -0
- package/vendor/latte/latte/src/Latte/PositionAwareException.php +50 -0
- package/vendor/latte/latte/src/Latte/Runtime/Block.php +24 -0
- package/vendor/latte/latte/src/Latte/Runtime/FilterExecutor.php +151 -0
- package/vendor/latte/latte/src/Latte/Runtime/FilterInfo.php +39 -0
- package/vendor/latte/latte/src/Latte/Runtime/Filters.php +234 -0
- package/vendor/latte/latte/src/Latte/Runtime/Html.php +35 -0
- package/vendor/latte/latte/src/Latte/Runtime/HtmlStringable.php +17 -0
- package/vendor/latte/latte/src/Latte/Runtime/Template.php +381 -0
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallNode.php +30 -0
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallableNode.php +29 -0
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallNode.php +32 -0
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallableNode.php +30 -0
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/PropertyFetchNode.php +32 -0
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/SandboxNode.php +73 -0
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticCallNode.php +31 -0
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticCallableNode.php +30 -0
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/StaticPropertyFetchNode.php +32 -0
- package/vendor/latte/latte/src/Latte/Sandbox/RuntimeChecker.php +116 -0
- package/vendor/latte/latte/src/Latte/Sandbox/SandboxExtension.php +132 -0
- package/vendor/latte/latte/src/Latte/Sandbox/SecurityPolicy.php +185 -0
- package/vendor/latte/latte/src/Latte/Strict.php +101 -0
- package/vendor/latte/latte/src/Latte/attributes.php +24 -0
- package/vendor/latte/latte/src/Latte/exceptions.php +69 -0
- package/vendor/latte/latte/src/Tools/Linter.php +175 -0
|
@@ -0,0 +1,115 @@
|
|
|
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\Essential;
|
|
11
|
+
|
|
12
|
+
use Latte;
|
|
13
|
+
use Latte\CompileException;
|
|
14
|
+
use Latte\Compiler\ExpressionBuilder;
|
|
15
|
+
use Latte\Compiler\Node;
|
|
16
|
+
use Latte\Compiler\Nodes\AuxiliaryNode;
|
|
17
|
+
use Latte\Compiler\Nodes\Php\Expression\FunctionCallNode;
|
|
18
|
+
use Latte\Compiler\Nodes\Php\Expression\VariableNode;
|
|
19
|
+
use Latte\Compiler\Nodes\Php\NameNode;
|
|
20
|
+
use Latte\Compiler\Nodes\TemplateNode;
|
|
21
|
+
use Latte\Compiler\NodeTraverser;
|
|
22
|
+
use Latte\Compiler\PrintContext;
|
|
23
|
+
use Latte\Essential\Nodes\ForeachNode;
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
final class Passes
|
|
27
|
+
{
|
|
28
|
+
use Latte\Strict;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Checks if foreach overrides template variables.
|
|
32
|
+
*/
|
|
33
|
+
public static function overwrittenVariablesPass(TemplateNode $node): void
|
|
34
|
+
{
|
|
35
|
+
$vars = [];
|
|
36
|
+
(new NodeTraverser)->traverse($node, function (Node $node) use (&$vars) {
|
|
37
|
+
if ($node instanceof ForeachNode && $node->checkArgs) {
|
|
38
|
+
foreach ([$node->key, $node->value] as $var) {
|
|
39
|
+
if ($var instanceof VariableNode) {
|
|
40
|
+
$vars[$var->name][] = $node->position->line;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
if ($vars) {
|
|
46
|
+
array_unshift($node->head->children, new AuxiliaryNode(fn(PrintContext $context) => $context->format(
|
|
47
|
+
<<<'XX'
|
|
48
|
+
if (!$this->getReferringTemplate() || $this->getReferenceType() === 'extends') {
|
|
49
|
+
foreach (array_intersect_key(%dump, $this->params) as $ʟ_v => $ʟ_l) {
|
|
50
|
+
trigger_error("Variable \$$ʟ_v overwritten in foreach on line $ʟ_l");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
XX,
|
|
55
|
+
array_map(fn($l) => implode(', ', $l), $vars),
|
|
56
|
+
)));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Move TemplatePrintNode to head.
|
|
63
|
+
*/
|
|
64
|
+
public static function moveTemplatePrintToHeadPass(TemplateNode $templateNode): void
|
|
65
|
+
{
|
|
66
|
+
(new NodeTraverser)->traverse($templateNode->main, function (Node $node) use ($templateNode) {
|
|
67
|
+
if ($node instanceof Latte\Essential\Nodes\TemplatePrintNode) {
|
|
68
|
+
array_unshift($templateNode->head->children, $node);
|
|
69
|
+
return new Latte\Compiler\Nodes\NopNode;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Enable custom functions.
|
|
77
|
+
*/
|
|
78
|
+
public static function customFunctionsPass(TemplateNode $node, array $functions): void
|
|
79
|
+
{
|
|
80
|
+
$names = array_keys($functions);
|
|
81
|
+
$names = array_combine(array_map('strtolower', $names), $names);
|
|
82
|
+
|
|
83
|
+
(new NodeTraverser)->traverse($node, function (Node $node) use ($names) {
|
|
84
|
+
if (($node instanceof FunctionCallNode || $node instanceof FunctionCallableNode)
|
|
85
|
+
&& $node->name instanceof NameNode
|
|
86
|
+
&& ($orig = $names[strtolower((string) $node->name)] ?? null)
|
|
87
|
+
) {
|
|
88
|
+
if ((string) $node->name !== $orig) {
|
|
89
|
+
trigger_error("Case mismatch on function name '{$node->name}', correct name is '$orig'.", E_USER_WARNING);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return ExpressionBuilder::function(
|
|
93
|
+
ExpressionBuilder::variable('$this')->property('global')->property('fn')->property($orig),
|
|
94
|
+
$node->args,
|
|
95
|
+
)->build();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* $ʟ_xxx variables are forbidden
|
|
103
|
+
*/
|
|
104
|
+
public static function internalVariablesPass(TemplateNode $node): void
|
|
105
|
+
{
|
|
106
|
+
(new NodeTraverser)->traverse($node, function (Node $node) {
|
|
107
|
+
if ($node instanceof VariableNode
|
|
108
|
+
&& is_string($node->name)
|
|
109
|
+
&& (str_starts_with($node->name, 'ʟ_'))
|
|
110
|
+
) {
|
|
111
|
+
throw new CompileException("Forbidden variable \$$node->name.", $node->position);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
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\Essential;
|
|
11
|
+
|
|
12
|
+
use Latte;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Raw PHP in {php ...}
|
|
17
|
+
*/
|
|
18
|
+
final class RawPhpExtension extends Latte\Extension
|
|
19
|
+
{
|
|
20
|
+
use Latte\Strict;
|
|
21
|
+
|
|
22
|
+
public function getTags(): array
|
|
23
|
+
{
|
|
24
|
+
return [
|
|
25
|
+
'php' => [Nodes\RawPhpNode::class, 'create'],
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
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\Essential;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/** @internal */
|
|
14
|
+
class RollbackException extends \Exception
|
|
15
|
+
{
|
|
16
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
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\Essential;
|
|
11
|
+
|
|
12
|
+
use Latte;
|
|
13
|
+
use Latte\Engine;
|
|
14
|
+
use Latte\Runtime\Template;
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
final class Tracer
|
|
21
|
+
{
|
|
22
|
+
public static function throw(): void
|
|
23
|
+
{
|
|
24
|
+
$e = new Latte\RuntimeException('Your location in Latte templates');
|
|
25
|
+
$trace = debug_backtrace();
|
|
26
|
+
$props = [
|
|
27
|
+
'file' => $trace[1]['object']->getName(),
|
|
28
|
+
'line' => self::getSourceLine($trace[0]['file'], $trace[0]['line']),
|
|
29
|
+
'trace' => self::generateTrace($trace),
|
|
30
|
+
];
|
|
31
|
+
foreach ($props as $name => $value) {
|
|
32
|
+
$ref = new \ReflectionProperty('Exception', $name);
|
|
33
|
+
$ref->setAccessible(true);
|
|
34
|
+
$ref->setValue($e, $value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
throw $e;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
private static function generateTrace(array $trace): array
|
|
42
|
+
{
|
|
43
|
+
$res = [];
|
|
44
|
+
foreach ($trace as $i => $item) {
|
|
45
|
+
$object = $item['object'] ?? null;
|
|
46
|
+
if ($object instanceof Template) {
|
|
47
|
+
$method = $item['function'] ?? '';
|
|
48
|
+
|
|
49
|
+
if (str_starts_with($method, 'block')) {
|
|
50
|
+
// begin of block
|
|
51
|
+
$comment = (new \ReflectionMethod($object, $method))->getDocComment();
|
|
52
|
+
$res[] = [
|
|
53
|
+
'function' => preg_match('~(\{.+\})~', $comment, $m) ? $m[1] : '?',
|
|
54
|
+
'file' => $object->getName(),
|
|
55
|
+
'line' => preg_match('~ on line (\d+)~', $comment, $m) ? (int) $m[1] : 0,
|
|
56
|
+
'args' => [], // $L_args is not true, will be added in next step
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
} elseif ($method === 'render' && $object->getReferenceType()) {
|
|
60
|
+
// begin of included/extended/... file
|
|
61
|
+
$res[] = [
|
|
62
|
+
'function' => '{' . $object->getReferenceType() . ' ' . basename($object->getName()) . '}',
|
|
63
|
+
'file' => $object->getReferringTemplate()->getName(),
|
|
64
|
+
'line' => 0, // will be added in next step
|
|
65
|
+
'args' => self::filterParams($object->getParameters()),
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
} elseif ($method === 'renderToContentType') {
|
|
69
|
+
// {include file}, extends, embed, sandbox, ...
|
|
70
|
+
$res[count($res) - 1]['line'] = self::getSourceLine($item['file'], $item['line']);
|
|
71
|
+
|
|
72
|
+
} elseif ($method === 'renderBlock' || $method === 'renderBlockParent') {
|
|
73
|
+
// {include block}
|
|
74
|
+
$res[count($res) - 1]['args'] = self::filterParams($item['args'][1] + $object->getParameters());
|
|
75
|
+
|
|
76
|
+
if ($method !== 'renderBlock' || isset($item['args'][2])) { // is not {block}
|
|
77
|
+
$res[] = [
|
|
78
|
+
'function' => '{include ' . ($method === 'renderBlockParent' ? 'parent' : $item['args'][0]) . '}',
|
|
79
|
+
'file' => $object->getName(),
|
|
80
|
+
'line' => self::getSourceLine($item['file'], $item['line']),
|
|
81
|
+
'args' => self::filterParams($item['args'][1]),
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} elseif ($object instanceof Engine) {
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return $res;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
private static function getSourceLine(string $compiledFile, int $line): int
|
|
95
|
+
{
|
|
96
|
+
if (!is_file($compiledFile)) {
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
$line = file($compiledFile)[$line - 1];
|
|
101
|
+
return preg_match('~/\* line (\d+) \*/~', $line, $m)
|
|
102
|
+
? (int) $m[1]
|
|
103
|
+
: 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
private static function filterParams(array $params): array
|
|
108
|
+
{
|
|
109
|
+
foreach ($params as $key => $foo) {
|
|
110
|
+
if (is_string($key) && str_starts_with($key, 'ʟ_')) {
|
|
111
|
+
unset($params[$key]);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return $params;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
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\Essential;
|
|
11
|
+
|
|
12
|
+
use Latte;
|
|
13
|
+
use Latte\Compiler\NodeHelpers;
|
|
14
|
+
use Latte\Compiler\Nodes\Php;
|
|
15
|
+
use Latte\Compiler\Tag;
|
|
16
|
+
use Latte\Engine;
|
|
17
|
+
use Latte\Essential\Nodes\PrintNode;
|
|
18
|
+
use Nette\Localization\Translator;
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Extension for translations.
|
|
23
|
+
*/
|
|
24
|
+
final class TranslatorExtension extends Latte\Extension
|
|
25
|
+
{
|
|
26
|
+
public function __construct(
|
|
27
|
+
private /*?callable|Translator*/ $translator,
|
|
28
|
+
private ?string $key = null,
|
|
29
|
+
) {
|
|
30
|
+
if ($translator instanceof Translator) {
|
|
31
|
+
$this->translator = [$translator, 'translate'];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
public function getTags(): array
|
|
37
|
+
{
|
|
38
|
+
return [
|
|
39
|
+
'_' => [$this, 'parseTranslate'],
|
|
40
|
+
'translate' => fn(Tag $tag) => yield from Nodes\TranslateNode::create($tag, $this->key ? $this->translator : null),
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
public function getFilters(): array
|
|
46
|
+
{
|
|
47
|
+
return [
|
|
48
|
+
'translate' => fn(Latte\Runtime\FilterInfo $fi, ...$args): string => $this->translator
|
|
49
|
+
? ($this->translator)(...$args)
|
|
50
|
+
: $args[0],
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
public function getCacheKey(Engine $engine): mixed
|
|
56
|
+
{
|
|
57
|
+
return $this->key;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* {_ ...}
|
|
63
|
+
*/
|
|
64
|
+
public function parseTranslate(Tag $tag): PrintNode
|
|
65
|
+
{
|
|
66
|
+
$tag->outputMode = $tag::OutputKeepIndentation;
|
|
67
|
+
$tag->expectArguments();
|
|
68
|
+
$node = new PrintNode;
|
|
69
|
+
$node->expression = $tag->parser->parseUnquotedStringOrExpression();
|
|
70
|
+
$args = new Php\Expression\ArrayNode;
|
|
71
|
+
if ($tag->parser->stream->tryConsume(',')) {
|
|
72
|
+
$args = $tag->parser->parseArguments();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
$node->modifier = $tag->parser->parseModifier();
|
|
76
|
+
$node->modifier->escape = true;
|
|
77
|
+
|
|
78
|
+
if ($this->translator
|
|
79
|
+
&& $this->key
|
|
80
|
+
&& ($expr = self::toValue($node->expression))
|
|
81
|
+
&& is_array($values = self::toValue($args))
|
|
82
|
+
&& is_string($translation = ($this->translator)($expr, ...$values))
|
|
83
|
+
) {
|
|
84
|
+
$node->expression = new Php\Scalar\StringNode($translation);
|
|
85
|
+
return $node;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
array_unshift($node->modifier->filters, new Php\FilterNode(new Php\IdentifierNode('translate'), $args->toArguments()));
|
|
89
|
+
return $node;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
public static function toValue($args): mixed
|
|
94
|
+
{
|
|
95
|
+
try {
|
|
96
|
+
return NodeHelpers::toValue($args, constants: true);
|
|
97
|
+
} catch (\InvalidArgumentException) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
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;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Latte extension.
|
|
15
|
+
*/
|
|
16
|
+
abstract class Extension
|
|
17
|
+
{
|
|
18
|
+
/**
|
|
19
|
+
* Initializes before template is compiler.
|
|
20
|
+
*/
|
|
21
|
+
public function beforeCompile(Engine $engine): void
|
|
22
|
+
{
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns a list of parsers for Latte tags.
|
|
28
|
+
* @return array<string, callable(Compiler\Tag, Compiler\TemplateParser): (Compiler\Node|\Generator|void)|\stdClass>
|
|
29
|
+
*/
|
|
30
|
+
public function getTags(): array
|
|
31
|
+
{
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns a list of parsers for Latte tags.
|
|
38
|
+
* @return array<string, callable(Compiler\Nodes\TemplateNode): void|\stdClass>
|
|
39
|
+
*/
|
|
40
|
+
public function getPasses(): array
|
|
41
|
+
{
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns a list of |filters.
|
|
48
|
+
* @return array<string, callable>
|
|
49
|
+
*/
|
|
50
|
+
public function getFilters(): array
|
|
51
|
+
{
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns a list of functions used in templates.
|
|
58
|
+
* @return array<string, callable>
|
|
59
|
+
*/
|
|
60
|
+
public function getFunctions(): array
|
|
61
|
+
{
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Returns a list of providers.
|
|
68
|
+
* @return array<mixed>
|
|
69
|
+
*/
|
|
70
|
+
public function getProviders(): array
|
|
71
|
+
{
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns a value to distinguish multiple versions of the template.
|
|
78
|
+
*/
|
|
79
|
+
public function getCacheKey(Engine $engine): mixed
|
|
80
|
+
{
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Initializes before template is rendered.
|
|
87
|
+
*/
|
|
88
|
+
public function beforeRender(Engine $engine): void
|
|
89
|
+
{
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
public static function order(callable $subject, array|string $before = [], array|string $after = []): \stdClass
|
|
94
|
+
{
|
|
95
|
+
return (object) get_defined_vars();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
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;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Latte helpers.
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
class Helpers
|
|
18
|
+
{
|
|
19
|
+
/** @var array<string, int> empty (void) HTML elements */
|
|
20
|
+
public static array $emptyElements = [
|
|
21
|
+
'img' => 1, 'hr' => 1, 'br' => 1, 'input' => 1, 'meta' => 1, 'area' => 1, 'embed' => 1, 'keygen' => 1, 'source' => 1, 'base' => 1,
|
|
22
|
+
'col' => 1, 'link' => 1, 'param' => 1, 'basefont' => 1, 'frame' => 1, 'isindex' => 1, 'wbr' => 1, 'command' => 1, 'track' => 1,
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Finds the best suggestion.
|
|
28
|
+
* @param string[] $items
|
|
29
|
+
*/
|
|
30
|
+
public static function getSuggestion(array $items, string $value): ?string
|
|
31
|
+
{
|
|
32
|
+
$best = null;
|
|
33
|
+
$min = (strlen($value) / 4 + 1) * 10 + .1;
|
|
34
|
+
foreach (array_unique($items) as $item) {
|
|
35
|
+
if (($len = levenshtein($item, $value, 10, 11, 10)) > 0 && $len < $min) {
|
|
36
|
+
$min = $len;
|
|
37
|
+
$best = $item;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return $best;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
/** intentionally without callable typehint, because it generates bad error messages */
|
|
46
|
+
public static function toReflection($callable): \ReflectionFunctionAbstract
|
|
47
|
+
{
|
|
48
|
+
if (is_string($callable) && strpos($callable, '::')) {
|
|
49
|
+
return new \ReflectionMethod($callable);
|
|
50
|
+
} elseif (is_array($callable)) {
|
|
51
|
+
return new \ReflectionMethod($callable[0], $callable[1]);
|
|
52
|
+
} elseif (is_object($callable) && !$callable instanceof \Closure) {
|
|
53
|
+
return new \ReflectionMethod($callable, '__invoke');
|
|
54
|
+
} else {
|
|
55
|
+
return new \ReflectionFunction($callable);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
public static function sortBeforeAfter(array $list): array
|
|
61
|
+
{
|
|
62
|
+
foreach ($list as $name => $info) {
|
|
63
|
+
if (!$info instanceof \stdClass || !($info->before ?? $info->after ?? null)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
unset($list[$name]);
|
|
68
|
+
$names = array_keys($list);
|
|
69
|
+
$best = null;
|
|
70
|
+
|
|
71
|
+
foreach ((array) $info->before as $target) {
|
|
72
|
+
if ($target === '*') {
|
|
73
|
+
$best = 0;
|
|
74
|
+
} elseif (isset($list[$target])) {
|
|
75
|
+
$pos = array_search($target, $names, true);
|
|
76
|
+
$best = min($pos, $best ?? $pos);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
foreach ((array) ($info->after ?? null) as $target) {
|
|
81
|
+
if ($target === '*') {
|
|
82
|
+
$best = count($names);
|
|
83
|
+
} elseif (isset($list[$target])) {
|
|
84
|
+
$pos = array_search($target, $names, true);
|
|
85
|
+
$best = max($pos + 1, $best);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
$list = array_slice($list, 0, $best, true)
|
|
90
|
+
+ [$name => $info]
|
|
91
|
+
+ array_slice($list, $best, null, true);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return $list;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
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;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Template loader.
|
|
15
|
+
*/
|
|
16
|
+
interface Loader
|
|
17
|
+
{
|
|
18
|
+
/**
|
|
19
|
+
* Returns template source code.
|
|
20
|
+
*/
|
|
21
|
+
function getContent(string $name): string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Checks whether template is expired.
|
|
25
|
+
*/
|
|
26
|
+
function isExpired(string $name, int $time): bool;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns referred template name.
|
|
30
|
+
*/
|
|
31
|
+
function getReferredName(string $name, string $referringName): string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Returns unique identifier for caching.
|
|
35
|
+
*/
|
|
36
|
+
function getUniqueId(string $name): string;
|
|
37
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
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\Loaders;
|
|
11
|
+
|
|
12
|
+
use Latte;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Template loader.
|
|
17
|
+
*/
|
|
18
|
+
class FileLoader implements Latte\Loader
|
|
19
|
+
{
|
|
20
|
+
use Latte\Strict;
|
|
21
|
+
|
|
22
|
+
protected ?string $baseDir = null;
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
public function __construct(?string $baseDir = null)
|
|
26
|
+
{
|
|
27
|
+
$this->baseDir = $baseDir ? $this->normalizePath("$baseDir/") : null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns template source code.
|
|
33
|
+
*/
|
|
34
|
+
public function getContent(string $fileName): string
|
|
35
|
+
{
|
|
36
|
+
$file = $this->baseDir . $fileName;
|
|
37
|
+
if ($this->baseDir && !str_starts_with($this->normalizePath($file), $this->baseDir)) {
|
|
38
|
+
throw new Latte\RuntimeException("Template '$file' is not within the allowed path '{$this->baseDir}'.");
|
|
39
|
+
|
|
40
|
+
} elseif (!is_file($file)) {
|
|
41
|
+
throw new Latte\RuntimeException("Missing template file '$file'.");
|
|
42
|
+
|
|
43
|
+
} elseif ($this->isExpired($fileName, time())) {
|
|
44
|
+
if (@touch($file) === false) {
|
|
45
|
+
trigger_error("File's modification time is in the future. Cannot update it: " . error_get_last()['message'], E_USER_WARNING);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return file_get_contents($file);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
public function isExpired(string $file, int $time): bool
|
|
54
|
+
{
|
|
55
|
+
$mtime = @filemtime($this->baseDir . $file); // @ - stat may fail
|
|
56
|
+
return !$mtime || $mtime > $time;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns referred template name.
|
|
62
|
+
*/
|
|
63
|
+
public function getReferredName(string $file, string $referringFile): string
|
|
64
|
+
{
|
|
65
|
+
if ($this->baseDir || !preg_match('#/|\\\\|[a-z][a-z0-9+.-]*:#iA', $file)) {
|
|
66
|
+
$file = $this->normalizePath($referringFile . '/../' . $file);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return $file;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Returns unique identifier for caching.
|
|
75
|
+
*/
|
|
76
|
+
public function getUniqueId(string $file): string
|
|
77
|
+
{
|
|
78
|
+
return $this->baseDir . strtr($file, '/', DIRECTORY_SEPARATOR);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
protected static function normalizePath(string $path): string
|
|
83
|
+
{
|
|
84
|
+
$res = [];
|
|
85
|
+
foreach (explode('/', strtr($path, '\\', '/')) as $part) {
|
|
86
|
+
if ($part === '..' && $res && end($res) !== '..') {
|
|
87
|
+
array_pop($res);
|
|
88
|
+
} elseif ($part !== '.') {
|
|
89
|
+
$res[] = $part;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return implode(DIRECTORY_SEPARATOR, $res);
|
|
94
|
+
}
|
|
95
|
+
}
|