Skip to content

Commit

Permalink
Merge pull request #18 from Paneon/feature/required-props
Browse files Browse the repository at this point in the history
Add support for dynamic classes using object binding
  • Loading branch information
Macavity authored Feb 21, 2019
2 parents e1c8391 + a4aa825 commit 7bc68d0
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 31 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
# PHPUnit
.phpcs-cache

node_modules
59 changes: 30 additions & 29 deletions src/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,9 @@ public function convert(): string
public function convertNode(DOMNode $node): DOMNode
{
switch ($node->nodeType) {
// We don't need to handle either of these node-types
case XML_TEXT_NODE:
$this->logger->debug('Text node found', ['name' => $node->nodeName]);
// fall through to next case, because we don't need to handle either of these node-types
case XML_COMMENT_NODE:
$this->logger->debug('Comment node found', ['name' => $node->nodeName]);
return $node;
case XML_ELEMENT_NODE:
/** @var DOMElement $node */
Expand Down Expand Up @@ -184,25 +182,29 @@ private function handleAttributeBinding(DOMElement $node)
switch ($name) {
case 'key':
// Not necessary in twig
$this->logger->debug('- skip: key');
return;
case 'style':
break;
case 'class':
break;
}

$regexArrayBinding = '/^\[([^\]]+)\]$/';
$regexArrayElements = '/((?:[\'"])(?<elements>[^\'"])[\'"])/';
$regexTemplateString = '/^`(?P<content>.+)`$/';
$regexObjectBinding = '/^\{(?<elements>[^\}]+)\}$/';
$regexObjectElements = '/["\']?(?<class>[^"\']+)["\']?:\s*(?<condition>[^,]+)/x';

if ($value === 'true') {
$this->logger->debug('- setAttribute ' . $name);
$node->setAttribute($name, $name);
} elseif (preg_match('/^\[([^\]]+)\]$/', $value, $matches)) {
$this->logger->debug('- is array '.$value);
} elseif (preg_match($regexArrayBinding, $value, $matches)) {
$this->logger->debug('- array binding ', ['value' => $value]);

if(preg_match_all('/((?:[\'"])(?<elements>[^\'"])[\'"])/', $value, $arrayMatch)){
if (preg_match_all($regexArrayElements, $value, $arrayMatch)) {
$value = $arrayMatch['elements'];
$this->logger->debug('- ', ['match' => $arrayMatch]);
}
else {
} else {
$value = [];
}

Expand All @@ -218,8 +220,23 @@ private function handleAttributeBinding(DOMElement $node)
$dynamicValues[] = $className;
}
}
}
elseif (preg_match('/^`(?P<content>.+)`$/', $value, $matches)) {
} elseif (preg_match($regexObjectBinding, $value, $matches)) {
$this->logger->debug('- object binding ', ['value' => $value]);

$items = explode(',', $matches['elements']);
$this->logger->debug(print_r($items,true));

foreach ($items as $item) {
if(preg_match($regexObjectElements, $item, $matchElement)){
$dynamicValues[] = sprintf(
'{{ %s ? \'%s\' }}',
$this->builder->refactorCondition($matchElement['condition']),
$matchElement['class']
);
}
}

} elseif (preg_match($regexTemplateString, $value, $matches)) {
/*
* <div :class="`abc ${someDynamicClass}`">
*/
Expand Down Expand Up @@ -262,7 +279,6 @@ private function handleIf(DOMElement $node): void
} else {
$condition = $node->getAttribute('v-if');
}
$condition = $this->sanitizeCondition($condition);

// Open with if
$openIf = $this->document->createTextNode($this->builder->createIf($condition));
Expand All @@ -283,7 +299,6 @@ private function handleIf(DOMElement $node): void
} else {
$condition = $node->getAttribute('v-else-if');
}
$condition = $this->sanitizeCondition($condition);

