Skip to content

Commit 7bc68d0

Browse files
authored
Merge pull request #18 from Paneon/feature/required-props
Add support for dynamic classes using object binding
2 parents e1c8391 + a4aa825 commit 7bc68d0

File tree

10 files changed

+73
-31
lines changed

10 files changed

+73
-31
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
# PHPUnit
1010
.phpcs-cache
1111

12+
node_modules

src/Compiler.php

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,9 @@ public function convert(): string
9292
public function convertNode(DOMNode $node): DOMNode
9393
{
9494
switch ($node->nodeType) {
95+
// We don't need to handle either of these node-types
9596
case XML_TEXT_NODE:
96-
$this->logger->debug('Text node found', ['name' => $node->nodeName]);
97-
// fall through to next case, because we don't need to handle either of these node-types
9897
case XML_COMMENT_NODE:
99-
$this->logger->debug('Comment node found', ['name' => $node->nodeName]);
10098
return $node;
10199
case XML_ELEMENT_NODE:
102100
/** @var DOMElement $node */
@@ -184,25 +182,29 @@ private function handleAttributeBinding(DOMElement $node)
184182
switch ($name) {
185183
case 'key':
186184
// Not necessary in twig
187-
$this->logger->debug('- skip: key');
188185
return;
189186
case 'style':
190187
break;
191188
case 'class':
192189
break;
193190
}
194191

192+
$regexArrayBinding = '/^\[([^\]]+)\]$/';
193+
$regexArrayElements = '/((?:[\'"])(?<elements>[^\'"])[\'"])/';
194+
$regexTemplateString = '/^`(?P<content>.+)`$/';
195+
$regexObjectBinding = '/^\{(?<elements>[^\}]+)\}$/';
196+
$regexObjectElements = '/["\']?(?<class>[^"\']+)["\']?:\s*(?<condition>[^,]+)/x';
197+
195198
if ($value === 'true') {
196199
$this->logger->debug('- setAttribute ' . $name);
197200
$node->setAttribute($name, $name);
198-
} elseif (preg_match('/^\[([^\]]+)\]$/', $value, $matches)) {
199-
$this->logger->debug('- is array '.$value);
201+
} elseif (preg_match($regexArrayBinding, $value, $matches)) {
202+
$this->logger->debug('- array binding ', ['value' => $value]);
200203

201-
if(preg_match_all('/((?:[\'"])(?<elements>[^\'"])[\'"])/', $value, $arrayMatch)){
204+
if (preg_match_all($regexArrayElements, $value, $arrayMatch)) {
202205
$value = $arrayMatch['elements'];
203206
$this->logger->debug('- ', ['match' => $arrayMatch]);
204-
}
205-
else {
207+
} else {
206208
$value = [];
207209
}
208210

@@ -218,8 +220,23 @@ private function handleAttributeBinding(DOMElement $node)
218220
$dynamicValues[] = $className;
219221
}
220222
}
221-
}
222-
elseif (preg_match('/^`(?P<content>.+)`$/', $value, $matches)) {
223+
} elseif (preg_match($regexObjectBinding, $value, $matches)) {
224+
$this->logger->debug('- object binding ', ['value' => $value]);
225+
226+
$items = explode(',', $matches['elements']);
227+
$this->logger->debug(print_r($items,true));
228+
229+
foreach ($items as $item) {
230+
if(preg_match($regexObjectElements, $item, $matchElement)){
231+
$dynamicValues[] = sprintf(
232+
'{{ %s ? \'%s\' }}',
233+
$this->builder->refactorCondition($matchElement['condition']),
234+
$matchElement['class']
235+
);
236+
}
237+
}
238+
239+
} elseif (preg_match($regexTemplateString, $value, $matches)) {
223240
/*
224241
* <div :class="`abc ${someDynamicClass}`">
225242
*/
@@ -262,7 +279,6 @@ private function handleIf(DOMElement $node): void
262279
} else {
263280
$condition = $node->getAttribute('v-if');
264281
}
265-
$condition = $this->sanitizeCondition($condition);
266282

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

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

405-
protected function sanitizeCondition(string $condition)
406-
{
407-
$condition = str_replace('&&', 'and', $condition);
408-
$condition = str_replace('||', 'or', $condition);
409-
$condition = str_replace('!==', '!=', $condition);
410-
$condition = preg_replace('/!([^=])/', 'not $1', $condition);
411-
412-
foreach (Replacements::getConstants() as $constant => $value) {
413-
$condition = str_replace($value, Replacements::getSanitizedConstant($constant), $condition);
414-
}
415-
416-
return $condition;
417-
}
418-
419420
protected function implodeAttributeValue(string $attribute, array $values, string $oldValue): string
420421
{
421422
$glue = ' ';
422423

423-
if($attribute === 'style') {
424+
if ($attribute === 'style') {
424425
$glue = '; ';
425426
}
426427

427-
if(!empty($oldValue)) {
428+
if (!empty($oldValue)) {
428429
$values = array_merge([$oldValue], $values);
429430
}
430431

src/Utils/TwigBuilder.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Paneon\VueToTwig\Utils;
44

5+
use Paneon\VueToTwig\Models\Replacements;
56
use Paneon\VueToTwig\Property;
67

78
class TwigBuilder
@@ -135,6 +136,14 @@ public function refactorCondition(string $condition): string
135136
{
136137
$condition = str_replace('===', '==', $condition);
137138
$condition = str_replace('!==', '!=', $condition);
139+
$condition = str_replace('&&', 'and', $condition);
140+
$condition = str_replace('||', 'or', $condition);
141+
$condition = preg_replace('/!([^=])/', 'not $1', $condition);
142+
$condition = str_replace('.length', '|length', $condition);
143+
144+
foreach (Replacements::getConstants() as $constant => $value) {
145+
$condition = str_replace($value, Replacements::getSanitizedConstant($constant), $condition);
146+
}
138147

139148
return $condition;
140149
}

tests/fixtures/vue-bind/binding-with-template-string.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
<div class="block block--{{ modifier }}" style="fill: {{ color }}">
33
Hello World
44
</div>
5+
<div class="{{ isTrue ? 'a' : 'b' }}"></div>
56
</div>

tests/fixtures/vue-bind/binding-with-template-string.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<div :class="`block block--${modifier}`" :style="`fill: ${color}`">
44
Hello World
55
</div>
6+
<div :class="`${isTrue ? 'a' : 'b'}`"></div>
67
</div>
78
</template>
89

tests/fixtures/vue-bind/bindings.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
<input type="radio" checked>
44
<img src="{{imageSrc}}">
55
<div class="a b c"></div>
6+
<div class="category-filter-list categories {{ isSomething ? 'block' }} {{ not isSomething ? 'block2' }}"></div>
67
</div>
78
</div>

tests/fixtures/vue-bind/bindings.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<input type="radio" :checked="true">
55
<img :src="imageSrc">
66
<div :class="['a', 'b', 'c']"></div>
7-
</div>
7+
<div :class="{ 'block': isSomething, 'block2': !isSomething}" class="category-filter-list categories"></div>
8+
</div>
89
</div>
9-
</template>
10+
</template>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<template>
2+
<div>
3+
<div>
4+
<p>{{ title }}</p>
5+
<p v-if="req">Boolean</p>
6+
</div>
7+
</div>
8+
</template>
9+
10+
<script>
11+
export default {
12+
props: {
13+
title: {
14+
type: String,
15+
default: 'Default title'
16+
},
17+
req: {
18+
type: Boolean,
19+
required: true,
20+
},
21+
},
22+
}
23+
</script>

tests/fixtures/vue-if/if-strict-equal.twig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
{% if a == 1 %}
33
<div>Text</div>
44
{% endif %}
5+
{% if a|length %}
6+
<div>Text</div>
7+
{% endif %}
58
</div>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<template>
22
<div>
33
<div v-if="a === 1">Text</div>
4+
<div v-if="a.length">Text</div>
45
</div>
56
</template>

0 commit comments

Comments
 (0)