Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions src/JsParsing/BinaryExpression.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
declare( strict_types = 1 );

namespace WMDE\VueJsTemplating\JsParsing;

use RuntimeException;

class BinaryExpression implements ParsedExpression {

private ParsedExpression $left;
private ParsedExpression $right;
private string $operator;

public function __construct( ParsedExpression $left, ParsedExpression $right, string $operator ) {
$this->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 . '"' )
};
}

}
27 changes: 27 additions & 0 deletions src/JsParsing/BooleanLiteral.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare( strict_types = 1 );

namespace WMDE\VueJsTemplating\JsParsing;

class BooleanLiteral implements ParsedExpression {

/**
* @var bool value
*/
private $value;

public function __construct( bool $value ) {
$this->value = $value;
}

/**
* @param array $data ignored
*
* @return value as provided on construction time
*/
public function evaluate( array $data ) {
return $this->value;
}

}
30 changes: 30 additions & 0 deletions src/JsParsing/NumericLiteral.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare( strict_types = 1 );

namespace WMDE\VueJsTemplating\JsParsing;

class NumericLiteral implements ParsedExpression {

/**
* @var int|float
*/
private $value;

/**
* @param int|float $value
*/
public function __construct( $value ) {
$this->value = $value;
}

/**
* @param array $data ignored
*
* @return value as provided on construction time
*/
public function evaluate( array $data ) {
return $this->value;
}

}
12 changes: 12 additions & 0 deletions src/JsParsing/PeastExpressionConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 ),
Expand All @@ -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 )
)
Expand Down
46 changes: 46 additions & 0 deletions tests/php/JsParsing/BasicJsExpressionParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace WMDE\VueJsTemplating\Test\JsParsing;

use Exception;
use PHPUnit\Framework\TestCase;
use WMDE\VueJsTemplating\JsParsing\BasicJsExpressionParser;

Expand Down Expand Up @@ -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 ] ] );
}

}
15 changes: 15 additions & 0 deletions tests/php/TemplatingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,21 @@ public function testMoustacheVariableWithArrayObjectTypeSubstitution() {
$this->assertSame( '<p>{"a":"b","c":"d"}</p>', $result );
}

public function testTemplateWithBooleanExpression() {
$result = $this->createAndRender(
'<div><div v-if="myvar === \'myvalue\'"><p>Paragraph</p></div></div>',
[ 'myvar' => 'myvalue' ]
);

$this->assertSame( '<div><div><p>Paragraph</p></div></div>', $result );
}

public function testTemplateWithBooleanValueInIf() {
$result = $this->createAndRender( '<p><a v-if="false"></a></p>', [ 'variable' => true ] );

$this->assertSame( '<p></p>', $result );
}

/**
* @param string $template HTML
* @param array $data
Expand Down