From 27ccf46bfd9ee85e782d36519928ed9d42930975 Mon Sep 17 00:00:00 2001 From: KyleKatarn Date: Sat, 8 Oct 2022 21:43:10 +0200 Subject: [PATCH 1/2] Fix expression read in assignments --- .../Lexer/Lexer/Scanner/AssignmentScanner.php | 10 +++++-- .../Lexer/Lexer/Scanner/AttributeScanner.php | 30 ++++++++++++------- src/Phug/Lexer/Lexer/State.php | 7 +++-- .../Lexer/Scanner/AttributeScannerTest.php | 24 +++++++++++++++ tests/Phug/RendererTest.php | 13 ++++++++ 5 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/Phug/Lexer/Lexer/Scanner/AssignmentScanner.php b/src/Phug/Lexer/Lexer/Scanner/AssignmentScanner.php index 1897b9db..11066756 100644 --- a/src/Phug/Lexer/Lexer/Scanner/AssignmentScanner.php +++ b/src/Phug/Lexer/Lexer/Scanner/AssignmentScanner.php @@ -14,9 +14,15 @@ class AssignmentScanner implements ScannerInterface { public function scan(State $state) { - return $state->scanToken( + foreach ($state->scanToken( AssignmentToken::class, '&(?[a-zA-Z_][a-zA-Z0-9\-_]*)' - ); + ) as $token) { + yield $token; + + foreach ($state->scan(AttributeScanner::class, ['allow_name' => false]) as $attributeToken) { + yield $attributeToken; + } + } } } diff --git a/src/Phug/Lexer/Lexer/Scanner/AttributeScanner.php b/src/Phug/Lexer/Lexer/Scanner/AttributeScanner.php index 877d7607..ff6816c6 100644 --- a/src/Phug/Lexer/Lexer/Scanner/AttributeScanner.php +++ b/src/Phug/Lexer/Lexer/Scanner/AttributeScanner.php @@ -120,13 +120,15 @@ private function getAttributeValue(Reader $reader, array $chars = null) return $expression; } - private function readAttributeValue(Reader $reader, AttributeToken $token) + private function readAttributeValue(Reader $reader, AttributeToken $token, $expression = '') { - $expression = $this->getAttributeValue($reader); + $expression .= $this->getAttributeValue($reader); + while ($this->isTruncatedExpression($reader, $expression)) { $this->skipComments($reader); $expression .= $this->getAttributeValue($reader); } + $token->setValue($expression); //Ignore a comma if found @@ -212,7 +214,7 @@ private function getAttributeToken(State $state) $token->escape(); $token->check(); - if ($variadic = $reader->peekString('...')) { + if ($reader->peekString('...')) { $token->setIsVariadic(true); $reader->consume(); } @@ -220,9 +222,17 @@ private function getAttributeToken(State $state) return $token; } - private function seedAttributeToken(State $state, AttributeToken $token, $expression) + private function seedAttributeToken(State $state, AttributeToken $token, $expression, array $options) { $reader = $state->getReader(); + $allowName = isset($options['allow_name']) ? $options['allow_name'] : true; + + if (!$allowName) { + $this->readAttributeValue($reader, $token, $expression); + $this->skipComments($reader); + + return; + } $token->setName($expression); @@ -254,7 +264,7 @@ private function seedAttributeToken(State $state, AttributeToken $token, $expres } } - private function scanParenthesesContent(State $state) + private function scanParenthesesContent(State $state, array $options) { $reader = $state->getReader(); @@ -265,7 +275,7 @@ private function scanParenthesesContent(State $state) continue; } - $this->seedAttributeToken($state, $token, $expression); + $this->seedAttributeToken($state, $token, $expression, $options); yield $token; @@ -277,7 +287,7 @@ private function scanParenthesesContent(State $state) } } - private function scanParentheses(State $state) + private function scanParentheses(State $state, array $options) { $reader = $state->getReader(); @@ -285,7 +295,7 @@ private function scanParentheses(State $state) return; } - foreach ($this->scanParenthesesContent($state) as $token) { + foreach ($this->scanParenthesesContent($state, $options) as $token) { yield $token; } @@ -296,7 +306,7 @@ private function scanParentheses(State $state) } } - public function scan(State $state) + public function scan(State $state, array $options = []) { $reader = $state->getReader(); @@ -309,7 +319,7 @@ public function scan(State $state) $reader->consume(); yield $state->endToken($start); - foreach ($this->scanParentheses($state) as $token) { + foreach ($this->scanParentheses($state, $options) as $token) { yield $token; } diff --git a/src/Phug/Lexer/Lexer/State.php b/src/Phug/Lexer/Lexer/State.php index 415e7efc..c7f0d054 100644 --- a/src/Phug/Lexer/Lexer/State.php +++ b/src/Phug/Lexer/Lexer/State.php @@ -230,20 +230,21 @@ public function indent($level = null) * use the `loopScan`-method * * @param array|string $scanners the scanners to run + * @param array $options options to be passed for the scanner * * @throws LexerException * * @return iterable the generator yielding all tokens found */ - public function scan($scanners) + public function scan($scanners, array $options = []) { $scanners = $this->filterScanners($scanners); - foreach ($scanners as $key => $scanner) { + foreach ($scanners as $scanner) { /** @var ScannerInterface $scanner */ $success = false; - foreach ($scanner->scan($this) as $token) { + foreach ($scanner->scan($this, $options) as $token) { if (!($token instanceof TokenInterface)) { $this->throwException( 'Scanner '.get_class($scanner).' generated a result that is not a '.TokenInterface::class diff --git a/tests/Phug/Lexer/Scanner/AttributeScannerTest.php b/tests/Phug/Lexer/Scanner/AttributeScannerTest.php index 496971eb..7729349f 100644 --- a/tests/Phug/Lexer/Scanner/AttributeScannerTest.php +++ b/tests/Phug/Lexer/Scanner/AttributeScannerTest.php @@ -5,6 +5,7 @@ use Phug\Lexer; use Phug\Lexer\Scanner\AttributeScanner; use Phug\Lexer\State; +use Phug\Lexer\Token\AssignmentToken; use Phug\Lexer\Token\AttributeEndToken; use Phug\Lexer\Token\AttributeStartToken; use Phug\Lexer\Token\AttributeToken; @@ -601,4 +602,27 @@ public function testJsAttributeStyle() self::assertSame('class', $class->getName()); self::assertSame('"a"', $class->getValue()); } + + public function testTernaryRendering() + { + list( + $tag, + $assignment, + $start, + $attribute, + $end, + ) = $this->assertTokens('div&attributes(val === "42" ? {"answer": "42"} : {"ko": "failed"})', [ + TagToken::class, + AssignmentToken::class, + AttributeStartToken::class, + AttributeToken::class, + AttributeEndToken::class, + ]); + + self::assertSame('div', $tag->getName()); + self::assertSame('attributes', $assignment->getName()); + self::assertSame(0, $start->getLevel()); + self::assertSame('val === "42" ? {"answer": "42"} : {"ko": "failed"}', $attribute->getValue()); + self::assertSame(0, $end->getLevel()); + } } diff --git a/tests/Phug/RendererTest.php b/tests/Phug/RendererTest.php index e9b83823..a18051f5 100644 --- a/tests/Phug/RendererTest.php +++ b/tests/Phug/RendererTest.php @@ -1418,6 +1418,19 @@ public function testBooleanCastAbleObject() self::assertSame('

if true

unless false

while

while

', trim($pug->render($code, $data))); } + public function testTernaryRendering() + { + include_once __DIR__.'/Utils/BooleanAble.php'; + + $pug = new Renderer([ + 'modules' => [JsPhpizePhug::class], + ]); + $code = 'div&attributes(val === "42" ? {"answer": "42"} : {"ko": "failed"})'; + + self::assertSame('
', trim($pug->render($code, ['val' => '42']))); + self::assertSame('
', trim($pug->render($code, ['val' => '1']))); + } + private function getJsPhpizeVersion() { $directory = __DIR__.'/../../vendor/composer'; From 7533aafd57e0a5abeafa6fa917345efd3a38aba2 Mon Sep 17 00:00:00 2001 From: KyleKatarn Date: Sat, 8 Oct 2022 22:47:25 +0200 Subject: [PATCH 2/2] Fix tests for assignment --- .multi-tester.yml | 41 +++++++++++++++---- .../Lexer/Scanner/AssignmentScannerTest.php | 2 +- .../Lexer/Scanner/AttributeScannerTest.php | 26 ++++++------ 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/.multi-tester.yml b/.multi-tester.yml index a35826a0..d17331c1 100644 --- a/.multi-tester.yml +++ b/.multi-tester.yml @@ -1,4 +1,7 @@ -pug-php/pug: default +pug-php/pug: + install: + - composer config --no-plugins allow-plugins.nodejs-php-fallback/nodejs-php-fallback true + - composer install --no-interaction pug/bemto: autoload: @@ -8,11 +11,20 @@ pug/bemto: - composer dump-autoload --optimize --no-interaction --quiet - composer self-update --2 -pug-php/pug-assets: default +pug-php/pug-assets: + install: + - composer config --no-plugins allow-plugins.nodejs-php-fallback/nodejs-php-fallback true + - composer install --no-interaction -pug-php/pug-minify: default +pug-php/pug-minify: + install: + - composer config --no-plugins allow-plugins.nodejs-php-fallback/nodejs-php-fallback true + - composer install --no-interaction -pug/slim: default +pug/slim: + install: + - composer config --no-plugins allow-plugins.nodejs-php-fallback/nodejs-php-fallback true + - composer install --no-interaction pug/twig: autoload: @@ -21,8 +33,19 @@ pug/twig: - composer dump-autoload --optimize --no-interaction --quiet - composer self-update --2 -ci-pug/ci-pug: default - -bkwld/laravel-pug: default - -pug/yii2: default +ci-pug/ci-pug: + install: + - composer config --no-plugins allow-plugins.nodejs-php-fallback/nodejs-php-fallback true + - composer install --no-interaction + +bkwld/laravel-pug: + install: + - composer config --no-plugins allow-plugins.pug/installer true + - composer config --no-plugins allow-plugins.nodejs-php-fallback/nodejs-php-fallback true + - composer install --no-interaction + +pug/yii2: + install: + - composer config --no-plugins allow-plugins.yiisoft/yii2-composer true + - composer config --no-plugins allow-plugins.nodejs-php-fallback/nodejs-php-fallback true + - composer install --no-interaction diff --git a/tests/Phug/Lexer/Scanner/AssignmentScannerTest.php b/tests/Phug/Lexer/Scanner/AssignmentScannerTest.php index 7ba75009..d9029677 100644 --- a/tests/Phug/Lexer/Scanner/AssignmentScannerTest.php +++ b/tests/Phug/Lexer/Scanner/AssignmentScannerTest.php @@ -59,7 +59,7 @@ public function testObjectInTernary() self::assertSame( 'isNestedFile ? {\'href\': \'../account-orders.html\'} : {\'href\': \'accountorders.html\'}', - $tok->getName() + $tok->getValue() ); } } diff --git a/tests/Phug/Lexer/Scanner/AttributeScannerTest.php b/tests/Phug/Lexer/Scanner/AttributeScannerTest.php index 7729349f..33186456 100644 --- a/tests/Phug/Lexer/Scanner/AttributeScannerTest.php +++ b/tests/Phug/Lexer/Scanner/AttributeScannerTest.php @@ -603,21 +603,21 @@ public function testJsAttributeStyle() self::assertSame('"a"', $class->getValue()); } + /** + * @covers \Phug\Lexer\Scanner\AssignmentScanner::scan + */ public function testTernaryRendering() { - list( - $tag, - $assignment, - $start, - $attribute, - $end, - ) = $this->assertTokens('div&attributes(val === "42" ? {"answer": "42"} : {"ko": "failed"})', [ - TagToken::class, - AssignmentToken::class, - AttributeStartToken::class, - AttributeToken::class, - AttributeEndToken::class, - ]); + list($tag, $assignment, $start, $attribute, $end) = $this->assertTokens( + 'div&attributes(val === "42" ? {"answer": "42"} : {"ko": "failed"})', + [ + TagToken::class, + AssignmentToken::class, + AttributeStartToken::class, + AttributeToken::class, + AttributeEndToken::class, + ] + ); self::assertSame('div', $tag->getName()); self::assertSame('attributes', $assignment->getName());