@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
|
@@ -10,10 +10,16 @@ declare(strict_types=1);
|
|
|
10
10
|
namespace Latte\Essential\Nodes;
|
|
11
11
|
|
|
12
12
|
use Latte\CompileException;
|
|
13
|
+
use Latte\Compiler\Node;
|
|
13
14
|
use Latte\Compiler\Nodes\AreaNode;
|
|
15
|
+
use Latte\Compiler\Nodes\AuxiliaryNode;
|
|
14
16
|
use Latte\Compiler\Nodes\NopNode;
|
|
17
|
+
use Latte\Compiler\Nodes\Php\Expression\VariableNode;
|
|
15
18
|
use Latte\Compiler\Nodes\Php\ExpressionNode;
|
|
19
|
+
use Latte\Compiler\Nodes\Php\ListNode;
|
|
16
20
|
use Latte\Compiler\Nodes\StatementNode;
|
|
21
|
+
use Latte\Compiler\Nodes\TemplateNode;
|
|
22
|
+
use Latte\Compiler\NodeTraverser;
|
|
17
23
|
use Latte\Compiler\Position;
|
|
18
24
|
use Latte\Compiler\PrintContext;
|
|
19
25
|
use Latte\Compiler\Tag;
|
|
@@ -28,7 +34,7 @@ class ForeachNode extends StatementNode
|
|
|
28
34
|
public ExpressionNode $expression;
|
|
29
35
|
public ?ExpressionNode $key = null;
|
|
30
36
|
public bool $byRef = false;
|
|
31
|
-
public ExpressionNode $value;
|
|
37
|
+
public ExpressionNode|ListNode $value;
|
|
32
38
|
public AreaNode $content;
|
|
33
39
|
public ?AreaNode $else = null;
|
|
34
40
|
public ?Position $elseLine = null;
|
|
@@ -40,9 +46,8 @@ class ForeachNode extends StatementNode
|
|
|
40
46
|
public static function create(Tag $tag): \Generator
|
|
41
47
|
{
|
|
42
48
|
$tag->expectArguments();
|
|
43
|
-
$node = new static;
|
|
49
|
+
$node = $tag->node = new static;
|
|
44
50
|
self::parseArguments($tag->parser, $node);
|
|
45
|
-
$tag->data->iterateWhile = [$node->key, $node->value];
|
|
46
51
|
|
|
47
52
|
$modifier = $tag->parser->parseModifier();
|
|
48
53
|
foreach ($modifier->filters as $filter) {
|
|
@@ -73,16 +78,7 @@ class ForeachNode extends StatementNode
|
|
|
73
78
|
$stream = $parser->stream;
|
|
74
79
|
$node->expression = $parser->parseExpression();
|
|
75
80
|
$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();
|
|
81
|
+
[$node->key, $node->value, $node->byRef] = $parser->parseForeach();
|
|
86
82
|
}
|
|
87
83
|
|
|
88
84
|
|
|
@@ -152,4 +148,35 @@ class ForeachNode extends StatementNode
|
|
|
152
148
|
yield $this->else;
|
|
153
149
|
}
|
|
154
150
|
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Pass: checks if foreach overrides template variables.
|
|
155
|
+
*/
|
|
156
|
+
public static function overwrittenVariablesPass(TemplateNode $node): void
|
|
157
|
+
{
|
|
158
|
+
$vars = [];
|
|
159
|
+
(new NodeTraverser)->traverse($node, function (Node $node) use (&$vars) {
|
|
160
|
+
if ($node instanceof self && $node->checkArgs) {
|
|
161
|
+
foreach ([$node->key, $node->value] as $var) {
|
|
162
|
+
if ($var instanceof VariableNode) {
|
|
163
|
+
$vars[$var->name][] = $node->position->line;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
if ($vars) {
|
|
169
|
+
array_unshift($node->head->children, new AuxiliaryNode(fn(PrintContext $context) => $context->format(
|
|
170
|
+
<<<'XX'
|
|
171
|
+
if (!$this->getReferringTemplate() || $this->getReferenceType() === 'extends') {
|
|
172
|
+
foreach (array_intersect_key(%dump, $this->params) as $ʟ_v => $ʟ_l) {
|
|
173
|
+
trigger_error("Variable \$$ʟ_v overwritten in foreach on line $ʟ_l");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
XX,
|
|
178
|
+
array_map(fn($l) => implode(', ', $l), $vars),
|
|
179
|
+
)));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
155
182
|
}
|
|
@@ -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
|
+
}
|
|
@@ -11,10 +11,12 @@ namespace Latte\Essential\Nodes;
|
|
|
11
11
|
|
|
12
12
|
use Latte;
|
|
13
13
|
use Latte\CompileException;
|
|
14
|
-
use Latte\Compiler\Nodes\Php\
|
|
14
|
+
use Latte\Compiler\Nodes\Php\Expression\AuxiliaryNode;
|
|
15
15
|
use Latte\Compiler\Nodes\StatementNode;
|
|
16
16
|
use Latte\Compiler\PrintContext;
|
|
17
17
|
use Latte\Compiler\Tag;
|
|
18
|
+
use Latte\Compiler\TemplateParser;
|
|
19
|
+
use Latte\ContentType;
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
/**
|
|
@@ -22,50 +24,40 @@ use Latte\Compiler\Tag;
|
|
|
22
24
|
*/
|
|
23
25
|
final class NTagNode extends StatementNode
|
|
24
26
|
{
|
|
25
|
-
public
|
|
26
|
-
public string $origName;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
public static function create(Tag $tag): void
|
|
27
|
+
public static function create(Tag $tag, TemplateParser $parser): void
|
|
30
28
|
{
|
|
31
29
|
if (preg_match('(style$|script$)iA', $tag->htmlElement->name)) {
|
|
32
30
|
throw new CompileException('Attribute n:tag is not allowed in <script> or <style>', $tag->position);
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
$tag->expectArguments();
|
|
36
|
-
$
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
$tag->htmlElement->variableName = new AuxiliaryNode(
|
|
35
|
+
fn(PrintContext $context, $newName) => $context->format(
|
|
36
|
+
self::class . '::check(%dump, %node, %dump)',
|
|
37
|
+
$tag->htmlElement->name,
|
|
38
|
+
$newName,
|
|
39
|
+
$parser->getContentType() === ContentType::Xml,
|
|
40
|
+
),
|
|
41
|
+
[$tag->parser->parseExpression()],
|
|
42
|
+
);
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
|
|
43
46
|
public function print(PrintContext $context): string
|
|
44
47
|
{
|
|
45
|
-
|
|
46
|
-
. var_export($this->origName, true)
|
|
47
|
-
. ', '
|
|
48
|
-
. $this->name->print($context)
|
|
49
|
-
. ')';
|
|
48
|
+
throw new \LogicException('Cannot directly print');
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
|
|
53
|
-
public static function check(string $orig, $new):
|
|
52
|
+
public static function check(string $orig, mixed $new, bool $xml): mixed
|
|
54
53
|
{
|
|
55
54
|
if ($new === null) {
|
|
56
55
|
return $orig;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|| !preg_match('~' . Latte\Compiler\TemplateLexer::ReTagName . '$~DA', $new)
|
|
61
|
-
) {
|
|
62
|
-
throw new Latte\RuntimeException('Invalid tag name ' . var_export($new, true));
|
|
63
|
-
|
|
64
|
-
} elseif (
|
|
65
|
-
in_array($lower = strtolower($new), ['style', 'script'], true)
|
|
66
|
-
|| isset(Latte\Helpers::$emptyElements[strtolower($orig)]) !== isset(Latte\Helpers::$emptyElements[$lower])
|
|
56
|
+
} elseif (!$xml
|
|
57
|
+
&& is_string($new)
|
|
58
|
+
&& isset(Latte\Helpers::$emptyElements[strtolower($orig)]) !== isset(Latte\Helpers::$emptyElements[strtolower($new)])
|
|
67
59
|
) {
|
|
68
|
-
throw new Latte\RuntimeException("Forbidden tag <$orig> change to <$new
|
|
60
|
+
throw new Latte\RuntimeException("Forbidden tag <$orig> change to <$new>");
|
|
69
61
|
}
|
|
70
62
|
|
|
71
63
|
return $new;
|
|
@@ -74,6 +66,6 @@ final class NTagNode extends StatementNode
|
|
|
74
66
|
|
|
75
67
|
public function &getIterator(): \Generator
|
|
76
68
|
{
|
|
77
|
-
yield
|
|
69
|
+
false && yield;
|
|
78
70
|
}
|
|
79
71
|
}
|
|
@@ -16,7 +16,6 @@ use Latte\Compiler\Nodes\StatementNode;
|
|
|
16
16
|
use Latte\Compiler\PrintContext;
|
|
17
17
|
use Latte\Compiler\Tag;
|
|
18
18
|
use Latte\Compiler\TemplateParser;
|
|
19
|
-
use Latte\ContentType;
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
/**
|
|
@@ -26,24 +25,17 @@ class PrintNode extends StatementNode
|
|
|
26
25
|
{
|
|
27
26
|
public ExpressionNode $expression;
|
|
28
27
|
public ModifierNode $modifier;
|
|
28
|
+
private ?string $followsQuote = null;
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
public static function create(Tag $tag, TemplateParser $parser): static
|
|
32
32
|
{
|
|
33
33
|
$tag->outputMode = $tag::OutputKeepIndentation;
|
|
34
|
-
|
|
35
|
-
$stream = $parser->getStream();
|
|
36
|
-
if (
|
|
37
|
-
$tag->isInText()
|
|
38
|
-
&& $parser->getContentType() === ContentType::Html
|
|
39
|
-
&& $tag->htmlElement?->name === 'script'
|
|
40
|
-
&& preg_match('#["\']#A', $stream->peek()->text)
|
|
41
|
-
) {
|
|
42
|
-
throw new CompileException("Do not place {$tag->getNotation(true)} inside quotes in JavaScript.", $tag->position);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
34
|
$tag->expectArguments();
|
|
46
35
|
$node = new static;
|
|
36
|
+
$node->followsQuote = preg_match('#["\']#A', $parser->getStream()->peek()->text)
|
|
37
|
+
? $tag->getNotation(true)
|
|
38
|
+
: null;
|
|
47
39
|
$node->expression = $tag->parser->parseExpression();
|
|
48
40
|
$node->modifier = $tag->parser->parseModifier();
|
|
49
41
|
$node->modifier->escape = true;
|
|
@@ -53,6 +45,9 @@ class PrintNode extends StatementNode
|
|
|
53
45
|
|
|
54
46
|
public function print(PrintContext $context): string
|
|
55
47
|
{
|
|
48
|
+
if ($this->followsQuote && $context->getEscaper()->export() === 'html/raw/js') {
|
|
49
|
+
throw new CompileException("Do not place {$this->followsQuote} inside quotes in JavaScript.", $this->position);
|
|
50
|
+
}
|
|
56
51
|
return $context->format(
|
|
57
52
|
"echo %modify(%node) %line;\n",
|
|
58
53
|
$this->modifier,
|
|
@@ -22,7 +22,7 @@ class RollbackNode extends StatementNode
|
|
|
22
22
|
{
|
|
23
23
|
public static function create(Tag $tag): static
|
|
24
24
|
{
|
|
25
|
-
if (!$tag->closestTag([
|
|
25
|
+
if (!$tag->closestTag([TryNode::class])) {
|
|
26
26
|
throw new CompileException('Tag {rollback} must be inside {try} ... {/try}.', $tag->position);
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -27,7 +27,7 @@ class SpacelessNode extends StatementNode
|
|
|
27
27
|
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
|
|
28
28
|
public static function create(Tag $tag): \Generator
|
|
29
29
|
{
|
|
30
|
-
$node = new static;
|
|
30
|
+
$node = $tag->node = new static;
|
|
31
31
|
[$node->content] = yield;
|
|
32
32
|
return $node;
|
|
33
33
|
}
|
|
@@ -37,7 +37,7 @@ class SwitchNode extends StatementNode
|
|
|
37
37
|
throw new CompileException('Attribute n:switch is not supported.', $tag->position);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
$node = new static;
|
|
40
|
+
$node = $tag->node = new static;
|
|
41
41
|
$node->expression = $tag->parser->isEnd()
|
|
42
42
|
? null
|
|
43
43
|
: $tag->parser->parseExpression();
|
|
@@ -9,15 +9,17 @@ declare(strict_types=1);
|
|
|
9
9
|
|
|
10
10
|
namespace Latte\Essential\Nodes;
|
|
11
11
|
|
|
12
|
+
use Latte\Compiler\Node;
|
|
13
|
+
use Latte\Compiler\Nodes;
|
|
12
14
|
use Latte\Compiler\Nodes\StatementNode;
|
|
13
|
-
use Latte\Compiler\
|
|
15
|
+
use Latte\Compiler\NodeTraverser;
|
|
14
16
|
use Latte\Compiler\PrintContext;
|
|
15
17
|
use Latte\Compiler\Tag;
|
|
16
18
|
use Latte\Compiler\Token;
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
|
-
* {templatePrint [
|
|
22
|
+
* {templatePrint [ParentClass]}
|
|
21
23
|
*/
|
|
22
24
|
class TemplatePrintNode extends StatementNode
|
|
23
25
|
{
|
|
@@ -34,7 +36,13 @@ class TemplatePrintNode extends StatementNode
|
|
|
34
36
|
|
|
35
37
|
public function print(PrintContext $context): string
|
|
36
38
|
{
|
|
37
|
-
return
|
|
39
|
+
return $context->format(<<<'XX'
|
|
40
|
+
$ʟ_bp = new Latte\Essential\Blueprint;
|
|
41
|
+
$ʟ_bp->printBegin();
|
|
42
|
+
$ʟ_bp->printClass($ʟ_bp->generateTemplateClass($this->getParameters(), extends: %dump));
|
|
43
|
+
$ʟ_bp->printEnd();
|
|
44
|
+
exit;
|
|
45
|
+
XX, $this->template);
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
|
|
@@ -42,4 +50,18 @@ class TemplatePrintNode extends StatementNode
|
|
|
42
50
|
{
|
|
43
51
|
false && yield;
|
|
44
52
|
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Pass: moves this node to head.
|
|
57
|
+
*/
|
|
58
|
+
public static function moveToHeadPass(Nodes\TemplateNode $templateNode): void
|
|
59
|
+
{
|
|
60
|
+
(new NodeTraverser)->traverse($templateNode->main, function (Node $node) use ($templateNode) {
|
|
61
|
+
if ($node instanceof self) {
|
|
62
|
+
array_unshift($templateNode->head->children, $node);
|
|
63
|
+
return new Nodes\NopNode;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
45
67
|
}
|
|
@@ -35,7 +35,7 @@ class TranslateNode extends StatementNode
|
|
|
35
35
|
{
|
|
36
36
|
$tag->outputMode = $tag::OutputKeepIndentation;
|
|
37
37
|
|
|
38
|
-
$node = new static;
|
|
38
|
+
$node = $tag->node = new static;
|
|
39
39
|
$args = $tag->parser->parseArguments();
|
|
40
40
|
$node->modifier = $tag->parser->parseModifier();
|
|
41
41
|
$node->modifier->escape = true;
|
|
@@ -25,9 +25,9 @@ class TryNode extends StatementNode
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
|
|
28
|
-
public static function create(): \Generator
|
|
28
|
+
public static function create(Tag $tag): \Generator
|
|
29
29
|
{
|
|
30
|
-
$node = new static;
|
|
30
|
+
$node = $tag->node = new static;
|
|
31
31
|
[$node->try, $nextTag] = yield ['else'];
|
|
32
32
|
if ($nextTag?->name === 'else') {
|
|
33
33
|
[$node->else] = yield;
|
|
@@ -46,12 +46,11 @@ class TryNode extends StatementNode
|
|
|
46
46
|
try %line {
|
|
47
47
|
%node
|
|
48
48
|
} catch (Throwable $ʟ_e) {
|
|
49
|
-
|
|
49
|
+
ob_clean();
|
|
50
50
|
if (!($ʟ_e instanceof Latte\Essential\RollbackException) && isset($this->global->coreExceptionHandler)) {
|
|
51
51
|
($this->global->coreExceptionHandler)($ʟ_e, $this);
|
|
52
52
|
}
|
|
53
53
|
%node
|
|
54
|
-
ob_start();
|
|
55
54
|
} finally {
|
|
56
55
|
echo ob_get_clean();
|
|
57
56
|
$iterator = $ʟ_it = $ʟ_try[%0.dump][0];
|
|
@@ -33,9 +33,16 @@ class VarPrintNode extends StatementNode
|
|
|
33
33
|
|
|
34
34
|
public function print(PrintContext $context): string
|
|
35
35
|
{
|
|
36
|
-
$vars = $this->all
|
|
36
|
+
$vars = $this->all
|
|
37
|
+
? 'get_defined_vars()'
|
|
37
38
|
: 'array_diff_key(get_defined_vars(), $this->getParameters())';
|
|
38
|
-
return
|
|
39
|
+
return <<<XX
|
|
40
|
+
\$ʟ_bp = new Latte\\Essential\\Blueprint;
|
|
41
|
+
\$ʟ_bp->printBegin();
|
|
42
|
+
\$ʟ_bp->printVars($vars);
|
|
43
|
+
\$ʟ_bp->printEnd();
|
|
44
|
+
exit;
|
|
45
|
+
XX;
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
|
|
@@ -29,7 +29,7 @@ class WhileNode extends StatementNode
|
|
|
29
29
|
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
|
|
30
30
|
public static function create(Tag $tag): \Generator
|
|
31
31
|
{
|
|
32
|
-
$node = new static;
|
|
32
|
+
$node = $tag->node = new static;
|
|
33
33
|
$node->postTest = $tag->parser->isEnd();
|
|
34
34
|
if (!$node->postTest) {
|
|
35
35
|
$node->condition = $tag->parser->parseExpression();
|