@vituum/vite-plugin-latte 1.0.0-beta.1 → 1.1.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/package.json +13 -11
- package/types/index.d.ts +2 -0
- package/vendor/autoload.php +19 -1
- 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 +12 -8
- package/vendor/composer/autoload_namespaces.php +1 -1
- package/vendor/composer/autoload_psr4.php +1 -1
- package/vendor/composer/autoload_real.php +7 -26
- package/vendor/composer/autoload_static.php +13 -9
- 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 +103 -88
- 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/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 +3 -3
- 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 +14 -7
- package/vendor/latte/latte/src/Latte/Compiler/Tag.php +13 -14
- package/vendor/latte/latte/src/Latte/Compiler/TagLexer.php +3 -7
- package/vendor/latte/latte/src/Latte/Compiler/TagParser.php +52 -3
- package/vendor/latte/latte/src/Latte/Compiler/TagParserData.php +354 -322
- package/vendor/latte/latte/src/Latte/Compiler/TemplateGenerator.php +6 -5
- package/vendor/latte/latte/src/Latte/Compiler/TemplateLexer.php +95 -176
- package/vendor/latte/latte/src/Latte/Compiler/TemplateParser.php +40 -33
- package/vendor/latte/latte/src/Latte/Compiler/TemplateParserHtml.php +182 -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 +37 -8
- package/vendor/latte/latte/src/Latte/Essential/Blueprint.php +0 -2
- package/vendor/latte/latte/src/Latte/Essential/CachingIterator.php +0 -4
- package/vendor/latte/latte/src/Latte/Essential/CoreExtension.php +14 -3
- package/vendor/latte/latte/src/Latte/Essential/Filters.php +8 -6
- 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 +1 -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 +4 -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/TranslateNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Nodes/TryNode.php +3 -4
- package/vendor/latte/latte/src/Latte/Essential/Nodes/WhileNode.php +1 -1
- package/vendor/latte/latte/src/Latte/Essential/Passes.php +9 -11
- 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/Loaders/FileLoader.php +0 -2
- 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 -30
- package/vendor/latte/latte/src/Latte/Runtime/Html.php +0 -4
- package/vendor/latte/latte/src/Latte/Runtime/Template.php +2 -2
- 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
|
@@ -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
|
|
|
@@ -15,6 +15,7 @@ use Latte\Compiler\Nodes\TemplateNode;
|
|
|
15
15
|
use Latte\Compiler\Nodes\TextNode;
|
|
16
16
|
use Latte\Compiler\Tag;
|
|
17
17
|
use Latte\Compiler\TemplateParser;
|
|
18
|
+
use Latte\Runtime;
|
|
18
19
|
use Latte\RuntimeException;
|
|
19
20
|
use Nette;
|
|
20
21
|
|
|
@@ -24,14 +25,21 @@ use Nette;
|
|
|
24
25
|
*/
|
|
25
26
|
final class CoreExtension extends Latte\Extension
|
|
26
27
|
{
|
|
27
|
-
use Latte\Strict;
|
|
28
|
-
|
|
29
28
|
private array $functions;
|
|
29
|
+
private bool $strict;
|
|
30
|
+
private Runtime\Template $template;
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
public function beforeCompile(Latte\Engine $engine): void
|
|
33
34
|
{
|
|
34
35
|
$this->functions = $engine->getFunctions();
|
|
36
|
+
$this->strict = $engine->isStrictParsing();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
public function beforeRender(Runtime\Template $template): void
|
|
41
|
+
{
|
|
42
|
+
$this->template = $template;
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
|
|
@@ -92,6 +100,7 @@ final class CoreExtension extends Latte\Extension
|
|
|
92
100
|
'ifset' => [Nodes\IfNode::class, 'create'],
|
|
93
101
|
'ifchanged' => [Nodes\IfChangedNode::class, 'create'],
|
|
94
102
|
'n:ifcontent' => [Nodes\IfContentNode::class, 'create'],
|
|
103
|
+
'n:else' => [Nodes\NElseNode::class, 'create'],
|
|
95
104
|
'switch' => [Nodes\SwitchNode::class, 'create'],
|
|
96
105
|
];
|
|
97
106
|
}
|
|
@@ -178,6 +187,7 @@ final class CoreExtension extends Latte\Extension
|
|
|
178
187
|
'last' => [Filters::class, 'last'],
|
|
179
188
|
'odd' => [Filters::class, 'odd'],
|
|
180
189
|
'slice' => [Filters::class, 'slice'],
|
|
190
|
+
'hasBlock' => fn(string $name): bool => $this->template->hasBlock($name),
|
|
181
191
|
];
|
|
182
192
|
}
|
|
183
193
|
|
|
@@ -185,10 +195,11 @@ final class CoreExtension extends Latte\Extension
|
|
|
185
195
|
public function getPasses(): array
|
|
186
196
|
{
|
|
187
197
|
return [
|
|
188
|
-
'internalVariables' =>
|
|
198
|
+
'internalVariables' => fn(TemplateNode $node) => Passes::internalVariablesPass($node, $this->strict),
|
|
189
199
|
'overwrittenVariables' => [Passes::class, 'overwrittenVariablesPass'],
|
|
190
200
|
'customFunctions' => fn(TemplateNode $node) => Passes::customFunctionsPass($node, $this->functions),
|
|
191
201
|
'moveTemplatePrintToHead' => [Passes::class, 'moveTemplatePrintToHeadPass'],
|
|
202
|
+
'nElse' => [Nodes\NElseNode::class, 'processPass'],
|
|
192
203
|
];
|
|
193
204
|
}
|
|
194
205
|
|
|
@@ -120,7 +120,7 @@ final class Filters
|
|
|
120
120
|
} elseif ($info->contentType === ContentType::Html) {
|
|
121
121
|
$s = preg_replace_callback('#<(textarea|pre).*?</\1#si', fn($m) => strtr($m[0], " \t\r\n", "\x1F\x1E\x1D\x1A"), $s);
|
|
122
122
|
if (preg_last_error()) {
|
|
123
|
-
throw new Latte\
|
|
123
|
+
throw new Latte\RuntimeException(preg_last_error_msg());
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
$s = preg_replace('#(?:^|[\r\n]+)(?=[^\r\n])#', '$0' . str_repeat($chars, $level), $s);
|
|
@@ -250,7 +250,7 @@ final class Filters
|
|
|
250
250
|
{
|
|
251
251
|
$res = preg_replace($pattern, $replacement, $subject);
|
|
252
252
|
if (preg_last_error()) {
|
|
253
|
-
throw new Latte\
|
|
253
|
+
throw new Latte\RuntimeException(preg_last_error_msg());
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
return $res;
|
|
@@ -372,9 +372,11 @@ final class Filters
|
|
|
372
372
|
|
|
373
373
|
private static function strLength(string $s): int
|
|
374
374
|
{
|
|
375
|
-
return
|
|
376
|
-
|
|
377
|
-
|
|
375
|
+
return match (true) {
|
|
376
|
+
extension_loaded('mbstring') => mb_strlen($s, 'UTF-8'),
|
|
377
|
+
extension_loaded('iconv') => iconv_strlen($s, 'UTF-8'),
|
|
378
|
+
default => strlen(@utf8_decode($s)), // deprecated
|
|
379
|
+
};
|
|
378
380
|
}
|
|
379
381
|
|
|
380
382
|
|
|
@@ -386,7 +388,7 @@ final class Filters
|
|
|
386
388
|
$charlist = preg_quote($charlist, '#');
|
|
387
389
|
$s = preg_replace('#^[' . $charlist . ']+|[' . $charlist . ']+$#Du', '', (string) $s);
|
|
388
390
|
if (preg_last_error()) {
|
|
389
|
-
throw new Latte\
|
|
391
|
+
throw new Latte\RuntimeException(preg_last_error_msg());
|
|
390
392
|
}
|
|
391
393
|
|
|
392
394
|
return $s;
|
|
@@ -40,7 +40,7 @@ class BlockNode extends StatementNode
|
|
|
40
40
|
{
|
|
41
41
|
$tag->outputMode = $tag::OutputRemoveIndentation;
|
|
42
42
|
$stream = $tag->parser->stream;
|
|
43
|
-
$node = new static;
|
|
43
|
+
$node = $tag->node = new static;
|
|
44
44
|
|
|
45
45
|
if (!$stream->is('|', Token::End)) {
|
|
46
46
|
$layer = $tag->parser->tryConsumeTokenBeforeUnquotedString('local')
|
|
@@ -52,7 +52,6 @@ class BlockNode extends StatementNode
|
|
|
52
52
|
|
|
53
53
|
if (!$node->block->isDynamic()) {
|
|
54
54
|
$parser->checkBlockIsUnique($node->block);
|
|
55
|
-
$tag->data->block = $node->block; // for {include}
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -11,9 +11,7 @@ namespace Latte\Essential\Nodes;
|
|
|
11
11
|
|
|
12
12
|
use Latte\CompileException;
|
|
13
13
|
use Latte\Compiler\Escaper;
|
|
14
|
-
use Latte\Compiler\Node;
|
|
15
14
|
use Latte\Compiler\Nodes\AreaNode;
|
|
16
|
-
use Latte\Compiler\Nodes\Php\Expression;
|
|
17
15
|
use Latte\Compiler\Nodes\Php\ExpressionNode;
|
|
18
16
|
use Latte\Compiler\Nodes\Php\ModifierNode;
|
|
19
17
|
use Latte\Compiler\Nodes\StatementNode;
|
|
@@ -36,7 +34,7 @@ class CaptureNode extends StatementNode
|
|
|
36
34
|
{
|
|
37
35
|
$tag->expectArguments();
|
|
38
36
|
$variable = $tag->parser->parseExpression();
|
|
39
|
-
if (
|
|
37
|
+
if (!$variable->isWritable()) {
|
|
40
38
|
$text = '';
|
|
41
39
|
$i = 0;
|
|
42
40
|
while ($token = $tag->parser->stream->peek(--$i)) {
|
|
@@ -45,7 +43,7 @@ class CaptureNode extends StatementNode
|
|
|
45
43
|
|
|
46
44
|
throw new CompileException("It is not possible to write into '$text' in " . $tag->getNotation(), $tag->position);
|
|
47
45
|
}
|
|
48
|
-
$node = new static;
|
|
46
|
+
$node = $tag->node = new static;
|
|
49
47
|
$node->variable = $variable;
|
|
50
48
|
$node->modifier = $tag->parser->parseModifier();
|
|
51
49
|
[$node->content] = yield;
|
|
@@ -80,15 +78,6 @@ class CaptureNode extends StatementNode
|
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
|
|
83
|
-
private static function canBeAssignedTo(Node $node): bool
|
|
84
|
-
{
|
|
85
|
-
return $node instanceof Expression\VariableNode
|
|
86
|
-
|| $node instanceof Expression\ArrayAccessNode
|
|
87
|
-
|| $node instanceof Expression\PropertyFetchNode
|
|
88
|
-
|| $node instanceof Expression\StaticPropertyFetchNode;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
81
|
public function &getIterator(): \Generator
|
|
93
82
|
{
|
|
94
83
|
yield $this->variable;
|
|
@@ -32,7 +32,7 @@ class ContentTypeNode extends StatementNode
|
|
|
32
32
|
while (!$tag->parser->stream->consume()->isEnd());
|
|
33
33
|
$type = trim($tag->parser->text);
|
|
34
34
|
|
|
35
|
-
if (!$tag->isInHead() && !($tag->htmlElement?->
|
|
35
|
+
if (!$tag->isInHead() && !($tag->htmlElement?->is('script') && str_contains($type, 'html'))) {
|
|
36
36
|
throw new CompileException('{contentType} is allowed only in template header.', $tag->position);
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -42,11 +42,10 @@ class DefineNode extends StatementNode
|
|
|
42
42
|
$tag->parser->stream->tryConsume('#');
|
|
43
43
|
$name = $tag->parser->parseUnquotedStringOrExpression();
|
|
44
44
|
|
|
45
|
-
$node = new static;
|
|
45
|
+
$node = $tag->node = new static;
|
|
46
46
|
$node->block = new Block($name, $layer, $tag);
|
|
47
47
|
if (!$node->block->isDynamic()) {
|
|
48
48
|
$parser->checkBlockIsUnique($node->block);
|
|
49
|
-
$tag->data->block = $node->block; // for {include}
|
|
50
49
|
$tag->parser->stream->tryConsume(',');
|
|
51
50
|
$node->block->parameters = self::parseParameters($tag);
|
|
52
51
|
}
|
|
@@ -43,7 +43,7 @@ class EmbedNode extends StatementNode
|
|
|
43
43
|
$tag->outputMode = $tag::OutputRemoveIndentation;
|
|
44
44
|
$tag->expectArguments();
|
|
45
45
|
|
|
46
|
-
$node = new static;
|
|
46
|
+
$node = $tag->node = new static;
|
|
47
47
|
$mode = $tag->parser->tryConsumeTokenBeforeUnquotedString('block', 'file')?->text;
|
|
48
48
|
$node->name = $tag->parser->parseUnquotedStringOrExpression();
|
|
49
49
|
$node->mode = $mode ?? ($node->name instanceof StringNode && preg_match('~[\w-]+$~DA', $node->name->value) ? 'block' : 'file');
|
|
@@ -33,8 +33,6 @@ class ExtendsNode extends StatementNode
|
|
|
33
33
|
$node = new static;
|
|
34
34
|
if (!$tag->isInHead()) {
|
|
35
35
|
throw new CompileException("{{$tag->name}} must be placed in template head.", $tag->position);
|
|
36
|
-
} elseif (isset($tag->data->extends)) {
|
|
37
|
-
throw new CompileException("Multiple {{$tag->name}} declarations are not allowed.", $tag->position);
|
|
38
36
|
} elseif ($tag->parser->stream->tryConsume('auto')) {
|
|
39
37
|
$node->extends = new NullNode;
|
|
40
38
|
} elseif ($tag->parser->stream->tryConsume('none')) {
|
|
@@ -42,7 +40,6 @@ class ExtendsNode extends StatementNode
|
|
|
42
40
|
} else {
|
|
43
41
|
$node->extends = $tag->parser->parseUnquotedStringOrExpression();
|
|
44
42
|
}
|
|
45
|
-
$tag->data->extends = true;
|
|
46
43
|
return $node;
|
|
47
44
|
}
|
|
48
45
|
|
|
@@ -34,7 +34,7 @@ class FirstLastSepNode extends StatementNode
|
|
|
34
34
|
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
|
|
35
35
|
public static function create(Tag $tag): \Generator
|
|
36
36
|
{
|
|
37
|
-
$node = new static;
|
|
37
|
+
$node = $tag->node = new static;
|
|
38
38
|
$node->name = $tag->name;
|
|
39
39
|
$node->width = $tag->parser->isEnd() ? null : $tag->parser->parseExpression();
|
|
40
40
|
|
|
@@ -35,7 +35,7 @@ class ForNode extends StatementNode
|
|
|
35
35
|
{
|
|
36
36
|
$tag->expectArguments();
|
|
37
37
|
$stream = $tag->parser->stream;
|
|
38
|
-
$node = new static;
|
|
38
|
+
$node = $tag->node = new static;
|
|
39
39
|
while (!$stream->is(';')) {
|
|
40
40
|
$node->init[] = $tag->parser->parseExpression();
|
|
41
41
|
$stream->tryConsume(',');
|
|
@@ -13,6 +13,7 @@ use Latte\CompileException;
|
|
|
13
13
|
use Latte\Compiler\Nodes\AreaNode;
|
|
14
14
|
use Latte\Compiler\Nodes\NopNode;
|
|
15
15
|
use Latte\Compiler\Nodes\Php\ExpressionNode;
|
|
16
|
+
use Latte\Compiler\Nodes\Php\ListNode;
|
|
16
17
|
use Latte\Compiler\Nodes\StatementNode;
|
|
17
18
|
use Latte\Compiler\Position;
|
|
18
19
|
use Latte\Compiler\PrintContext;
|
|
@@ -28,7 +29,7 @@ class ForeachNode extends StatementNode
|
|
|
28
29
|
public ExpressionNode $expression;
|
|
29
30
|
public ?ExpressionNode $key = null;
|
|
30
31
|
public bool $byRef = false;
|
|
31
|
-
public ExpressionNode $value;
|
|
32
|
+
public ExpressionNode|ListNode $value;
|
|
32
33
|
public AreaNode $content;
|
|
33
34
|
public ?AreaNode $else = null;
|
|
34
35
|
public ?Position $elseLine = null;
|
|
@@ -40,9 +41,8 @@ class ForeachNode extends StatementNode
|
|
|
40
41
|
public static function create(Tag $tag): \Generator
|
|
41
42
|
{
|
|
42
43
|
$tag->expectArguments();
|
|
43
|
-
$node = new static;
|
|
44
|
+
$node = $tag->node = new static;
|
|
44
45
|
self::parseArguments($tag->parser, $node);
|
|
45
|
-
$tag->data->iterateWhile = [$node->key, $node->value];
|
|
46
46
|
|
|
47
47
|
$modifier = $tag->parser->parseModifier();
|
|
48
48
|
foreach ($modifier->filters as $filter) {
|
|
@@ -73,16 +73,7 @@ class ForeachNode extends StatementNode
|
|
|
73
73
|
$stream = $parser->stream;
|
|
74
74
|
$node->expression = $parser->parseExpression();
|
|
75
75
|
$stream->consume('as');
|
|
76
|
-
|
|
77
|
-
$node->value = $parser->parseExpression();
|
|
78
|
-
if (!$stream->tryConsume('=>')) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
$node->key = $node->value;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
$node->byRef = (bool) $stream->tryConsume('&');
|
|
85
|
-
$node->value = $parser->parseExpression();
|
|
76
|
+
[$node->key, $node->value, $node->byRef] = $parser->parseForeach();
|
|
86
77
|
}
|
|
87
78
|
|
|
88
79
|
|
|
@@ -31,7 +31,7 @@ class IfChangedNode extends StatementNode
|
|
|
31
31
|
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
|
|
32
32
|
public static function create(Tag $tag): \Generator
|
|
33
33
|
{
|
|
34
|
-
$node = new static;
|
|
34
|
+
$node = $tag->node = new static;
|
|
35
35
|
$node->conditions = $tag->parser->parseArguments();
|
|
36
36
|
|
|
37
37
|
[$node->then, $nextTag] = yield ['else'];
|
|
@@ -27,12 +27,13 @@ class IfContentNode extends StatementNode
|
|
|
27
27
|
public AreaNode $content;
|
|
28
28
|
public int $id;
|
|
29
29
|
public ElementNode $htmlElement;
|
|
30
|
+
public ?AreaNode $else = null;
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
|
|
33
34
|
public static function create(Tag $tag, TemplateParser $parser): \Generator
|
|
34
35
|
{
|
|
35
|
-
$node = new static;
|
|
36
|
+
$node = $tag->node = new static;
|
|
36
37
|
$node->id = $parser->generateId();
|
|
37
38
|
[$node->content] = yield;
|
|
38
39
|
$node->htmlElement = $tag->htmlElement;
|
|
@@ -47,6 +48,7 @@ class IfContentNode extends StatementNode
|
|
|
47
48
|
{
|
|
48
49
|
try {
|
|
49
50
|
$saved = $this->htmlElement->content;
|
|
51
|
+
$else = $this->else ?? new AuxiliaryNode(fn() => '');
|
|
50
52
|
$this->htmlElement->content = new AuxiliaryNode(fn() => <<<XX
|
|
51
53
|
ob_start();
|
|
52
54
|
try {
|
|
@@ -63,6 +65,7 @@ class IfContentNode extends StatementNode
|
|
|
63
65
|
} finally {
|
|
64
66
|
if (\$ʟ_ifc[$this->id] ?? null) {
|
|
65
67
|
ob_end_clean();
|
|
68
|
+
{$else->print($context)}
|
|
66
69
|
} else {
|
|
67
70
|
echo ob_get_clean();
|
|
68
71
|
}
|
|
@@ -10,7 +10,6 @@ declare(strict_types=1);
|
|
|
10
10
|
namespace Latte\Essential\Nodes;
|
|
11
11
|
|
|
12
12
|
use Latte\CompileException;
|
|
13
|
-
use Latte\Compiler\ExpressionBuilder;
|
|
14
13
|
use Latte\Compiler\Nodes\AreaNode;
|
|
15
14
|
use Latte\Compiler\Nodes\Php\Expression;
|
|
16
15
|
use Latte\Compiler\Nodes\Php\ExpressionNode;
|
|
@@ -42,7 +41,7 @@ class IfNode extends StatementNode
|
|
|
42
41
|
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
|
|
43
42
|
public static function create(Tag $tag, TemplateParser $parser): \Generator
|
|
44
43
|
{
|
|
45
|
-
$node = new static;
|
|
44
|
+
$node = $tag->node = new static;
|
|
46
45
|
$node->ifset = in_array($tag->name, ['ifset', 'elseifset'], true);
|
|
47
46
|
$node->capture = !$tag->isNAttribute() && $tag->name === 'if' && $tag->parser->isEnd();
|
|
48
47
|
$node->position = $tag->position;
|
|
@@ -83,7 +82,10 @@ class IfNode extends StatementNode
|
|
|
83
82
|
$block = $parser->tryConsumeTokenBeforeUnquotedString('block') ?? $parser->stream->tryConsume('#');
|
|
84
83
|
$name = $parser->parseUnquotedStringOrExpression();
|
|
85
84
|
$list[] = $block || $name instanceof StringNode
|
|
86
|
-
?
|
|
85
|
+
? new Expression\AuxiliaryNode(
|
|
86
|
+
fn(PrintContext $context, ExpressionNode $name) => '$this->hasBlock(' . $name->print($context) . ')',
|
|
87
|
+
[$name],
|
|
88
|
+
)
|
|
87
89
|
: new Expression\IssetNode([$name]);
|
|
88
90
|
} while ($parser->stream->tryConsume(','));
|
|
89
91
|
|
|
@@ -65,12 +65,15 @@ class IncludeBlockNode extends StatementNode
|
|
|
65
65
|
throw new CompileException('Filters are not allowed in {include parent}', $tag->position);
|
|
66
66
|
|
|
67
67
|
} elseif ($node->parent || $tokenName->is('this')) {
|
|
68
|
-
$item = $tag->closestTag(
|
|
68
|
+
$item = $tag->closestTag(
|
|
69
|
+
[BlockNode::class, DefineNode::class],
|
|
70
|
+
fn($item) => $item->node?->block && !$item->node->block->isDynamic() && $item->node->block->name !== ''
|
|
71
|
+
);
|
|
69
72
|
if (!$item) {
|
|
70
73
|
throw new CompileException("Cannot include $tokenName->text block outside of any block.", $tag->position);
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
$node->name = $item->
|
|
76
|
+
$node->name = $item->node->block->name;
|
|
74
77
|
}
|
|
75
78
|
|
|
76
79
|
$node->blocks = &$parser->blocks;
|
|
@@ -12,6 +12,7 @@ namespace Latte\Essential\Nodes;
|
|
|
12
12
|
use Latte\CompileException;
|
|
13
13
|
use Latte\Compiler\Nodes\AreaNode;
|
|
14
14
|
use Latte\Compiler\Nodes\Php\ExpressionNode;
|
|
15
|
+
use Latte\Compiler\Nodes\Php\ListNode;
|
|
15
16
|
use Latte\Compiler\Nodes\StatementNode;
|
|
16
17
|
use Latte\Compiler\PrintContext;
|
|
17
18
|
use Latte\Compiler\Tag;
|
|
@@ -25,25 +26,26 @@ class IterateWhileNode extends StatementNode
|
|
|
25
26
|
public ExpressionNode $condition;
|
|
26
27
|
public AreaNode $content;
|
|
27
28
|
public ?ExpressionNode $key;
|
|
28
|
-
public ExpressionNode $value;
|
|
29
|
+
public ExpressionNode|ListNode $value;
|
|
29
30
|
public bool $postTest;
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
|
|
33
34
|
public static function create(Tag $tag): \Generator
|
|
34
35
|
{
|
|
35
|
-
$foreach = $tag->closestTag([
|
|
36
|
+
$foreach = $tag->closestTag([ForeachNode::class])?->node;
|
|
36
37
|
if (!$foreach) {
|
|
37
38
|
throw new CompileException("Tag {{$tag->name}} must be inside {foreach} ... {/foreach}.", $tag->position);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
$node = new static;
|
|
41
|
+
$node = $tag->node = new static;
|
|
41
42
|
$node->postTest = $tag->parser->isEnd();
|
|
42
43
|
if (!$node->postTest) {
|
|
43
44
|
$node->condition = $tag->parser->parseExpression();
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
$node->key = $foreach->key;
|
|
48
|
+
$node->value = $foreach->value;
|
|
47
49
|
[$node->content, $nextTag] = yield;
|
|
48
50
|
if ($node->postTest) {
|
|
49
51
|
$nextTag->expectArguments();
|
|
@@ -26,54 +26,57 @@ class JumpNode extends StatementNode
|
|
|
26
26
|
{
|
|
27
27
|
public string $type;
|
|
28
28
|
public ExpressionNode $condition;
|
|
29
|
-
public ?string $endTag = null;
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
public static function create(Tag $tag): static
|
|
33
32
|
{
|
|
34
33
|
$tag->expectArguments();
|
|
35
|
-
$
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
34
|
+
$tag->outputMode = $tag->name === 'exitIf' // to not be in prepare()
|
|
35
|
+
? $tag::OutputRemoveIndentation
|
|
36
|
+
: $tag::OutputNone;
|
|
37
|
+
|
|
40
38
|
for (
|
|
41
39
|
$parent = $tag->parent;
|
|
42
|
-
|
|
40
|
+
$parent?->node instanceof IfNode || $parent?->node instanceof IfContentNode;
|
|
43
41
|
$parent = $parent->parent
|
|
44
42
|
);
|
|
45
|
-
|
|
43
|
+
$pnode = $parent?->node;
|
|
44
|
+
if (!match ($tag->name) {
|
|
45
|
+
'breakIf', 'continueIf' => $pnode instanceof ForNode || $pnode instanceof ForeachNode || $pnode instanceof WhileNode,
|
|
46
|
+
'skipIf' => $pnode instanceof ForeachNode,
|
|
47
|
+
'exitIf' => !$pnode || $pnode instanceof BlockNode || $pnode instanceof DefineNode,
|
|
48
|
+
}) {
|
|
46
49
|
throw new CompileException("Tag {{$tag->name}} is unexpected here.", $tag->position);
|
|
47
50
|
}
|
|
48
51
|
|
|
52
|
+
$last = $parent?->prefix === Tag::PrefixNone
|
|
53
|
+
? $parent->htmlElement->parent
|
|
54
|
+
: $parent?->htmlElement;
|
|
55
|
+
$el = $tag->htmlElement;
|
|
56
|
+
while ($el && $el !== $last) {
|
|
57
|
+
$el->breakable = true;
|
|
58
|
+
$el = $el->parent;
|
|
59
|
+
}
|
|
60
|
+
|
|
49
61
|
$node = new static;
|
|
50
62
|
$node->type = $tag->name;
|
|
51
63
|
$node->condition = $tag->parser->parseExpression();
|
|
52
|
-
if (isset($tag->htmlElement->nAttributes['foreach'])) {
|
|
53
|
-
$node->endTag = $tag->htmlElement->name;
|
|
54
|
-
}
|
|
55
64
|
return $node;
|
|
56
65
|
}
|
|
57
66
|
|
|
58
67
|
|
|
59
68
|
public function print(PrintContext $context): string
|
|
60
69
|
{
|
|
61
|
-
$cmd = match ($this->type) {
|
|
62
|
-
'breakIf' => 'break;',
|
|
63
|
-
'continueIf' => 'continue;',
|
|
64
|
-
'skipIf' => '{ $iterator->skipRound(); continue; }',
|
|
65
|
-
'exitIf' => 'return;',
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
if ($this->endTag) {
|
|
69
|
-
$cmd = "{ echo \"</$this->endTag>\\n\"; $cmd; } ";
|
|
70
|
-
}
|
|
71
|
-
|
|
72
70
|
return $context->format(
|
|
73
71
|
"if (%node) %line %raw\n",
|
|
74
72
|
$this->condition,
|
|
75
73
|
$this->position,
|
|
76
|
-
$
|
|
74
|
+
match ($this->type) {
|
|
75
|
+
'breakIf' => 'break;',
|
|
76
|
+
'continueIf' => 'continue;',
|
|
77
|
+
'skipIf' => '{ $iterator->skipRound(); continue; }',
|
|
78
|
+
'exitIf' => 'return;',
|
|
79
|
+
},
|
|
77
80
|
);
|
|
78
81
|
}
|
|
79
82
|
|
|
@@ -0,0 +1,88 @@
|
|
|
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\Nodes;
|
|
11
|
+
|
|
12
|
+
use Latte\CompileException;
|
|
13
|
+
use Latte\Compiler\Node;
|
|
14
|
+
use Latte\Compiler\Nodes;
|
|
15
|
+
use Latte\Compiler\Nodes\AreaNode;
|
|
16
|
+
use Latte\Compiler\Nodes\StatementNode;
|
|
17
|
+
use Latte\Compiler\NodeTraverser;
|
|
18
|
+
use Latte\Compiler\PrintContext;
|
|
19
|
+
use Latte\Compiler\Tag;
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* n:else
|
|
24
|
+
*/
|
|
25
|
+
final class NElseNode extends StatementNode
|
|
26
|
+
{
|
|
27
|
+
public AreaNode $content;
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
|
|
31
|
+
public static function create(Tag $tag): \Generator
|
|
32
|
+
{
|
|
33
|
+
$node = $tag->node = new static;
|
|
34
|
+
[$node->content] = yield;
|
|
35
|
+
return $node;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
public function print(PrintContext $context): string
|
|
40
|
+
{
|
|
41
|
+
throw new \LogicException('Cannot directly print');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
public function &getIterator(): \Generator
|
|
46
|
+
{
|
|
47
|
+
yield $this->content;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
public static function processPass(Node $node): void
|
|
52
|
+
{
|
|
53
|
+
(new NodeTraverser)->traverse($node, function (Node $node) {
|
|
54
|
+
if ($node instanceof Nodes\FragmentNode) {
|
|
55
|
+
for ($i = count($node->children) - 1; $i >= 0; $i--) {
|
|
56
|
+
$nElse = $node->children[$i];
|
|
57
|
+
if (!$nElse instanceof self) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
array_splice($node->children, $i, 1);
|
|
62
|
+
$prev = $node->children[--$i] ?? null;
|
|
63
|
+
if ($prev instanceof Nodes\TextNode && trim($prev->content) === '') {
|
|
64
|
+
array_splice($node->children, $i, 1);
|
|
65
|
+
$prev = $node->children[--$i] ?? null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (
|
|
69
|
+
$prev instanceof IfNode
|
|
70
|
+
|| $prev instanceof ForeachNode
|
|
71
|
+
|| $prev instanceof TryNode
|
|
72
|
+
|| $prev instanceof IfChangedNode
|
|
73
|
+
|| $prev instanceof IfContentNode
|
|
74
|
+
) {
|
|
75
|
+
if ($prev->else) {
|
|
76
|
+
throw new CompileException('Multiple "else" found.', $nElse->position);
|
|
77
|
+
}
|
|
78
|
+
$prev->else = $nElse->content;
|
|
79
|
+
} else {
|
|
80
|
+
throw new CompileException('n:else must be immediately after n:if, n:foreach etc', $nElse->position);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} elseif ($node instanceof self) {
|
|
84
|
+
throw new CompileException('n:else must be immediately after n:if, n:foreach etc', $node->position);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|