diff --git a/phpstan.neon b/phpstan.neon
index 7013f6993..5db9012da 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,4 +1,8 @@
parameters:
+ excludePaths:
+ analyse:
+ - src/Latte/Compiler/TagParser.php
+
level: 5
paths:
diff --git a/src/Latte/Compiler/Block.php b/src/Latte/Compiler/Block.php
index 6dc9a61cb..39995882d 100644
--- a/src/Latte/Compiler/Block.php
+++ b/src/Latte/Compiler/Block.php
@@ -26,6 +26,7 @@ final class Block
/** @var ParameterNode[] */
public array $parameters = [];
+ public VariableScope $variables;
public function __construct(
diff --git a/src/Latte/Compiler/PrintContext.php b/src/Latte/Compiler/PrintContext.php
index e204f72ae..e5001b762 100644
--- a/src/Latte/Compiler/PrintContext.php
+++ b/src/Latte/Compiler/PrintContext.php
@@ -77,10 +77,14 @@ final class PrintContext
/** @var Escaper[] */
private array $escaperStack = [];
+ /** @var VariableScope[] */
+ private array $scopeStack = [];
+
public function __construct(string $contentType = ContentType::Html)
{
$this->escaperStack[] = new Escaper($contentType);
+ $this->scopeStack[] = new VariableScope;
}
@@ -160,9 +164,28 @@ public function getEscaper(): Escaper
}
+ public function beginVariableScope(): VariableScope
+ {
+ return $this->scopeStack[] = clone end($this->scopeStack);
+ }
+
+
+ public function restoreVariableScope(): void
+ {
+ array_pop($this->scopeStack);
+ }
+
+
+ public function getVariableScope(): VariableScope
+ {
+ return end($this->scopeStack);
+ }
+
+
public function addBlock(Block $block): void
{
$block->escaping = $this->getEscaper()->export();
+ $block->variables = clone $this->getVariableScope();
$block->method = 'block' . ucfirst(trim(preg_replace('#\W+#', '_', $block->name->print($this)), '_'));
$lower = strtolower($block->method);
$used = $this->blocks + ['block' => 1];
diff --git a/src/Latte/Compiler/TemplateGenerator.php b/src/Latte/Compiler/TemplateGenerator.php
index 11a319fa6..ae5e29b77 100644
--- a/src/Latte/Compiler/TemplateGenerator.php
+++ b/src/Latte/Compiler/TemplateGenerator.php
@@ -11,6 +11,8 @@
use Latte;
use Latte\ContentType;
+use Latte\Essential\Blueprint;
+use Nette\PhpGenerator as Php;
/**
@@ -38,20 +40,24 @@ public function generate(
string $className,
?string $comment = null,
bool $strictMode = false,
+ array $filters = [],
): string {
$context = new PrintContext($node->contentType);
- $code = $node->main->print($context);
- $code = self::buildParams($code, [], '$ʟ_args', $context);
- $this->addMethod('main', $code, 'array $ʟ_args');
+ $scope = $context->getVariableScope();
+ $this->addMethod('main', '');
$head = (new NodeTraverser)->traverse($node->head, fn(Node $node) => $node instanceof Nodes\TextNode ? new Nodes\NopNode : $node);
$code = $head->print($context);
if ($code || $context->paramsExtraction) {
$code .= 'return get_defined_vars();';
- $code = self::buildParams($code, $context->paramsExtraction, '$this->params', $context);
+ $code = self::buildParams($code, $context->paramsExtraction, '$this->params', $context, $scope);
$this->addMethod('prepare', $code, '', 'array');
}
+ $code = $node->main->print($context);
+ $code = self::buildParams($code, [], '$ʟ_args', $context, $context->getVariableScope());
+ $this->addMethod('main', $code, 'array $ʟ_args');
+
if ($node->contentType !== ContentType::Html) {
$this->addConstant('ContentType', $node->contentType);
}
@@ -75,13 +81,18 @@ public function generate(
. ($method['body'] ? "\t\t$method[body]\n" : '') . "\t}";
}
+ $comment .= "\n@property Filters$className \$filters";
+ $comment = str_replace('*/', '* /', $comment);
+ $comment = str_replace("\n", "\n * ", "/**\n" . trim($comment)) . "\n */\n";
+
$code = "generateStub($node, 'Filters' . $className, $filters);
$code = PhpHelpers::optimizeEcho($code);
$code = PhpHelpers::reformatCode($code);
@@ -100,10 +111,21 @@ private function generateBlocks(array $blocks, PrintContext $context): void
: [$block->method, $block->escaping];
}
- $body = $this->buildParams($block->content, $block->parameters, '$ʟ_args', $context);
+ $body = self::buildParams($block->content, $block->parameters, '$ʟ_args', $context, $block->variables);
if (!$block->isDynamic() && str_contains($body, '$')) {
$embedded = $block->tag->name === 'block' && is_int($block->layer) && $block->layer;
- $body = 'extract(' . ($embedded ? 'end($this->varStack)' : '$this->params') . ');' . $body;
+ if($context->paramsExtraction) {
+ $paramTypes = '';
+ foreach ($context->paramsExtraction as $param) {
+ $paramTypes .= $param->type ?
+ VariableScope::printComment($param->var->name, $param->type->type) . "\n" :
+ '';
+ }
+ $body = 'extract($this->prepare());' . "\n" . $paramTypes . $body;
+ } else {
+ $body = 'extract(' . ($embedded ? 'end($this->varStack)' : '$this->params') . ');' . $body;
+ }
+
}
$this->addMethod(
@@ -121,8 +143,49 @@ private function generateBlocks(array $blocks, PrintContext $context): void
}
- private function buildParams(string $body, array $params, string $cont, PrintContext $context): string
+ private function generateStub(Node $node, string $className, $filters): string
{
+ if (!class_exists(Php\ClassType::class)) {
+ return '';
+ }
+
+ $used = [];
+ (new NodeTraverser)->traverse($node, function (Node $node) use (&$used) {
+ if ($node instanceof Nodes\Php\FilterNode) {
+ $used[$node->name->name] = true;
+ }
+ });
+
+ $class = new Php\ClassType($className);
+ $filters = array_intersect_key($filters, $used);
+ foreach ($filters as $name => $callback) {
+ $func = (new Php\Factory)->fromCallable($callback);
+ $type = Blueprint::printType($func->getReturnType(), $func->isReturnNullable(), null) ?: 'mixed';
+ $params = [];
+ $list = $func->getParameters();
+ foreach ($list as $param) {
+ $variadic = $func->isVariadic() && $param === end($list);
+ $params[] = (Blueprint::printType($param->getType(), $param->isNullable(), null) ?: 'mixed')
+ . ($variadic ? '...' : '');
+ }
+
+ $class->addComment('@property callable(' . implode(', ', $params) . "): $type \$$name");
+ }
+
+ return (string) $class;
+ }
+
+
+ /**
+ * @param Nodes\Php\ParameterNode[] $params
+ */
+ private static function buildParams(
+ string $body,
+ array $params,
+ string $cont,
+ PrintContext $context,
+ VariableScope $scope,
+ ): string {
if (!str_contains($body, '$') && !str_contains($body, 'get_defined_vars()')) {
return $body;
}
@@ -130,7 +193,8 @@ private function buildParams(string $body, array $params, string $cont, PrintCon
$res = [];
foreach ($params as $i => $param) {
$res[] = $context->format(
- '%node = %raw[%dump] ?? %raw[%dump] ?? %node;',
+ '%raw%node = %raw[%dump] ?? %raw[%dump] ?? %node;',
+ $param->type ? VariableScope::printComment($param->var->name, $param->type->type) . ' ' : '',
$param->var,
$cont,
$i,
@@ -140,10 +204,12 @@ private function buildParams(string $body, array $params, string $cont, PrintCon
);
}
- $extract = $params
- ? implode('', $res) . 'unset($ʟ_args);'
- : "extract($cont);" . (str_contains($cont, '$this') ? '' : "unset($cont);");
- return $extract . "\n\n" . $body;
+ $extract = $params ? implode('', $res) : "extract($cont);";
+ $extract .= (str_contains($cont, '$this') ? '' : "unset($cont);");
+
+ return $extract
+ . $scope->extractTypes() . "\n\n"
+ . $body;
}
diff --git a/src/Latte/Compiler/VariableScope.php b/src/Latte/Compiler/VariableScope.php
new file mode 100644
index 000000000..a6c1fd84c
--- /dev/null
+++ b/src/Latte/Compiler/VariableScope.php
@@ -0,0 +1,51 @@
+types[$name] = $this->printComment($name, $type);
+ }
+
+
+ public function addExpression(Nodes\Php\ExpressionNode $expr, ?Nodes\Php\SuperiorTypeNode $type): string
+ {
+ return $expr instanceof Nodes\Php\Expression\VariableNode && is_string($expr->name)
+ ? $this->addVariable($expr->name, $type?->type)
+ : '';
+ }
+
+
+ public static function printComment(string $name, ?string $type): string
+ {
+ if (!$type) {
+ return '';
+ }
+ $str = '@var ' . $type . ' $' . $name;
+ return '/** ' . str_replace('*/', '* /', $str) . ' */';
+ }
+
+
+ public function extractTypes(): string
+ {
+ return implode("\n", array_filter($this->types));
+ }
+}
diff --git a/src/Latte/Engine.php b/src/Latte/Engine.php
index af8621efd..f04b43132 100644
--- a/src/Latte/Engine.php
+++ b/src/Latte/Engine.php
@@ -191,6 +191,7 @@ public function generate(TemplateNode $node, string $name): string
$this->getTemplateClass($name),
$comment,
$this->strictTypes,
+ $this->getFilters(),
);
}
diff --git a/src/Latte/Essential/Blueprint.php b/src/Latte/Essential/Blueprint.php
index 51622e7a0..19914417b 100644
--- a/src/Latte/Essential/Blueprint.php
+++ b/src/Latte/Essential/Blueprint.php
@@ -95,7 +95,7 @@ public function addFunctions(Php\ClassType $class, array $funcs): void
}
- private function printType(?string $type, bool $nullable, ?Php\PhpNamespace $namespace): string
+ public static function printType(?string $type, bool $nullable, ?Php\PhpNamespace $namespace): string
{
if ($type === null) {
return '';
@@ -123,7 +123,7 @@ public function printParameters(
$list = $function->getParameters();
foreach ($list as $param) {
$variadic = $function->isVariadic() && $param === end($list);
- $params[] = ltrim($this->printType($param->getType(), $param->isNullable(), $namespace) . ' ')
+ $params[] = ltrim(self::printType($param->getType(), $param->isNullable(), $namespace) . ' ')
. ($param->isReference() ? '&' : '')
. ($variadic ? '...' : '')
. '$' . $param->getName()
diff --git a/src/Latte/Essential/Nodes/BlockNode.php b/src/Latte/Essential/Nodes/BlockNode.php
index d1a982cc3..acfea4c43 100644
--- a/src/Latte/Essential/Nodes/BlockNode.php
+++ b/src/Latte/Essential/Nodes/BlockNode.php
@@ -74,14 +74,20 @@ public static function create(Tag $tag, TemplateParser $parser): \Generator
public function print(PrintContext $context): string
{
- if (!$this->block) {
- return $this->printFilter($context);
+ $context->beginVariableScope();
+ try {
+ if (!$this->block) {
+ return $this->printFilter($context);
- } elseif ($this->block->isDynamic()) {
- return $this->printDynamic($context);
- }
+ } elseif ($this->block->isDynamic()) {
+ return $this->printDynamic($context);
- return $this->printStatic($context);
+ } else {
+ return $this->printStatic($context);
+ }
+ } finally {
+ $context->restoreVariableScope();
+ }
}
@@ -91,7 +97,9 @@ private function printFilter(PrintContext $context): string
<<<'XX'
ob_start(fn() => '') %line;
try {
- (function () { extract(func_get_arg(0));
+ (function () {
+ extract(func_get_arg(0));
+ %raw
%node
})(get_defined_vars());
} finally {
@@ -101,6 +109,7 @@ private function printFilter(PrintContext $context): string
XX,
$this->position,
+ $context->getVariableScope()->extractTypes(),
$this->content,
$context->getEscaper()->export(),
$this->modifier,
diff --git a/src/Latte/Essential/Nodes/ForeachNode.php b/src/Latte/Essential/Nodes/ForeachNode.php
index 338a89646..b3c3f888e 100644
--- a/src/Latte/Essential/Nodes/ForeachNode.php
+++ b/src/Latte/Essential/Nodes/ForeachNode.php
@@ -88,6 +88,12 @@ private static function parseArguments(TagParser $parser, self $node): void
public function print(PrintContext $context): string
{
+ $scope = $context->getVariableScope();
+ if ($this->key) {
+ $scope->addExpression($this->key, null);
+ }
+ $scope->addExpression($this->value, null);
+
$content = $this->content->print($context);
$iterator = $this->else || ($this->iterator ?? preg_match('#\$iterator\W|\Wget_defined_vars\W#', $content));
diff --git a/src/Latte/Essential/Nodes/TemplateTypeNode.php b/src/Latte/Essential/Nodes/TemplateTypeNode.php
index aa3fb4678..03298864b 100644
--- a/src/Latte/Essential/Nodes/TemplateTypeNode.php
+++ b/src/Latte/Essential/Nodes/TemplateTypeNode.php
@@ -13,6 +13,7 @@
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;
+use Latte\Compiler\Token;
/**
@@ -20,19 +21,42 @@
*/
class TemplateTypeNode extends StatementNode
{
+ public string $class;
+
+
public static function create(Tag $tag): static
{
if (!$tag->isInHead()) {
throw new CompileException('{templateType} is allowed only in template header.', $tag->position);
}
$tag->expectArguments('class name');
- $tag->parser->parseExpression();
- return new static;
+ $token = $tag->parser->stream->consume(Token::Php_Identifier, Token::Php_NameQualified, Token::Php_NameFullyQualified);
+ if (!class_exists($token->text)) {
+ throw new CompileException("Class '$token->text' used in {templateType} doesn't exist.", $token->position);
+ }
+
+ $node = new static;
+ $node->class = $token->text;
+ return $node;
}
public function print(PrintContext $context): string
{
+ $scope = $context->getVariableScope();
+ $rc = new \ReflectionClass($this->class);
+ foreach ($rc->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
+ $type = $this->parseAnnotation($property->getDocComment() ?: '') ?: (string) $property->getType();
+ $scope->addVariable($property->getName(), $type);
+ }
+
return '';
}
+
+
+ private function parseAnnotation(string $comment): ?string
+ {
+ $comment = trim($comment, '/*');
+ return preg_match('#@var ([^$]+)#', $comment, $m) ? trim($m[1]) : null;
+ }
}
diff --git a/src/Latte/Essential/Nodes/VarNode.php b/src/Latte/Essential/Nodes/VarNode.php
index c3eea61f3..3d7513002 100644
--- a/src/Latte/Essential/Nodes/VarNode.php
+++ b/src/Latte/Essential/Nodes/VarNode.php
@@ -13,10 +13,12 @@
use Latte\Compiler\Nodes\Php\Expression\VariableNode;
use Latte\Compiler\Nodes\Php\ExpressionNode;
use Latte\Compiler\Nodes\Php\Scalar\NullNode;
+use Latte\Compiler\Nodes\Php\SuperiorTypeNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;
use Latte\Compiler\Token;
+use Latte\Compiler\VariableScope;
/**
@@ -27,7 +29,7 @@ class VarNode extends StatementNode
{
public bool $default;
- /** @var AssignNode[] */
+ /** @var array{AssignNode, ?SuperiorTypeNode}[] */
public array $assignments = [];
@@ -46,14 +48,14 @@ private static function parseAssignments(Tag $tag, bool $default): array
$stream = $tag->parser->stream;
$res = [];
do {
- $tag->parser->parseType();
+ $type = $tag->parser->parseType();
$save = $stream->getIndex();
$expr = $stream->is(Token::Php_Variable) ? $tag->parser->parseExpression() : null;
if ($expr instanceof VariableNode) {
- $res[] = new AssignNode($expr, new NullNode);
+ $res[] = [new AssignNode($expr, new NullNode), $type];
} elseif ($expr instanceof AssignNode && (!$default || $expr->var instanceof VariableNode)) {
- $res[] = $expr;
+ $res[] = [$expr, $type];
} else {
$stream->seek($save);
$stream->throwUnexpectedException(addendum: ' in ' . $tag->getNotation());
@@ -66,27 +68,29 @@ private static function parseAssignments(Tag $tag, bool $default): array
public function print(PrintContext $context): string
{
- $res = [];
+ $scope = $context->getVariableScope();
+ $res = $types = [];
+
if ($this->default) {
- foreach ($this->assignments as $assign) {
- assert($assign->var instanceof VariableNode);
- if ($assign->var->name instanceof ExpressionNode) {
- $var = $assign->var->name->print($context);
- } else {
- $var = $context->encodeString($assign->var->name);
- }
+ foreach ($this->assignments as [$assign, $type]) {
+ $var = $assign->var->name instanceof ExpressionNode
+ ? $assign->var->name->print($context)
+ : $context->encodeString($assign->var->name);
$res[] = $var . ' => ' . $assign->expr->print($context);
+ $types[] = VariableScope::printComment($var, $type?->type);
}
return $context->format(
- 'extract([%raw], EXTR_SKIP) %line;',
+ 'extract([%raw], EXTR_SKIP) %line;%raw ',
implode(', ', $res),
$this->position,
+ implode('', $types),
);
}
- foreach ($this->assignments as $assign) {
- $res[] = $assign->print($context);
+ foreach ($this->assignments as [$assign, $type]) {
+ $comment = $scope->addExpression($assign->var, $type);
+ $res[] = $comment . $assign->print($context);
}
return $context->format(
@@ -99,8 +103,11 @@ public function print(PrintContext $context): string
public function &getIterator(): \Generator
{
- foreach ($this->assignments as &$assign) {
+ foreach ($this->assignments as [&$assign, &$type]) {
yield $assign;
+ if ($type) {
+ yield $type;
+ }
}
}
}
diff --git a/src/Latte/Essential/Nodes/VarTypeNode.php b/src/Latte/Essential/Nodes/VarTypeNode.php
index 2585a513b..839c75139 100644
--- a/src/Latte/Essential/Nodes/VarTypeNode.php
+++ b/src/Latte/Essential/Nodes/VarTypeNode.php
@@ -9,10 +9,13 @@
namespace Latte\Essential\Nodes;
+use Latte\Compiler\Nodes\Php\Expression\VariableNode;
+use Latte\Compiler\Nodes\Php\SuperiorTypeNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;
use Latte\Compiler\Token;
+use Latte\Compiler\VariableScope;
/**
@@ -20,17 +23,44 @@
*/
class VarTypeNode extends StatementNode
{
+ public VariableNode $variable;
+ public SuperiorTypeNode $type;
+ public bool $isParameterType = false;
+
+
public static function create(Tag $tag): static
{
$tag->expectArguments();
- $tag->parser->parseType();
- $tag->parser->stream->consume(Token::Php_Variable);
- return new static;
+ $type = $tag->parser->parseType();
+ if (!$type) {
+ $tag->parser->stream->throwUnexpectedException();
+ }
+ $token = $tag->parser->stream->consume(Token::Php_Variable);
+
+ $node = new static;
+ $node->type = $type;
+ $node->variable = new VariableNode(substr($token->text, 1));
+ $node->isParameterType = $tag->isInHead();
+ return $node;
}
public function print(PrintContext $context): string
{
- return '';
+ if ($this->isParameterType) {
+ $scope = $context->getVariableScope();
+ return $scope->addExpression($this->variable, $this->type) . "\n";
+ } elseif (is_string($this->variable->name)) {
+ return VariableScope::printComment($this->variable->name, $this->type?->type) . "\n";
+ } else {
+ return '';
+ }
+ }
+
+
+ public function &getIterator(): \Generator
+ {
+ yield $this->variable;
+ yield $this->type;
}
}
diff --git a/tests/common/expected/Compiler.unquoted.attrs.phtml b/tests/common/expected/Compiler.unquoted.attrs.phtml
index 7896aa032..e0f285d76 100644
--- a/tests/common/expected/Compiler.unquoted.attrs.phtml
+++ b/tests/common/expected/Compiler.unquoted.attrs.phtml
@@ -40,3 +40,4 @@ final class Template%a% extends Latte\Runtime\Template
';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/common/expected/contentType.ical.phtml b/tests/common/expected/contentType.ical.phtml
index 47fc9154d..b45c44ddc 100644
--- a/tests/common/expected/contentType.ical.phtml
+++ b/tests/common/expected/contentType.ical.phtml
@@ -49,3 +49,4 @@ World' /* line %d% */;
return get_defined_vars();
}
}
+%A%
\ No newline at end of file
diff --git a/tests/common/expected/contentType.xml.phtml b/tests/common/expected/contentType.xml.phtml
index 656b9de6b..498ec5293 100644
--- a/tests/common/expected/contentType.xml.phtml
+++ b/tests/common/expected/contentType.xml.phtml
@@ -147,3 +147,4 @@ var html = ';
return get_defined_vars();
}
}
+%A%
\ No newline at end of file
diff --git a/tests/filters/expected/general.phtml b/tests/filters/expected/general.phtml
index 9c18078b9..23a7c060f 100644
--- a/tests/filters/expected/general.phtml
+++ b/tests/filters/expected/general.phtml
@@ -95,3 +95,4 @@ bar')) /* line %d% */;
echo "\n";
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/define.args.phpt b/tests/tags/define.args.phpt
index 47ce35e72..eaaafa34b 100644
--- a/tests/tags/define.args.phpt
+++ b/tests/tags/define.args.phpt
@@ -160,3 +160,26 @@ Assert::matchFile(
__DIR__ . '/expected/define.args5.html',
$latte->renderToString($template),
);
+
+// types
+$latte->setLoader(new Latte\Loaders\StringLoader);
+$template = <<<'XX'
+default values
+
+{define test $var1 = 0, array $var2 = [1, 2, 3], int $var3 = 10}
+ Variables {$var1}, {$var2|implode}, {$var3}
+{/define}
+
+a) {include test, 1}
+
+b) {include test, var1 => 1}
+XX;
+
+Assert::matchFile(
+ __DIR__ . '/expected/define.args6.phtml',
+ $latte->compile($template)
+);
+Assert::matchFile(
+ __DIR__ . '/expected/define.args6.html',
+ $latte->renderToString($template)
+);
diff --git a/tests/tags/expected/block.dynamic.phtml b/tests/tags/expected/block.dynamic.phtml
index 80ead1d29..6cf2e82a9 100644
--- a/tests/tags/expected/block.dynamic.phtml
+++ b/tests/tags/expected/block.dynamic.phtml
@@ -109,3 +109,4 @@ final class Template%a% extends Latte\Runtime\Template
echo ' expression ';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/block.local.dynamic.phtml b/tests/tags/expected/block.local.dynamic.phtml
index 19c44503b..940c90c45 100644
--- a/tests/tags/expected/block.local.dynamic.phtml
+++ b/tests/tags/expected/block.local.dynamic.phtml
@@ -98,3 +98,4 @@ final class Template%a% extends Latte\Runtime\Template
echo 'hello';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/define.args1.phtml b/tests/tags/expected/define.args1.phtml
index 669589658..4e62bdad5 100644
--- a/tests/tags/expected/define.args1.phtml
+++ b/tests/tags/expected/define.args1.phtml
@@ -62,3 +62,4 @@ d) ';
$this->renderBlock('test', ['hello'] + [], 'html') /* line %d% */;
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/define.args2.phtml b/tests/tags/expected/define.args2.phtml
index e623f7f98..64778be3c 100644
--- a/tests/tags/expected/define.args2.phtml
+++ b/tests/tags/expected/define.args2.phtml
@@ -51,3 +51,4 @@ d) ';
echo "\n";
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/define.args3.phtml b/tests/tags/expected/define.args3.phtml
index 7a91196fe..a2b0882da 100644
--- a/tests/tags/expected/define.args3.phtml
+++ b/tests/tags/expected/define.args3.phtml
@@ -48,3 +48,4 @@ c) ';
echo "\n";
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/define.args4.phtml b/tests/tags/expected/define.args4.phtml
index ab1fc96a7..02e4d2ae5 100644
--- a/tests/tags/expected/define.args4.phtml
+++ b/tests/tags/expected/define.args4.phtml
@@ -26,3 +26,4 @@ c) ';
$this->renderBlock('test', ['hello' => 1] + [], 'html') /* line %d% */;
}
}
+%A%
diff --git a/tests/tags/expected/define.args5.phtml b/tests/tags/expected/define.args5.phtml
index abeded288..6177bb489 100644
--- a/tests/tags/expected/define.args5.phtml
+++ b/tests/tags/expected/define.args5.phtml
@@ -42,3 +42,4 @@ b) ';
echo "\n";
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/define.args6.html b/tests/tags/expected/define.args6.html
new file mode 100644
index 000000000..128d3f783
--- /dev/null
+++ b/tests/tags/expected/define.args6.html
@@ -0,0 +1,7 @@
+default values
+
+
+a) Variables 1, 123, 10
+
+
+b) Variables 1, 123, 10
diff --git a/tests/tags/expected/define.args6.phtml b/tests/tags/expected/define.args6.phtml
new file mode 100644
index 000000000..f96c1c593
--- /dev/null
+++ b/tests/tags/expected/define.args6.phtml
@@ -0,0 +1,45 @@
+ 'blockTest'],
+ ];
+
+
+ public function main(array $ʟ_args): void
+ {
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+ echo 'default values
+
+
+a) ';
+ $this->renderBlock('test', [1] + [], 'html') /* line %d% */;
+ echo '
+
+b) ';
+ $this->renderBlock('test', ['var1' => 1] + [], 'html') /* line %d% */;
+ }
+
+
+ /** {define test $var1 = 0, array $var2 = [1, 2, 3], int $var3 = 10} on line %d% */
+ public function blockTest(array $ʟ_args): void
+ {
+ extract($this->params);
+ $var1 = $ʟ_args[0] ?? $ʟ_args['var1'] ?? 0;
+ /** @var array $var2 */ $var2 = $ʟ_args[1] ?? $ʟ_args['var2'] ?? [1, 2, 3];
+ /** @var int $var3 */ $var3 = $ʟ_args[2] ?? $ʟ_args['var3'] ?? 10;
+ unset($ʟ_args);
+
+ echo ' Variables ';
+ echo LR\Filters::escapeHtmlText($var1) /* line %d% */;
+ echo ', ';
+ echo LR\Filters::escapeHtmlText(($this->filters->implode)($var2)) /* line %d% */;
+ echo ', ';
+ echo LR\Filters::escapeHtmlText($var3) /* line %d% */;
+ echo "\n";
+ }
+}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/define.phtml b/tests/tags/expected/define.phtml
index 51d63a484..050802021 100644
--- a/tests/tags/expected/define.phtml
+++ b/tests/tags/expected/define.phtml
@@ -51,3 +51,4 @@ final class Template%a% extends Latte\Runtime\Template
echo 'true';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/define.typehints.phtml b/tests/tags/expected/define.typehints.phtml
index 49c699d6f..ed93986ac 100644
--- a/tests/tags/expected/define.typehints.phtml
+++ b/tests/tags/expected/define.typehints.phtml
@@ -22,3 +22,4 @@ final class Template%a% extends Latte\Runtime\Template
{
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/embed.block.phtml b/tests/tags/expected/embed.block.phtml
index 974eaee47..bbb491ff4 100644
--- a/tests/tags/expected/embed.block.phtml
+++ b/tests/tags/expected/embed.block.phtml
@@ -72,3 +72,4 @@ final class Template%a% extends Latte\Runtime\Template
echo 'embed1-A';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/embed.file.phtml b/tests/tags/expected/embed.file.phtml
index d2c655a8e..2ce330386 100644
--- a/tests/tags/expected/embed.file.phtml
+++ b/tests/tags/expected/embed.file.phtml
@@ -46,3 +46,4 @@ final class Template%a% extends Latte\Runtime\Template
echo 'nested embeds A';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/extends.1.phtml b/tests/tags/expected/extends.1.phtml
index 1c29e833d..1677c9454 100644
--- a/tests/tags/expected/extends.1.phtml
+++ b/tests/tags/expected/extends.1.phtml
@@ -19,3 +19,4 @@ final class Template%a% extends Latte\Runtime\Template
return get_defined_vars();
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/extends.4.phtml b/tests/tags/expected/extends.4.phtml
index 6e7e07890..0df86d5f4 100644
--- a/tests/tags/expected/extends.4.phtml
+++ b/tests/tags/expected/extends.4.phtml
@@ -30,3 +30,4 @@ final class Template%a% extends Latte\Runtime\Template
';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/general.n-attributes.phtml b/tests/tags/expected/general.n-attributes.phtml
index b0484ae2e..d63e3a59e 100644
--- a/tests/tags/expected/general.n-attributes.phtml
+++ b/tests/tags/expected/general.n-attributes.phtml
@@ -497,3 +497,4 @@ final class Template%a% extends Latte\Runtime\Template
';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/general.phtml b/tests/tags/expected/general.phtml
index 0ba353307..df0b87e77 100644
--- a/tests/tags/expected/general.phtml
+++ b/tests/tags/expected/general.phtml
@@ -2,7 +2,10 @@
use Latte\Runtime as LR;
-/** source: %A% */
+/**
+* source: %a%
+* @property FiltersTemplate%a%
+*/
final class Template%a% extends Latte\Runtime\Template
{
public const Blocks = [
@@ -108,3 +111,4 @@ final class Template%a% extends Latte\Runtime\Template
';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/import.phtml b/tests/tags/expected/import.phtml
index efbfc743c..5dd111702 100644
--- a/tests/tags/expected/import.phtml
+++ b/tests/tags/expected/import.phtml
@@ -18,3 +18,8 @@ final class Template%a% extends Latte\Runtime\Template
return get_defined_vars();
}
}
+
+
+class FiltersTemplate%a%
+{
+}
diff --git a/tests/tags/expected/include.block.from.phtml b/tests/tags/expected/include.block.from.phtml
index a335ee03e..043fab4d4 100644
--- a/tests/tags/expected/include.block.from.phtml
+++ b/tests/tags/expected/include.block.from.phtml
@@ -8,3 +8,4 @@ final class Template%a% extends Latte\Runtime\Template
echo ' after';
%A%
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/include.inc1.phtml b/tests/tags/expected/include.inc1.phtml
index 68d3d47b6..118de1249 100644
--- a/tests/tags/expected/include.inc1.phtml
+++ b/tests/tags/expected/include.inc1.phtml
@@ -24,3 +24,4 @@ Parent: ';
echo "\n";
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/include.inc2.phtml b/tests/tags/expected/include.inc2.phtml
index 5810d2df6..18dcffbd2 100644
--- a/tests/tags/expected/include.inc2.phtml
+++ b/tests/tags/expected/include.inc2.phtml
@@ -19,3 +19,4 @@ Parent: ';
echo "\n";
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/include.inc3.phtml b/tests/tags/expected/include.inc3.phtml
index 24290bf94..7ac596aa6 100644
--- a/tests/tags/expected/include.inc3.phtml
+++ b/tests/tags/expected/include.inc3.phtml
@@ -14,3 +14,4 @@ final class Template%a% extends Latte\Runtime\Template
';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/include.phtml b/tests/tags/expected/include.phtml
index a71b9f829..083614c90 100644
--- a/tests/tags/expected/include.phtml
+++ b/tests/tags/expected/include.phtml
@@ -12,3 +12,4 @@ final class Template%a% extends Latte\Runtime\Template
}) /* line %d% */;
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/include.with-blocks.inc.phtml b/tests/tags/expected/include.with-blocks.inc.phtml
index c8e566e3a..a578ba461 100644
--- a/tests/tags/expected/include.with-blocks.inc.phtml
+++ b/tests/tags/expected/include.with-blocks.inc.phtml
@@ -27,3 +27,4 @@ final class Template%a% extends Latte\Runtime\Template
echo "\n";
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/include.with-blocks.phtml b/tests/tags/expected/include.with-blocks.phtml
index f10a80e17..a06e8f645 100644
--- a/tests/tags/expected/include.with-blocks.phtml
+++ b/tests/tags/expected/include.with-blocks.phtml
@@ -11,3 +11,4 @@ final class Template%a% extends Latte\Runtime\Template
$this->renderBlock('test', [], 'html') /* line %d% */;
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/inheritance.1.parent.phtml b/tests/tags/expected/inheritance.1.parent.phtml
index 4478de062..58b23e3d6 100644
--- a/tests/tags/expected/inheritance.1.parent.phtml
+++ b/tests/tags/expected/inheritance.1.parent.phtml
@@ -72,3 +72,4 @@ Parent: ';
';
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/inheritance.1.phtml b/tests/tags/expected/inheritance.1.phtml
index 3d113a0b7..e791014a8 100644
--- a/tests/tags/expected/inheritance.1.phtml
+++ b/tests/tags/expected/inheritance.1.phtml
@@ -71,3 +71,4 @@ final class Template%a% extends Latte\Runtime\Template
echo "\n";
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/inheritance.2.phtml b/tests/tags/expected/inheritance.2.phtml
index 2da627331..85fc8ae5b 100644
--- a/tests/tags/expected/inheritance.2.phtml
+++ b/tests/tags/expected/inheritance.2.phtml
@@ -69,3 +69,4 @@ final class Template%a% extends Latte\Runtime\Template
{
}
}
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/parameters.inc1.phtml b/tests/tags/expected/parameters.inc1.phtml
new file mode 100644
index 000000000..c7deafae6
--- /dev/null
+++ b/tests/tags/expected/parameters.inc1.phtml
@@ -0,0 +1,9 @@
+%A%
+ public function main(array $ʟ_args): void
+ {
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/parameters.inc2.phtml b/tests/tags/expected/parameters.inc2.phtml
new file mode 100644
index 000000000..2ade69aeb
--- /dev/null
+++ b/tests/tags/expected/parameters.inc2.phtml
@@ -0,0 +1,16 @@
+%A%
+ public function main(array $ʟ_args): void
+ {
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
+ public function prepare(): array
+ {
+ $a = $this->params[0] ?? $this->params['a'] ?? null;
+
+ return get_defined_vars();
+ }
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/parameters.inc3.phtml b/tests/tags/expected/parameters.inc3.phtml
new file mode 100644
index 000000000..ad93a72aa
--- /dev/null
+++ b/tests/tags/expected/parameters.inc3.phtml
@@ -0,0 +1,16 @@
+%A%
+ public function main(array $ʟ_args): void
+ {
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
+ public function prepare(): array
+ {
+ /** @var int $a */ $a = $this->params[0] ?? $this->params['a'] ?? 5;
+
+ return get_defined_vars();
+ }
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/parameters.inc4.phtml b/tests/tags/expected/parameters.inc4.phtml
new file mode 100644
index 000000000..11ab9dc95
--- /dev/null
+++ b/tests/tags/expected/parameters.inc4.phtml
@@ -0,0 +1,17 @@
+%A%
+ public function main(array $ʟ_args): void
+ {
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
+ public function prepare(): array
+ {
+ $a = $this->params[0] ?? $this->params['a'] ?? null;
+ /** @var int $b */ $b = $this->params[1] ?? $this->params['b'] ?? 5;
+
+ return get_defined_vars();
+ }
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/parameters.inc5.phtml b/tests/tags/expected/parameters.inc5.phtml
new file mode 100644
index 000000000..ad60d8440
--- /dev/null
+++ b/tests/tags/expected/parameters.inc5.phtml
@@ -0,0 +1,16 @@
+%A%
+ public function main(array $ʟ_args): void
+ {
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
+ public function prepare(): array
+ {
+ $glob = $this->params[0] ?? $this->params['glob'] ?? null;
+
+ return get_defined_vars();
+ }
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/parameters.inc6.phtml b/tests/tags/expected/parameters.inc6.phtml
new file mode 100644
index 000000000..7ca2227b9
--- /dev/null
+++ b/tests/tags/expected/parameters.inc6.phtml
@@ -0,0 +1,16 @@
+%A%
+ public function main(array $ʟ_args): void
+ {
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
+ public function prepare(): array
+ {
+ /** @var ?\Exception $glob */ $glob = $this->params[0] ?? $this->params['glob'] ?? null;
+
+ return get_defined_vars();
+ }
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/parameters.inc7.phtml b/tests/tags/expected/parameters.inc7.phtml
new file mode 100644
index 000000000..9c94579a8
--- /dev/null
+++ b/tests/tags/expected/parameters.inc7.phtml
@@ -0,0 +1,27 @@
+%A%
+ public function main(array $ʟ_args): void
+ {
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
+ public function prepare(): array
+ {
+ $a = $this->params[0] ?? $this->params['a'] ?? null;
+ /** @var int $b */ $b = $this->params[1] ?? $this->params['b'] ?? 5;
+
+ return get_defined_vars();
+ }
+%A%
+ public function blockX(array $ʟ_args): void
+ {
+ extract($this->prepare());
+ /** @var int $b */
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/parameters.inc8.phtml b/tests/tags/expected/parameters.inc8.phtml
new file mode 100644
index 000000000..9c94579a8
--- /dev/null
+++ b/tests/tags/expected/parameters.inc8.phtml
@@ -0,0 +1,27 @@
+%A%
+ public function main(array $ʟ_args): void
+ {
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
+ public function prepare(): array
+ {
+ $a = $this->params[0] ?? $this->params['a'] ?? null;
+ /** @var int $b */ $b = $this->params[1] ?? $this->params['b'] ?? 5;
+
+ return get_defined_vars();
+ }
+%A%
+ public function blockX(array $ʟ_args): void
+ {
+ extract($this->prepare());
+ /** @var int $b */
+ extract($ʟ_args);
+ unset($ʟ_args);
+
+%A%
+ }
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/templateType.phtml b/tests/tags/expected/templateType.phtml
new file mode 100644
index 000000000..303e4bbf4
--- /dev/null
+++ b/tests/tags/expected/templateType.phtml
@@ -0,0 +1,19 @@
+ $arrayType */
+%A%
+ public function blockTest(array $ʟ_args): void
+ {
+ extract($this->params);
+ extract($ʟ_args);
+ unset($ʟ_args);
+ /** @var int $intType */
+ /** @var int|bool $intBoolType */
+ /** @var array $arrayType */
+%A%
\ No newline at end of file
diff --git a/tests/tags/expected/varType.phtml b/tests/tags/expected/varType.phtml
new file mode 100644
index 000000000..38e95e03d
--- /dev/null
+++ b/tests/tags/expected/varType.phtml
@@ -0,0 +1,20 @@
+params);
+ extract($ʟ_args);
+ unset($ʟ_args);
+ /** @var string $a */
+%A?%
+ /** @var int $b */
+ $b = 5%a%;
+%A%
+%A%
\ No newline at end of file
diff --git a/tests/tags/parameters.phpt b/tests/tags/parameters.phpt
index e193eebec..44786ba95 100644
--- a/tests/tags/parameters.phpt
+++ b/tests/tags/parameters.phpt
@@ -18,17 +18,34 @@ $latte->setLoader(new Latte\Loaders\StringLoader([
'main3' => '{include inc3.latte, a: 10}',
'main4' => '{include inc4.latte, a: 10}',
'main5' => '{include inc5.latte, a: 10}',
+ 'main6' => '{include inc6.latte, a: 10}',
+ 'main7' => '{include inc7.latte, a: 10}',
+ 'main8' => '{include inc8.latte, a: 10}',
'inc1.latte' => '{$a ?? "-"} {$b ?? "-"} {$glob ?? "-"}',
'inc2.latte' => '{parameters $a} {$a ?? "-"} {$b ?? "-"} {$glob ?? "-"}',
'inc3.latte' => '{parameters int $a = 5} {$a ?? "-"} {$b ?? "-"} {$glob ?? "-"}',
'inc4.latte' => '{parameters $a, int $b = 5} {$a ?? "-"} {$b ?? "-"} {$glob ?? "-"}',
'inc5.latte' => '{parameters $glob} {$a ?? "-"} {$b ?? "-"} {$glob ?? "-"}',
+ 'inc6.latte' => '{parameters ?\Exception $glob} {$a ?? "-"} {$b ?? "-"} {$glob->getMessage() ?? "-"}',
+ 'inc7.latte' => '{parameters $a, int $b = 5} {block x}{$a ?? "-"} {$b ?? "-"} {$glob ?? "-"}{/block}',
+ 'inc8.latte' => '{parameters $a, int $b = 5} {define x}{$a ?? "-"} {$b ?? "-"} {$glob ?? "-"}{/define}{include x}',
]));
+Assert::matchFile(__DIR__ . '/expected/parameters.inc1.phtml', $latte->compile('inc1.latte'));
+Assert::matchFile(__DIR__ . '/expected/parameters.inc2.phtml', $latte->compile('inc2.latte'));
+Assert::matchFile(__DIR__ . '/expected/parameters.inc3.phtml', $latte->compile('inc3.latte'));
+Assert::matchFile(__DIR__ . '/expected/parameters.inc4.phtml', $latte->compile('inc4.latte'));
+Assert::matchFile(__DIR__ . '/expected/parameters.inc5.phtml', $latte->compile('inc5.latte'));
+Assert::matchFile(__DIR__ . '/expected/parameters.inc6.phtml', $latte->compile('inc6.latte'));
+Assert::matchFile(__DIR__ . '/expected/parameters.inc7.phtml', $latte->compile('inc7.latte'));
+Assert::matchFile(__DIR__ . '/expected/parameters.inc8.phtml', $latte->compile('inc8.latte'));
Assert::same('10 - 123', $latte->renderToString('main1', ['glob' => 123]));
Assert::same(' 10 - -', $latte->renderToString('main2', ['glob' => 123]));
Assert::same(' 10 - -', $latte->renderToString('main3', ['glob' => 123]));
Assert::same(' 10 5 -', $latte->renderToString('main4', ['glob' => 123]));
Assert::same(' - - 123', $latte->renderToString('main5', ['glob' => 123]));
+Assert::same(' - - 123', $latte->renderToString('main6', ['glob' => new \Exception("123")]));
+Assert::same(' 10 5 -', $latte->renderToString('main7', ['glob' => 123]));
+Assert::same(' 10 5 -', $latte->renderToString('main8', ['glob' => 123]));
diff --git a/tests/tags/templateType.phpt b/tests/tags/templateType.phpt
index 847cb8e79..902ae51f4 100644
--- a/tests/tags/templateType.phpt
+++ b/tests/tags/templateType.phpt
@@ -11,6 +11,17 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
+class TemplateClass
+{
+ public $noType;
+ public int $intType;
+ public int|bool $intBoolType;
+ /** @var array */
+ public array $arrayType;
+ private int $private;
+}
+
+
$latte = new Latte\Engine;
$latte->setLoader(new Latte\Loaders\StringLoader);
@@ -20,10 +31,26 @@ Assert::exception(
'Missing class name in {templateType} (at column 1)',
);
+Assert::exception(
+ fn() => $latte->compile('{templateType AA\BBB}'),
+ Latte\CompileException::class,
+ "Class 'AA\\BBB' used in {templateType} doesn't exist (at column 15)",
+);
+
Assert::exception(
fn() => $latte->compile('{if true}{templateType stdClass}{/if}'),
Latte\CompileException::class,
'{templateType} is allowed only in template header (at column 10)',
);
-Assert::noError(fn() => $latte->compile('{templateType stdClass}'));
+Assert::contains(
+ '/** @var int $intType */' . "\n\t\t" .
+ '/** @var int|bool $intBoolType */'. "\n\t\t" .
+ '/** @var array $arrayType */'. "\n\n",
+ $latte->compile('{templateType TemplateClass}{$intBoolType}'),
+);
+
+Assert::matchFile(
+ __DIR__ . '/expected/templateType.phtml',
+ $latte->compile('{templateType TemplateClass}{$intBoolType}{define test}{$intBoolType}{/define}')
+);
diff --git a/tests/tags/var.default.nodes.phpt b/tests/tags/var.default.nodes.phpt
index 6f1794a97..911c420bc 100644
--- a/tests/tags/var.default.nodes.phpt
+++ b/tests/tags/var.default.nodes.phpt
@@ -20,5 +20,7 @@ Assert::match(<<<'XX'
name: var2
Integer:
value: 3
+ SuperiorType:
+ 'int|array'
Fragment:
XX, exportTraversing('{var $var, int|array $var2 = 3}'));
diff --git a/tests/tags/var.default.phpt b/tests/tags/var.default.phpt
index 627dd6392..42566d7c4 100644
--- a/tests/tags/var.default.phpt
+++ b/tests/tags/var.default.phpt
@@ -25,9 +25,9 @@ test('{var ...}', function () use ($latte) {
// types
Assert::contains('$temp->var1 = 123 /*', $latte->compile('{var int $temp->var1 = 123}'));
Assert::contains('$temp->var1 = 123 /*', $latte->compile('{var null|int|string[] $temp->var1 = 123}'));
- Assert::contains('$var1 = 123; $var2 = \'nette framework\' /*', ws($latte->compile('{var int|string[] $var1 = 123, ?class $var2 = "nette framework"}')));
- Assert::contains('$var1 = 123; $var2 = 456 /*', ws($latte->compile('{var A\B $var1 = 123, ?A\B $var2 = 456}')));
- Assert::contains('$var1 = 123; $var2 = 456 /*', ws($latte->compile('{var \A\B $var1 = 123, ?\A\B $var2 = 456}')));
+ Assert::contains('/** @var int|string[] $var1 */$var1 = 123; /** @var ?class $var2 */$var2 = \'nette framework\' /* line 1 */;', ws($latte->compile('{var int|string[] $var1 = 123, ?class $var2 = "nette framework"}')));
+ Assert::contains('/** @var A\B $var1 */$var1 = 123; /** @var ?A\B $var2 */$var2 = 456 /*', ws($latte->compile('{var A\B $var1 = 123, ?A\B $var2 = 456}')));
+ Assert::contains('/** @var \A\B $var1 */$var1 = 123; /** @var ?\A\B $var2 */$var2 = 456 /*', ws($latte->compile('{var \A\B $var1 = 123, ?\A\B $var2 = 456}')));
// errors
Assert::exception(
diff --git a/tests/tags/varType.nodes.phpt b/tests/tags/varType.nodes.phpt
index e20e9d6b3..8db160990 100644
--- a/tests/tags/varType.nodes.phpt
+++ b/tests/tags/varType.nodes.phpt
@@ -15,5 +15,9 @@ Assert::match(<<<'XX'
Template:
Fragment:
VarType:
+ Variable:
+ name: int
+ SuperiorType:
+ 'int'
Fragment:
XX, exportTraversing('{varType int $int}'));
diff --git a/tests/tags/varType.phpt b/tests/tags/varType.phpt
index a3306d9c2..66878d560 100644
--- a/tests/tags/varType.phpt
+++ b/tests/tags/varType.phpt
@@ -35,13 +35,49 @@ Assert::exception(
Assert::exception(
fn() => $latte->compile('{varType $var type}'),
Latte\CompileException::class,
- "Unexpected 'type', expecting end of tag in {varType} (at column 15)",
+ "Unexpected '\$vartype' (at column 10)",
);
-Assert::noError(fn() => $latte->compile('{varType type $var}'));
+Assert::contains(
+ '/** @var type $var */',
+ $latte->compile('{varType type $var}'),
+);
+
+Assert::contains(
+ '/** @var ?\Nm\Class $var */',
+ $latte->compile('{varType ?\Nm\Class $var}'),
+);
+
+Assert::contains(
+ '/** @var int|null $var */',
+ $latte->compile('{varType int|null $var}'),
+);
+
+Assert::contains(
+ '/** @var array{0:int,1:int} $var */',
+ $latte->compile('{varType array{0: int, 1: int} $var}'),
+);
-Assert::noError(fn() => $latte->compile('{varType ?\Nm\Class $var}'));
+$template = <<<'XX'
-Assert::noError(fn() => $latte->compile('{varType int|null $var}'));
+{varType string $a}
-Assert::noError(fn() => $latte->compile('{varType array{0: int, 1: int} $var}'));
+{$a}
+
+{varType string $c}
+{var $c = 10}
+
+{include test}
+
+{define test}
+ {varType int $b}
+ {var $b = 5}
+ {$a}{$b}
+{/define}
+
+XX;
+
+Assert::matchFile(
+ __DIR__ . '/expected/varType.phtml',
+ $latte->compile($template),
+);