// Replace old endif with else
$this->lastCloseIf->textContent = $this->builder->createElseIf($condition);
Expand Down Expand Up @@ -402,29 +417,15 @@ private function getRootNode(DOMElement $element): \DOMNode
return $firstTagNode;
}

protected function sanitizeCondition(string $condition)
{
$condition = str_replace('&&', 'and', $condition);
$condition = str_replace('||', 'or', $condition);
$condition = str_replace('!==', '!=', $condition);
$condition = preg_replace('/!([^=])/', 'not $1', $condition);

foreach (Replacements::getConstants() as $constant => $value) {
$condition = str_replace($value, Replacements::getSanitizedConstant($constant), $condition);
}

return $condition;
}

protected function implodeAttributeValue(string $attribute, array $values, string $oldValue): string
{
$glue = ' ';

if($attribute === 'style') {
if ($attribute === 'style') {
$glue = '; ';
}

if(!empty($oldValue)) {
if (!empty($oldValue)) {
$values = array_merge([$oldValue], $values);
}

Expand Down
9 changes: 9 additions & 0 deletions src/Utils/TwigBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Paneon\VueToTwig\Utils;

use Paneon\VueToTwig\Models\Replacements;
use Paneon\VueToTwig\Property;

class TwigBuilder
Expand Down Expand Up @@ -135,6 +136,14 @@ public function refactorCondition(string $condition): string
{
$condition = str_replace('===', '==', $condition);
$condition = str_replace('!==', '!=', $condition);
$condition = str_replace('&&', 'and', $condition);
$condition = str_replace('||', 'or', $condition);
$condition = preg_replace('/!([^=])/', 'not $1', $condition);
$condition = str_replace('.length', '|length', $condition);

foreach (Replacements::getConstants() as $constant => $value) {
$condition = str_replace($value, Replacements::getSanitizedConstant($constant), $condition);
}

return $condition;
}
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/vue-bind/binding-with-template-string.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
<div class="block block--{{ modifier }}" style="fill: {{ color }}">
Hello World
</div>
<div class="{{ isTrue ? 'a' : 'b' }}"></div>
</div>
1 change: 1 addition & 0 deletions tests/fixtures/vue-bind/binding-with-template-string.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<div :class="`block block--${modifier}`" :style="`fill: ${color}`">
Hello World
</div>
<div :class="`${isTrue ? 'a' : 'b'}`"></div>
</div>
</template>

Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/vue-bind/bindings.twig
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
<input type="radio" checked>
<img src="{{imageSrc}}">
<div class="a b c"></div>
<div class="category-filter-list categories {{ isSomething ? 'block' }} {{ not isSomething ? 'block2' }}"></div>
</div>
</div>
5 changes: 3 additions & 2 deletions tests/fixtures/vue-bind/bindings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<input type="radio" :checked="true">
<img :src="imageSrc">
<div :class="['a', 'b', 'c']"></div>
</div>
<div :class="{ 'block': isSomething, 'block2': !isSomething}" class="category-filter-list categories"></div>
</div>
</div>
</template>
</template>
23 changes: 23 additions & 0 deletions tests/fixtures/vue-bind/xbinding-props.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<div>
<div>
<p>{{ title }}</p>
<p v-if="req">Boolean</p>
</div>
</div>
</template>

<script>
export default {
props: {
title: {
type: String,
default: 'Default title'
},
req: {
type: Boolean,
required: true,
},
},
}
</script>
3 changes: 3 additions & 0 deletions tests/fixtures/vue-if/if-strict-equal.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
{% if a == 1 %}
<div>Text</div>
{% endif %}
{% if a|length %}
<div>Text</div>
{% endif %}
</div>
1 change: 1 addition & 0 deletions tests/fixtures/vue-if/if-strict-equal.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<div>
<div v-if="a === 1">Text</div>
<div v-if="a.length">Text</div>
</div>
</template>

0 comments on commit 7bc68d0

Please sign in to comment.