@vituum/vite-plugin-latte 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +2 -2
- package/latte/PlaceholderFunction.php +2 -2
- package/package.json +10 -11
- package/vendor/autoload.php +18 -0
- package/vendor/bin/latte-lint +16 -4
- package/vendor/composer/ClassLoader.php +72 -65
- package/vendor/composer/InstalledVersions.php +21 -12
- package/vendor/composer/autoload_classmap.php +14 -8
- package/vendor/composer/autoload_namespaces.php +1 -1
- package/vendor/composer/autoload_psr4.php +1 -1
- package/vendor/composer/autoload_real.php +3 -22
- package/vendor/composer/autoload_static.php +13 -7
- package/vendor/composer/installed.json +8 -8
- package/vendor/composer/installed.php +10 -10
- package/vendor/latte/latte/bin/latte-lint +8 -2
- package/vendor/latte/latte/composer.json +1 -1
- package/vendor/latte/latte/readme.md +6 -6
- package/vendor/latte/latte/src/Bridges/Tracy/BlueScreenPanel.php +1 -0
- package/vendor/latte/latte/src/Bridges/Tracy/LattePanel.php +3 -2
- package/vendor/latte/latte/src/Latte/Compiler/Block.php +0 -3
- package/vendor/latte/latte/src/Latte/Compiler/Escaper.php +113 -89
- package/vendor/latte/latte/src/Latte/Compiler/ExpressionBuilder.php +2 -1
- package/vendor/latte/latte/src/Latte/Compiler/Node.php +0 -4
- package/vendor/latte/latte/src/Latte/Compiler/NodeHelpers.php +0 -4
- package/vendor/latte/latte/src/Latte/Compiler/NodeTraverser.php +0 -4
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/AuxiliaryNode.php +11 -3
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/FragmentNode.php +10 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/AttributeNode.php +22 -4
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/ElementNode.php +35 -12
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ArgumentNode.php +6 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ArrayItemNode.php +12 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayNode.php +4 -31
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignNode.php +15 -1
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignOpNode.php +11 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AuxiliaryNode.php +42 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClassConstantFetchNode.php +2 -2
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClosureNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ConstantFetchNode.php +8 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/IssetNode.php +15 -1
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PostOpNode.php +11 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PreOpNode.php +11 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/{StaticCallNode.php → StaticMethodCallNode.php} +11 -1
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/{StaticCallableNode.php → StaticMethodCallableNode.php} +11 -1
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/TemporaryNode.php +38 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ExpressionNode.php +24 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/FilterNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ListItemNode.php +48 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ListNode.php +56 -0
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php +5 -5
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NameNode.php +11 -21
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/InterpolatedStringNode.php +1 -8
- package/vendor/latte/latte/src/Latte/Compiler/PhpHelpers.php +30 -0
- package/vendor/latte/latte/src/Latte/Compiler/Position.php +4 -8
- package/vendor/latte/latte/src/Latte/Compiler/PrintContext.php +15 -8
- package/vendor/latte/latte/src/Latte/Compiler/Tag.php +13 -14
- package/vendor/latte/latte/src/Latte/Compiler/TagLexer.php +5 -9
- package/vendor/latte/latte/src/Latte/Compiler/TagParser.php +52 -3
- package/vendor/latte/latte/src/Latte/Compiler/TagParserData.php +353 -326
- package/vendor/latte/latte/src/Latte/Compiler/TemplateGenerator.php +6 -5
- package/vendor/latte/latte/src/Latte/Compiler/TemplateLexer.php +105 -178
- package/vendor/latte/latte/src/Latte/Compiler/TemplateParser.php +40 -33
- package/vendor/latte/latte/src/Latte/Compiler/TemplateParserHtml.php +186 -126
- package/vendor/latte/latte/src/Latte/Compiler/Token.php +5 -9
- package/vendor/latte/latte/src/Latte/Compiler/TokenStream.php +6 -22
- package/vendor/latte/latte/src/Latte/Engine.php +136 -95
- package/vendor/latte/latte/src/Latte/Essential/AuxiliaryIterator.php +46 -0
- package/vendor/latte/latte/src/Latte/Essential/Blueprint.php +42 -27
- package/vendor/latte/latte/src/Latte/Essential/CachingIterator.php +0 -4
- package/vendor/latte/latte/src/Latte/Essential/CoreExtension.php +81 -66
- package/vendor/latte/latte/src/Latte/Essential/Filters.php +103 -43
- package/vendor/latte/latte/src/Latte/Essential/Nodes/BlockNode.php +1 -2
- package/vendor/latte/latte/src/Latte/Essential/Nodes/CaptureNode.php +2 -13
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ContentTypeNode.php +8 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/DefineNode.php +1 -2
- package/vendor/latte/latte/src/Latte/Essential/Nodes/EmbedNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ExtendsNode.php +0 -3
- package/vendor/latte/latte/src/Latte/Essential/Nodes/FirstLastSepNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ForNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ForeachNode.php +40 -13
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IfChangedNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IfContentNode.php +4 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IfNode.php +5 -3
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeBlockNode.php +5 -2
- package/vendor/latte/latte/src/Latte/Essential/Nodes/IterateWhileNode.php +6 -4
- package/vendor/latte/latte/src/Latte/Essential/Nodes/JumpNode.php +26 -23
- package/vendor/latte/latte/src/Latte/Essential/Nodes/NElseNode.php +88 -0
- package/vendor/latte/latte/src/Latte/Essential/Nodes/NTagNode.php +20 -28
- package/vendor/latte/latte/src/Latte/Essential/Nodes/PrintNode.php +7 -12
- package/vendor/latte/latte/src/Latte/Essential/Nodes/RollbackNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/SpacelessNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/SwitchNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplatePrintNode.php +25 -3
- package/vendor/latte/latte/src/Latte/Essential/Nodes/TranslateNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/TryNode.php +3 -4
- package/vendor/latte/latte/src/Latte/Essential/Nodes/VarPrintNode.php +9 -2
- package/vendor/latte/latte/src/Latte/Essential/Nodes/WhileNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Passes.php +16 -58
- package/vendor/latte/latte/src/Latte/Essential/RawPhpExtension.php +0 -2
- package/vendor/latte/latte/src/Latte/Essential/TranslatorExtension.php +6 -1
- package/vendor/latte/latte/src/Latte/Helpers.php +3 -1
- package/vendor/latte/latte/src/Latte/Loader.php +1 -0
- package/vendor/latte/latte/src/Latte/Loaders/FileLoader.php +1 -4
- package/vendor/latte/latte/src/Latte/Loaders/StringLoader.php +0 -2
- package/vendor/latte/latte/src/Latte/PositionAwareException.php +1 -1
- package/vendor/latte/latte/src/Latte/Runtime/Block.php +0 -4
- package/vendor/latte/latte/src/Latte/Runtime/FilterExecutor.php +43 -51
- package/vendor/latte/latte/src/Latte/Runtime/FilterInfo.php +0 -2
- package/vendor/latte/latte/src/Latte/Runtime/Filters.php +64 -33
- package/vendor/latte/latte/src/Latte/Runtime/FunctionExecutor.php +68 -0
- package/vendor/latte/latte/src/Latte/Runtime/Html.php +0 -4
- package/vendor/latte/latte/src/Latte/Runtime/Template.php +3 -5
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallNode.php +2 -1
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/SandboxNode.php +3 -3
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/{StaticCallNode.php → StaticMethodCallNode.php} +3 -3
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/{StaticCallableNode.php → StaticMethodCallableNode.php} +2 -2
- package/vendor/latte/latte/src/Latte/Sandbox/RuntimeChecker.php +0 -2
- package/vendor/latte/latte/src/Latte/Sandbox/SandboxExtension.php +11 -9
- package/vendor/latte/latte/src/Latte/Sandbox/SecurityPolicy.php +0 -2
- package/vendor/latte/latte/src/Latte/exceptions.php +2 -11
- package/vendor/latte/latte/src/Tools/Linter.php +13 -37
- package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/QuotedValue.php +0 -53
- package/vendor/latte/latte/src/Latte/Strict.php +0 -101
|
@@ -17,10 +17,13 @@ use Latte\Compiler\Nodes\TemplateNode;
|
|
|
17
17
|
*/
|
|
18
18
|
class Engine
|
|
19
19
|
{
|
|
20
|
-
|
|
20
|
+
public const Version = '3.0.16';
|
|
21
|
+
public const VersionId = 30016;
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
public const
|
|
23
|
+
/** @deprecated use Engine::Version */
|
|
24
|
+
public const
|
|
25
|
+
VERSION = self::Version,
|
|
26
|
+
VERSION_ID = self::VersionId;
|
|
24
27
|
|
|
25
28
|
/** @deprecated use ContentType::* */
|
|
26
29
|
public const
|
|
@@ -33,7 +36,7 @@ class Engine
|
|
|
33
36
|
|
|
34
37
|
private ?Loader $loader = null;
|
|
35
38
|
private Runtime\FilterExecutor $filters;
|
|
36
|
-
private \
|
|
39
|
+
private Runtime\FunctionExecutor $functions;
|
|
37
40
|
private \stdClass $providers;
|
|
38
41
|
|
|
39
42
|
/** @var Extension[] */
|
|
@@ -42,14 +45,17 @@ class Engine
|
|
|
42
45
|
private ?string $tempDirectory = null;
|
|
43
46
|
private bool $autoRefresh = true;
|
|
44
47
|
private bool $strictTypes = false;
|
|
48
|
+
private bool $strictParsing = false;
|
|
45
49
|
private ?Policy $policy = null;
|
|
46
50
|
private bool $sandboxed = false;
|
|
51
|
+
private ?string $phpBinary = null;
|
|
52
|
+
private ?string $cacheKey;
|
|
47
53
|
|
|
48
54
|
|
|
49
55
|
public function __construct()
|
|
50
56
|
{
|
|
51
57
|
$this->filters = new Runtime\FilterExecutor;
|
|
52
|
-
$this->functions = new \
|
|
58
|
+
$this->functions = new Runtime\FunctionExecutor;
|
|
53
59
|
$this->providers = new \stdClass;
|
|
54
60
|
$this->addExtension(new Essential\CoreExtension);
|
|
55
61
|
$this->addExtension(new Sandbox\SandboxExtension);
|
|
@@ -84,8 +90,9 @@ class Engine
|
|
|
84
90
|
* Creates template object.
|
|
85
91
|
* @param mixed[] $params
|
|
86
92
|
*/
|
|
87
|
-
public function createTemplate(string $name, array $params = []): Runtime\Template
|
|
93
|
+
public function createTemplate(string $name, array $params = [], $clearCache = true): Runtime\Template
|
|
88
94
|
{
|
|
95
|
+
$this->cacheKey = $clearCache ? null : $this->cacheKey;
|
|
89
96
|
$class = $this->getTemplateClass($name);
|
|
90
97
|
if (!class_exists($class, false)) {
|
|
91
98
|
$this->loadTemplate($name);
|
|
@@ -111,32 +118,36 @@ class Engine
|
|
|
111
118
|
throw new \LogicException('In sandboxed mode you need to set a security policy.');
|
|
112
119
|
}
|
|
113
120
|
|
|
114
|
-
$
|
|
121
|
+
$template = $this->getLoader()->getContent($name);
|
|
115
122
|
|
|
116
123
|
try {
|
|
117
|
-
$node = $this->parse($
|
|
124
|
+
$node = $this->parse($template);
|
|
118
125
|
$this->applyPasses($node);
|
|
119
|
-
$
|
|
126
|
+
$compiled = $this->generate($node, $name);
|
|
120
127
|
|
|
121
128
|
} catch (\Throwable $e) {
|
|
122
129
|
if (!$e instanceof CompileException && !$e instanceof SecurityViolationException) {
|
|
123
130
|
$e = new CompileException("Thrown exception '{$e->getMessage()}'", previous: $e);
|
|
124
131
|
}
|
|
125
132
|
|
|
126
|
-
throw $e->setSource($
|
|
133
|
+
throw $e->setSource($template, $name);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if ($this->phpBinary) {
|
|
137
|
+
Compiler\PhpHelpers::checkCode($this->phpBinary, $compiled, "(compiled $name)");
|
|
127
138
|
}
|
|
128
139
|
|
|
129
|
-
return $
|
|
140
|
+
return $compiled;
|
|
130
141
|
}
|
|
131
142
|
|
|
132
143
|
|
|
133
144
|
/**
|
|
134
145
|
* Parses template to AST node.
|
|
135
146
|
*/
|
|
136
|
-
public function parse(string $
|
|
147
|
+
public function parse(string $template): TemplateNode
|
|
137
148
|
{
|
|
138
|
-
$lexer = new Compiler\TemplateLexer;
|
|
139
149
|
$parser = new Compiler\TemplateParser;
|
|
150
|
+
$parser->strict = $this->strictParsing;
|
|
140
151
|
|
|
141
152
|
foreach ($this->extensions as $extension) {
|
|
142
153
|
$extension->beforeCompile($this);
|
|
@@ -146,7 +157,7 @@ class Engine
|
|
|
146
157
|
return $parser
|
|
147
158
|
->setContentType($this->contentType)
|
|
148
159
|
->setPolicy($this->getPolicy(effective: true))
|
|
149
|
-
->parse($
|
|
160
|
+
->parse($template);
|
|
150
161
|
}
|
|
151
162
|
|
|
152
163
|
|
|
@@ -169,16 +180,15 @@ class Engine
|
|
|
169
180
|
|
|
170
181
|
|
|
171
182
|
/**
|
|
172
|
-
* Generates
|
|
183
|
+
* Generates compiled PHP code.
|
|
173
184
|
*/
|
|
174
185
|
public function generate(TemplateNode $node, string $name): string
|
|
175
186
|
{
|
|
176
|
-
$comment = preg_match('#\n|\?#', $name) ? null : "source: $name";
|
|
177
187
|
$generator = new Compiler\TemplateGenerator;
|
|
178
188
|
return $generator->generate(
|
|
179
189
|
$node,
|
|
180
190
|
$this->getTemplateClass($name),
|
|
181
|
-
$
|
|
191
|
+
$name,
|
|
182
192
|
$this->strictTypes,
|
|
183
193
|
);
|
|
184
194
|
}
|
|
@@ -204,10 +214,10 @@ class Engine
|
|
|
204
214
|
private function loadTemplate(string $name): void
|
|
205
215
|
{
|
|
206
216
|
if (!$this->tempDirectory) {
|
|
207
|
-
$
|
|
208
|
-
if (@eval(substr($
|
|
217
|
+
$compiled = $this->compile($name);
|
|
218
|
+
if (@eval(substr($compiled, 5)) === false) { // @ is escalated to exception, substr removes <?php
|
|
209
219
|
throw (new CompileException('Error in template: ' . error_get_last()['message']))
|
|
210
|
-
->setSource($
|
|
220
|
+
->setSource($compiled, "$name (compiled)");
|
|
211
221
|
}
|
|
212
222
|
|
|
213
223
|
return;
|
|
@@ -217,36 +227,50 @@ class Engine
|
|
|
217
227
|
// 1) We want to do as little as possible IO calls on production and also directory and file can be not writable
|
|
218
228
|
// so on Linux we include the file directly without shared lock, therefore, the file must be created atomically by renaming.
|
|
219
229
|
// 2) On Windows file cannot be renamed-to while is open (ie by include), so we have to acquire a lock.
|
|
220
|
-
$
|
|
221
|
-
$
|
|
222
|
-
? $this->
|
|
230
|
+
$cacheFile = $this->getCacheFile($name);
|
|
231
|
+
$cacheKey = $this->autoRefresh
|
|
232
|
+
? md5(serialize($this->getCacheSignature($name)))
|
|
233
|
+
: null;
|
|
234
|
+
$lock = defined('PHP_WINDOWS_VERSION_BUILD') || $this->autoRefresh
|
|
235
|
+
? $this->acquireLock("$cacheFile.lock", LOCK_SH)
|
|
223
236
|
: null;
|
|
224
237
|
|
|
225
|
-
if (
|
|
238
|
+
if (
|
|
239
|
+
!($this->autoRefresh && $cacheKey !== stream_get_contents($lock))
|
|
240
|
+
&& (@include $cacheFile) !== false // @ - file may not exist
|
|
241
|
+
) {
|
|
226
242
|
return;
|
|
227
243
|
}
|
|
228
244
|
|
|
229
245
|
if ($lock) {
|
|
230
246
|
flock($lock, LOCK_UN); // release shared lock so we can get exclusive
|
|
247
|
+
fseek($lock, 0);
|
|
231
248
|
}
|
|
232
249
|
|
|
233
|
-
$lock = $this->acquireLock("$
|
|
250
|
+
$lock = $this->acquireLock("$cacheFile.lock", LOCK_EX);
|
|
234
251
|
|
|
235
252
|
// while waiting for exclusive lock, someone might have already created the cache
|
|
236
|
-
if (!is_file($
|
|
237
|
-
$
|
|
238
|
-
if (
|
|
239
|
-
|
|
240
|
-
|
|
253
|
+
if (!is_file($cacheFile) || ($this->autoRefresh && $cacheKey !== stream_get_contents($lock))) {
|
|
254
|
+
$compiled = $this->compile($name);
|
|
255
|
+
if (
|
|
256
|
+
file_put_contents("$cacheFile.tmp", $compiled) !== strlen($compiled)
|
|
257
|
+
|| !rename("$cacheFile.tmp", $cacheFile)
|
|
258
|
+
) {
|
|
259
|
+
@unlink("$cacheFile.tmp"); // @ - file may not exist
|
|
260
|
+
throw new RuntimeException("Unable to create '$cacheFile'.");
|
|
241
261
|
}
|
|
242
262
|
|
|
263
|
+
fseek($lock, 0);
|
|
264
|
+
fwrite($lock, $cacheKey ?? md5(serialize($this->getCacheSignature($name))));
|
|
265
|
+
ftruncate($lock, ftell($lock));
|
|
266
|
+
|
|
243
267
|
if (function_exists('opcache_invalidate')) {
|
|
244
|
-
@opcache_invalidate($
|
|
268
|
+
@opcache_invalidate($cacheFile, true); // @ can be restricted
|
|
245
269
|
}
|
|
246
270
|
}
|
|
247
271
|
|
|
248
|
-
if ((include $
|
|
249
|
-
throw new RuntimeException("Unable to load '$
|
|
272
|
+
if ((include $cacheFile) === false) {
|
|
273
|
+
throw new RuntimeException("Unable to load '$cacheFile'.");
|
|
250
274
|
}
|
|
251
275
|
|
|
252
276
|
flock($lock, LOCK_UN);
|
|
@@ -263,7 +287,7 @@ class Engine
|
|
|
263
287
|
throw new RuntimeException("Unable to create directory '$dir'. " . error_get_last()['message']);
|
|
264
288
|
}
|
|
265
289
|
|
|
266
|
-
$handle = @fopen($file, '
|
|
290
|
+
$handle = @fopen($file, 'c+'); // @ is escalated to exception
|
|
267
291
|
if (!$handle) {
|
|
268
292
|
throw new RuntimeException("Unable to create file '$file'. " . error_get_last()['message']);
|
|
269
293
|
} elseif (!@flock($handle, $mode)) { // @ is escalated to exception
|
|
@@ -274,54 +298,62 @@ class Engine
|
|
|
274
298
|
}
|
|
275
299
|
|
|
276
300
|
|
|
277
|
-
|
|
301
|
+
public function getCacheFile(string $name): string
|
|
278
302
|
{
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if ($time === false) {
|
|
285
|
-
return true;
|
|
286
|
-
}
|
|
303
|
+
$base = preg_match('#([/\\\\][\w@.-]{3,35}){1,3}$#D', '/' . $name, $m)
|
|
304
|
+
? preg_replace('#[^\w@.-]+#', '-', substr($m[0], 1)) . '--'
|
|
305
|
+
: '';
|
|
306
|
+
return $this->tempDirectory . '/' . $base . $this->generateCacheHash($name) . '.php';
|
|
307
|
+
}
|
|
287
308
|
|
|
288
|
-
foreach ($this->extensions as $extension) {
|
|
289
|
-
$r = new \ReflectionObject($extension);
|
|
290
|
-
if (is_file($r->getFileName()) && filemtime($r->getFileName()) > $time) {
|
|
291
|
-
return true;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
309
|
|
|
295
|
-
|
|
310
|
+
public function getTemplateClass(string $name): string
|
|
311
|
+
{
|
|
312
|
+
return 'Template_' . $this->generateCacheHash($name);
|
|
296
313
|
}
|
|
297
314
|
|
|
298
315
|
|
|
299
|
-
|
|
316
|
+
private function generateCacheHash(string $name): string
|
|
300
317
|
{
|
|
301
|
-
$
|
|
302
|
-
$
|
|
303
|
-
|
|
304
|
-
: '';
|
|
305
|
-
return "$this->tempDirectory/$base$hash.php";
|
|
318
|
+
$this->cacheKey ??= md5(serialize($this->getCacheKey()));
|
|
319
|
+
$hash = $this->cacheKey . $this->getLoader()->getUniqueId($name);
|
|
320
|
+
return substr(md5($hash), 0, 10);
|
|
306
321
|
}
|
|
307
322
|
|
|
308
323
|
|
|
309
|
-
|
|
324
|
+
/**
|
|
325
|
+
* Values that affect the results of compilation and the name of the cache file.
|
|
326
|
+
*/
|
|
327
|
+
protected function getCacheKey(): array
|
|
310
328
|
{
|
|
311
|
-
|
|
312
|
-
$this->getLoader()->getUniqueId($name),
|
|
313
|
-
self::VERSION,
|
|
314
|
-
array_keys((array) $this->functions),
|
|
329
|
+
return [
|
|
315
330
|
$this->contentType,
|
|
331
|
+
array_keys($this->getFunctions()),
|
|
332
|
+
array_map(
|
|
333
|
+
fn($extension) => [
|
|
334
|
+
get_debug_type($extension),
|
|
335
|
+
$extension->getCacheKey($this),
|
|
336
|
+
filemtime((new \ReflectionObject($extension))->getFileName()),
|
|
337
|
+
],
|
|
338
|
+
$this->extensions,
|
|
339
|
+
),
|
|
316
340
|
];
|
|
317
|
-
|
|
318
|
-
$key[] = [
|
|
319
|
-
get_debug_type($extension),
|
|
320
|
-
$extension->getCacheKey($this),
|
|
321
|
-
];
|
|
322
|
-
}
|
|
341
|
+
}
|
|
323
342
|
|
|
324
|
-
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Values that check the expiration of the compiled template.
|
|
346
|
+
*/
|
|
347
|
+
protected function getCacheSignature(string $name): array
|
|
348
|
+
{
|
|
349
|
+
return [
|
|
350
|
+
self::Version,
|
|
351
|
+
$this->getLoader()->getContent($name),
|
|
352
|
+
array_map(
|
|
353
|
+
fn($extension) => filemtime((new \ReflectionObject($extension))->getFileName()),
|
|
354
|
+
$this->extensions,
|
|
355
|
+
),
|
|
356
|
+
];
|
|
325
357
|
}
|
|
326
358
|
|
|
327
359
|
|
|
@@ -342,9 +374,9 @@ class Engine
|
|
|
342
374
|
/**
|
|
343
375
|
* Registers filter loader.
|
|
344
376
|
*/
|
|
345
|
-
public function addFilterLoader(callable $
|
|
377
|
+
public function addFilterLoader(callable $loader): static
|
|
346
378
|
{
|
|
347
|
-
$this->filters->add(null, $
|
|
379
|
+
$this->filters->add(null, $loader);
|
|
348
380
|
return $this;
|
|
349
381
|
}
|
|
350
382
|
|
|
@@ -380,7 +412,7 @@ class Engine
|
|
|
380
412
|
}
|
|
381
413
|
|
|
382
414
|
foreach ($extension->getFunctions() as $name => $value) {
|
|
383
|
-
$this->functions
|
|
415
|
+
$this->functions->add($name, $value);
|
|
384
416
|
}
|
|
385
417
|
|
|
386
418
|
foreach ($extension->getProviders() as $name => $value) {
|
|
@@ -406,7 +438,7 @@ class Engine
|
|
|
406
438
|
throw new \LogicException("Invalid function name '$name'.");
|
|
407
439
|
}
|
|
408
440
|
|
|
409
|
-
$this->functions
|
|
441
|
+
$this->functions->add($name, $callback);
|
|
410
442
|
return $this;
|
|
411
443
|
}
|
|
412
444
|
|
|
@@ -417,14 +449,7 @@ class Engine
|
|
|
417
449
|
*/
|
|
418
450
|
public function invokeFunction(string $name, array $args): mixed
|
|
419
451
|
{
|
|
420
|
-
|
|
421
|
-
$hint = ($t = Helpers::getSuggestion(array_keys((array) $this->functions), $name))
|
|
422
|
-
? ", did you mean '$t'?"
|
|
423
|
-
: '.';
|
|
424
|
-
throw new \LogicException("Function '$name' is not defined$hint");
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
return ($this->functions->$name)(...$args);
|
|
452
|
+
return ($this->functions->$name)(null, ...$args);
|
|
428
453
|
}
|
|
429
454
|
|
|
430
455
|
|
|
@@ -433,20 +458,20 @@ class Engine
|
|
|
433
458
|
*/
|
|
434
459
|
public function getFunctions(): array
|
|
435
460
|
{
|
|
436
|
-
return
|
|
461
|
+
return $this->functions->getAll();
|
|
437
462
|
}
|
|
438
463
|
|
|
439
464
|
|
|
440
465
|
/**
|
|
441
466
|
* Adds new provider.
|
|
442
467
|
*/
|
|
443
|
-
public function addProvider(string $name, mixed $
|
|
468
|
+
public function addProvider(string $name, mixed $provider): static
|
|
444
469
|
{
|
|
445
470
|
if (!preg_match('#^[a-z]\w*$#iD', $name)) {
|
|
446
471
|
throw new \LogicException("Invalid provider name '$name'.");
|
|
447
472
|
}
|
|
448
473
|
|
|
449
|
-
$this->providers->$name = $
|
|
474
|
+
$this->providers->$name = $provider;
|
|
450
475
|
return $this;
|
|
451
476
|
}
|
|
452
477
|
|
|
@@ -476,16 +501,16 @@ class Engine
|
|
|
476
501
|
}
|
|
477
502
|
|
|
478
503
|
|
|
479
|
-
public function setExceptionHandler(callable $
|
|
504
|
+
public function setExceptionHandler(callable $handler): static
|
|
480
505
|
{
|
|
481
|
-
$this->providers->coreExceptionHandler = $
|
|
506
|
+
$this->providers->coreExceptionHandler = $handler;
|
|
482
507
|
return $this;
|
|
483
508
|
}
|
|
484
509
|
|
|
485
510
|
|
|
486
|
-
public function setSandboxMode(bool $
|
|
511
|
+
public function setSandboxMode(bool $state = true): static
|
|
487
512
|
{
|
|
488
|
-
$this->sandboxed = $
|
|
513
|
+
$this->sandboxed = $state;
|
|
489
514
|
return $this;
|
|
490
515
|
}
|
|
491
516
|
|
|
@@ -510,9 +535,9 @@ class Engine
|
|
|
510
535
|
/**
|
|
511
536
|
* Sets auto-refresh mode.
|
|
512
537
|
*/
|
|
513
|
-
public function setAutoRefresh(bool $
|
|
538
|
+
public function setAutoRefresh(bool $state = true): static
|
|
514
539
|
{
|
|
515
|
-
$this->autoRefresh = $
|
|
540
|
+
$this->autoRefresh = $state;
|
|
516
541
|
return $this;
|
|
517
542
|
}
|
|
518
543
|
|
|
@@ -520,13 +545,26 @@ class Engine
|
|
|
520
545
|
/**
|
|
521
546
|
* Enables declare(strict_types=1) in templates.
|
|
522
547
|
*/
|
|
523
|
-
public function setStrictTypes(bool $
|
|
548
|
+
public function setStrictTypes(bool $state = true): static
|
|
524
549
|
{
|
|
525
|
-
$this->strictTypes = $
|
|
550
|
+
$this->strictTypes = $state;
|
|
526
551
|
return $this;
|
|
527
552
|
}
|
|
528
553
|
|
|
529
554
|
|
|
555
|
+
public function setStrictParsing(bool $state = true): static
|
|
556
|
+
{
|
|
557
|
+
$this->strictParsing = $state;
|
|
558
|
+
return $this;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
public function isStrictParsing(): bool
|
|
563
|
+
{
|
|
564
|
+
return $this->strictParsing;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
|
|
530
568
|
public function setLoader(Loader $loader): static
|
|
531
569
|
{
|
|
532
570
|
$this->loader = $loader;
|
|
@@ -536,11 +574,14 @@ class Engine
|
|
|
536
574
|
|
|
537
575
|
public function getLoader(): Loader
|
|
538
576
|
{
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
577
|
+
return $this->loader ??= new Loaders\FileLoader;
|
|
578
|
+
}
|
|
579
|
+
|
|
542
580
|
|
|
543
|
-
|
|
581
|
+
public function enablePhpLinter(?string $phpBinary): static
|
|
582
|
+
{
|
|
583
|
+
$this->phpBinary = $phpBinary;
|
|
584
|
+
return $this;
|
|
544
585
|
}
|
|
545
586
|
|
|
546
587
|
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
/**
|
|
14
|
+
* Iterates over key-value pairs.
|
|
15
|
+
* @internal
|
|
16
|
+
* @template K
|
|
17
|
+
* @template V
|
|
18
|
+
* @implements \IteratorAggregate<K, V>
|
|
19
|
+
*/
|
|
20
|
+
class AuxiliaryIterator implements \IteratorAggregate, \Countable
|
|
21
|
+
{
|
|
22
|
+
/**
|
|
23
|
+
* @param array<array{K, V}> $pairs
|
|
24
|
+
*/
|
|
25
|
+
public function __construct(
|
|
26
|
+
private array $pairs,
|
|
27
|
+
) {
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @return \Generator<K, V>
|
|
33
|
+
*/
|
|
34
|
+
public function getIterator(): \Generator
|
|
35
|
+
{
|
|
36
|
+
foreach ($this->pairs as [$key, $value]) {
|
|
37
|
+
yield $key => $value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
public function count(): int
|
|
43
|
+
{
|
|
44
|
+
return count($this->pairs);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -9,8 +9,6 @@ declare(strict_types=1);
|
|
|
9
9
|
|
|
10
10
|
namespace Latte\Essential;
|
|
11
11
|
|
|
12
|
-
use Latte;
|
|
13
|
-
use Latte\Runtime\Template;
|
|
14
12
|
use Nette\PhpGenerator as Php;
|
|
15
13
|
|
|
16
14
|
|
|
@@ -20,26 +18,46 @@ use Nette\PhpGenerator as Php;
|
|
|
20
18
|
*/
|
|
21
19
|
final class Blueprint
|
|
22
20
|
{
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
public function generateTemplateClass(
|
|
22
|
+
array $params,
|
|
23
|
+
?string $name = 'Template',
|
|
24
|
+
?string $extends = null,
|
|
25
|
+
): Php\ClassType
|
|
26
26
|
{
|
|
27
27
|
if (!class_exists(Php\ClassType::class)) {
|
|
28
|
-
throw new \LogicException('Nette PhpGenerator is required to
|
|
28
|
+
throw new \LogicException('Nette PhpGenerator is required to generate blueprint, install package `nette/php-generator`.');
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
$name = $name ?: 'Template';
|
|
32
31
|
$namespace = new Php\PhpNamespace(Php\Helpers::extractNamespace($name));
|
|
33
32
|
$class = $namespace->addClass(Php\Helpers::extractShortName($name));
|
|
33
|
+
if ($extends) {
|
|
34
|
+
if (class_exists($extends)) {
|
|
35
|
+
if ((new \ReflectionClass($extends))->isFinal()) {
|
|
36
|
+
throw new \LogicException("Blueprint error: Unable to extend final class $extends");
|
|
37
|
+
}
|
|
38
|
+
$class->setExtends($extends);
|
|
39
|
+
} elseif (trait_exists($extends)) {
|
|
40
|
+
$class->addTrait($extends);
|
|
41
|
+
} else {
|
|
42
|
+
throw new \LogicException("Blueprint error: Class '$extends' doesn't exist.");
|
|
43
|
+
}
|
|
44
|
+
$params = array_diff_key($params, get_class_vars($extends));
|
|
45
|
+
}
|
|
46
|
+
$this->addProperties($class, $params);
|
|
47
|
+
return $class;
|
|
48
|
+
}
|
|
34
49
|
|
|
35
|
-
$this->addProperties($class, $template->getParameters());
|
|
36
|
-
$functions = array_diff_key((array) $template->global->fn, (new Latte\Essential\CoreExtension)->getFunctions());
|
|
37
|
-
$this->addFunctions($class, $functions);
|
|
38
50
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
$this->printCode((string) $
|
|
42
|
-
|
|
51
|
+
public function printClass(Php\ClassType $class): void
|
|
52
|
+
{
|
|
53
|
+
$this->printCode((string) $class->getNamespace());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
public function clickableFile(string $file, int $line = 1): string
|
|
58
|
+
{
|
|
59
|
+
$link = 'editor://open/?file=' . rawurlencode(strtr($file, '/', DIRECTORY_SEPARATOR)) . '&line=' . $line;
|
|
60
|
+
return '<a href="' . htmlspecialchars($link) . '">' . htmlspecialchars($file) . '</a>';
|
|
43
61
|
}
|
|
44
62
|
|
|
45
63
|
|
|
@@ -48,24 +66,16 @@ final class Blueprint
|
|
|
48
66
|
*/
|
|
49
67
|
public function printVars(array $vars): void
|
|
50
68
|
{
|
|
51
|
-
if (!class_exists(Php\Type::class)) {
|
|
52
|
-
throw new \LogicException('Nette PhpGenerator is required to print template, install package `nette/php-generator`.');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
69
|
$res = '';
|
|
56
70
|
foreach ($vars as $name => $value) {
|
|
57
|
-
if (str_starts_with($name, 'ʟ_')) {
|
|
58
|
-
|
|
71
|
+
if (!str_starts_with($name, 'ʟ_')) {
|
|
72
|
+
$type = $this->getType($value);
|
|
73
|
+
$res .= "{varType $type $$name}\n";
|
|
59
74
|
}
|
|
60
|
-
|
|
61
|
-
$type = $this->getType($value);
|
|
62
|
-
$res .= "{varType $type $$name}\n";
|
|
63
75
|
}
|
|
64
76
|
|
|
65
|
-
$end = $this->printCanvas();
|
|
66
77
|
$this->printHeader('varPrint');
|
|
67
78
|
$this->printCode($res ?: 'No variables', 'latte');
|
|
68
|
-
echo $end;
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
|
|
@@ -136,12 +146,17 @@ final class Blueprint
|
|
|
136
146
|
}
|
|
137
147
|
|
|
138
148
|
|
|
139
|
-
public function
|
|
149
|
+
public function printBegin(): void
|
|
140
150
|
{
|
|
141
151
|
echo '<script src="https://nette.github.io/resources/prism/prism.js"></script>';
|
|
142
152
|
echo '<link rel="stylesheet" href="https://nette.github.io/resources/prism/prism.css">';
|
|
143
153
|
echo "<div style='all:initial;position:fixed;overflow:auto;z-index:1000;left:0;right:0;top:0;bottom:0;color:black;background:white;padding:1em'>\n";
|
|
144
|
-
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
public function printEnd(): void
|
|
158
|
+
{
|
|
159
|
+
echo "</div>\n";
|
|
145
160
|
}
|
|
146
161
|
|
|
147
162
|
|
|
@@ -9,8 +9,6 @@ declare(strict_types=1);
|
|
|
9
9
|
|
|
10
10
|
namespace Latte\Essential;
|
|
11
11
|
|
|
12
|
-
use Latte;
|
|
13
|
-
|
|
14
12
|
|
|
15
13
|
/**
|
|
16
14
|
* Smarter caching iterator.
|
|
@@ -29,8 +27,6 @@ use Latte;
|
|
|
29
27
|
*/
|
|
30
28
|
class CachingIterator extends \CachingIterator implements \Countable
|
|
31
29
|
{
|
|
32
|
-
use Latte\Strict;
|
|
33
|
-
|
|
34
30
|
private int $counter = 0;
|
|
35
31
|
private ?self $parent = null;
|
|
36
32
|
|