diff --git a/src/JsParsing/BinaryExpression.php b/src/JsParsing/BinaryExpression.php new file mode 100644 index 0000000..2892876 --- /dev/null +++ b/src/JsParsing/BinaryExpression.php @@ -0,0 +1,50 @@ +left = $left; + $this->right = $right; + $this->operator = $operator; + } + + /** + * @param array $data + * + * @throws RuntimeException + * @return bool + */ + public function evaluate( array $data ) { + $lval = $this->left->evaluate( $data ); + $rval = $this->right->evaluate( $data ); + if ( + !( is_string( $rval ) || is_numeric( $rval ) || is_bool( $rval ) ) || + !( is_string( $lval ) || is_numeric( $lval ) || is_bool( $lval ) ) + ) { + throw new RuntimeException( + 'BooleanExpression must compare strings or numbers. Got ' . + gettype( $lval ) . ' and ' . gettype( $rval ) + ); + } + return match ( $this->operator ) { + '===' => $lval === $rval, + '==' => $lval == $rval, + '>=' => $lval >= $rval, + '>' => $lval > $rval, + '<=' => $lval <= $rval, + '<' => $lval < $rval, + '!=' => $lval != $rval, + default => throw new RuntimeException( 'Unknown operator in BooleanExpression: "' . $this->operator . '"' ) + }; + } + +} diff --git a/src/JsParsing/BooleanLiteral.php b/src/JsParsing/BooleanLiteral.php new file mode 100644 index 0000000..c5464b8 --- /dev/null +++ b/src/JsParsing/BooleanLiteral.php @@ -0,0 +1,27 @@ +value = $value; + } + + /** + * @param array $data ignored + * + * @return value as provided on construction time + */ + public function evaluate( array $data ) { + return $this->value; + } + +} diff --git a/src/JsParsing/NumericLiteral.php b/src/JsParsing/NumericLiteral.php new file mode 100644 index 0000000..e5b9a78 --- /dev/null +++ b/src/JsParsing/NumericLiteral.php @@ -0,0 +1,30 @@ +value = $value; + } + + /** + * @param array $data ignored + * + * @return value as provided on construction time + */ + public function evaluate( array $data ) { + return $this->value; + } + +} diff --git a/src/JsParsing/PeastExpressionConverter.php b/src/JsParsing/PeastExpressionConverter.php index af57b3b..47480b3 100644 --- a/src/JsParsing/PeastExpressionConverter.php +++ b/src/JsParsing/PeastExpressionConverter.php @@ -4,10 +4,13 @@ namespace WMDE\VueJsTemplating\JsParsing; +use Peast\Syntax\Node\BinaryExpression as PeastBinaryExpression; +use Peast\Syntax\Node\BooleanLiteral as PeastBooleanLiteral; use Peast\Syntax\Node\CallExpression; use Peast\Syntax\Node\Expression; use Peast\Syntax\Node\Identifier; use Peast\Syntax\Node\MemberExpression; +use Peast\Syntax\Node\NumericLiteral as PeastNumericLiteral; use Peast\Syntax\Node\ObjectExpression; use Peast\Syntax\Node\StringLiteral as PeastStringLiteral; use Peast\Syntax\Node\UnaryExpression; @@ -71,6 +74,12 @@ protected function convertObjectExpression( ObjectExpression $expression ) { return new JsDictionary( $parsedExpressionMap ); } + protected function convertBinaryExpression( PeastBinaryExpression $expression ) { + $lexp = $this->convertExpression( $expression->getLeft() ); + $rexp = $this->convertExpression( $expression->getRight() ); + return new BinaryExpression( $lexp, $rexp, $expression->getOperator() ); + } + public function convertExpression( Expression $expression ) { return match( get_class( $expression ) ) { UnaryExpression::class => $this->convertUnaryExpression( $expression ), @@ -79,6 +88,9 @@ public function convertExpression( Expression $expression ) { Identifier::class => new VariableAccess( [ $expression->getName() ] ), CallExpression::class => $this->convertCallExpression( $expression ), ObjectExpression::class => $this->convertObjectExpression( $expression ), + PeastBooleanLiteral::class => new BooleanLiteral( $expression->getValue() ), + PeastNumericLiteral::class => new NumericLiteral( $expression->getValue() ), + PeastBinaryExpression::class => $this->convertBinaryExpression( $expression ), default => throw new RuntimeException( 'Unable to parse complex expression of type ' . get_class( $expression ) ) diff --git a/tests/php/JsParsing/BasicJsExpressionParserTest.php b/tests/php/JsParsing/BasicJsExpressionParserTest.php index 46152eb..a8cfa3c 100644 --- a/tests/php/JsParsing/BasicJsExpressionParserTest.php +++ b/tests/php/JsParsing/BasicJsExpressionParserTest.php @@ -2,6 +2,7 @@ namespace WMDE\VueJsTemplating\Test\JsParsing; +use Exception; use PHPUnit\Framework\TestCase; use WMDE\VueJsTemplating\JsParsing\BasicJsExpressionParser; @@ -116,4 +117,49 @@ public function testCanParse_dictionary_with_string_keys(): void { "wikibase-mex-icon-collapse-x-small" => false ], $result ); } + + public function testCanParse_boolean_literal(): void { + $jsExpressionEvaluator = new BasicJsExpressionParser( [] ); + + $parsedExpression = $jsExpressionEvaluator->parse( "false" ); + $result = $parsedExpression->evaluate( [] ); + + $this->assertFalse( $result ); + } + + public function testCanParseBinaryExpression_withBools(): void { + $jsExpressionEvaluator = new BasicJsExpressionParser( [] ); + + $parsedExpression = $jsExpressionEvaluator->parse( "false != true" ); + $result = $parsedExpression->evaluate( [] ); + + $this->assertTrue( $result ); + } + + public function testCanParseBinaryExpression_withNumbers(): void { + $jsExpressionEvaluator = new BasicJsExpressionParser( [] ); + + $parsedExpression = $jsExpressionEvaluator->parse( "3 < 4" ); + $result = $parsedExpression->evaluate( [] ); + + $this->assertTrue( $result ); + } + + public function testCanParseBinaryExpression_withStrings(): void { + $jsExpressionEvaluator = new BasicJsExpressionParser( [] ); + + $parsedExpression = $jsExpressionEvaluator->parse( "'this' == 'that'" ); + $result = $parsedExpression->evaluate( [] ); + + $this->assertFalse( $result ); + } + + public function testParseBinaryExpressionWithComplexValues_throwsError(): void { + $jsExpressionEvaluator = new BasicJsExpressionParser( [] ); + $this->expectException( Exception::class ); + + $parsedExpression = $jsExpressionEvaluator->parse( "3 < myvar" ); + $parsedExpression->evaluate( [ 'myvar' => [ 1, 2, 3 ] ] ); + } + } diff --git a/tests/php/TemplatingTest.php b/tests/php/TemplatingTest.php index c24699e..b8511d6 100644 --- a/tests/php/TemplatingTest.php +++ b/tests/php/TemplatingTest.php @@ -362,6 +362,21 @@ public function testMoustacheVariableWithArrayObjectTypeSubstitution() { $this->assertSame( '

{"a":"b","c":"d"}

', $result ); } + public function testTemplateWithBooleanExpression() { + $result = $this->createAndRender( + '

Paragraph

', + [ 'myvar' => 'myvalue' ] + ); + + $this->assertSame( '

Paragraph

', $result ); + } + + public function testTemplateWithBooleanValueInIf() { + $result = $this->createAndRender( '

', [ 'variable' => true ] ); + + $this->assertSame( '

', $result ); + } + /** * @param string $template HTML * @param array $data