Skip to content

Commit 3c24d23

Browse files
authored
Merge pull request #8 from Paneon/develop
Develop
2 parents 806afa6 + fb16b2c commit 3c24d23

File tree

5 files changed

+135
-42
lines changed

5 files changed

+135
-42
lines changed

src/Compiler.php

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use DOMText;
1010
use Exception;
1111
use Paneon\VueToTwig\Models\Replacements;
12+
use Paneon\VueToTwig\Utils\TwigBuilder;
1213
use Psr\Log\LoggerInterface;
1314

1415
class Compiler
@@ -28,11 +29,16 @@ class Compiler
2829

2930
/** @var string[] */
3031
protected $banner;
32+
/**
33+
* @var TwigBuilder
34+
*/
35+
protected $builder;
3136

3237
public function __construct(DOMDocument $document, LoggerInterface $logger)
3338
{
34-
$this->logger = $logger;
39+
$this->builder = new TwigBuilder();
3540
$this->document = $document;
41+
$this->logger = $logger;
3642
$this->lastCloseIf = null;
3743
$this->banner = [];
3844

@@ -77,10 +83,10 @@ public function convert(): string
7783

7884
public function convertNode(DOMNode $node): DOMNode
7985
{
80-
switch($node->nodeType) {
86+
switch ($node->nodeType) {
8187
case XML_TEXT_NODE:
8288
$this->logger->debug('Text node found', ['name' => $node->nodeName]);
83-
// fall through to next case, because we don't need to handle either of these node-types
89+
// fall through to next case, because we don't need to handle either of these node-types
8490
case XML_COMMENT_NODE:
8591
$this->logger->debug('Comment node found', ['name' => $node->nodeName]);
8692
return $node;
@@ -172,11 +178,10 @@ private function handleAttributeBinding(DOMElement $node)
172178
}
173179
$node->setAttribute($name, implode(' ', $classes));
174180
}
175-
}
176-
/*
181+
} /*
177182
* <div :class="`abc ${someDynamicClass}`">
178183
*/
179-
elseif(preg_match('/^`(?P<content>.+)`$/', $value, $matches)) {
184+
elseif (preg_match('/^`(?P<content>.+)`$/', $value, $matches)) {
180185
$templateStringContent = $matches['content'];
181186

182187
$templateStringContent = preg_replace(
@@ -186,8 +191,7 @@ private function handleAttributeBinding(DOMElement $node)
186191
);
187192

188193
$node->setAttribute($name, $templateStringContent);
189-
}
190-
else {
194+
} else {
191195
$this->logger->warning('- No Handling for: '.$value);
192196
}
193197

@@ -209,11 +213,11 @@ private function handleIf(DOMElement $node): void
209213
$condition = $this->sanitizeCondition($condition);
210214

211215
// Open with if
212-
$openIf = $this->document->createTextNode('{% if '.$condition.' %}');
216+
$openIf = $this->document->createTextNode($this->builder->createIf($condition));
213217
$node->parentNode->insertBefore($openIf, $node);
214218

215219
// Close with endif
216-
$closeIf = $this->document->createTextNode('{% endif %}');
220+
$closeIf = $this->document->createTextNode($this->builder->createEndIf());
217221
$node->parentNode->insertBefore($closeIf, $node->nextSibling);
218222

219223
$this->lastCloseIf = $closeIf;
@@ -224,20 +228,20 @@ private function handleIf(DOMElement $node): void
224228
$condition = $this->sanitizeCondition($condition);
225229

226230
// Replace old endif with else
227-
$this->lastCloseIf->textContent = '{% elseif '.$condition.' %}';
231+
$this->lastCloseIf->textContent = $this->builder->createElseIf($condition);
228232

229233
// Close with new endif
230-
$closeIf = $this->document->createTextNode('{% endif %}');
234+
$closeIf = $this->document->createTextNode($this->builder->createEndIf());
231235
$node->parentNode->insertBefore($closeIf, $node->nextSibling);
232236
$this->lastCloseIf = $closeIf;
233237

234238
$node->removeAttribute('v-else-if');
235239
} elseif ($node->hasAttribute('v-else')) {
236240
// Replace old endif with else
237-
$this->lastCloseIf->textContent = '{% else %}';
241+
$this->lastCloseIf->textContent = $this->builder->createElse();
238242

239243
// Close with new endif
240-
$closeIf = $this->document->createTextNode('{% endif %}');
244+
$closeIf = $this->document->createTextNode($this->builder->createEndIf());
241245
$node->parentNode->insertBefore($closeIf, $node->nextSibling);
242246
$this->lastCloseIf = $closeIf;
243247

@@ -268,7 +272,7 @@ private function handleFor(DOMElement $node)
268272
}
269273

270274
// (1)
271-
$forCommand = '{% for '.$forLeft.' in '.$listName.' %}';
275+
$forCommand = $this->builder->createForItemInList($forLeft, $listName);
272276

273277
if (strpos($forLeft, ',')) {
274278
$forLeft = str_replace('(', '', $forLeft);
@@ -281,19 +285,19 @@ private function handleFor(DOMElement $node)
281285
$forIndex = $forLeftArray[2] ?? null;
282286

283287
// (3)
284-
$forCommand = '{% for '.$forKey.', '.$forValue.' in '.$listName.' %}';
288+
$forCommand = $this->builder->createFor($listName, $forValue, $forKey);
285289

286290
if ($forIndex) {
287291
// (4)
288-
$forCommand .= ' {% set '.$forIndex.' = loop.index0 %}';
292+
$forCommand .= $this->builder->createVariable($forIndex, 'loop.index0');
289293
}
290294
}
291295

292296
$startFor = $this->document->createTextNode($forCommand);
293297
$node->parentNode->insertBefore($startFor, $node);
294298

295299
// End For
296-
$endFor = $this->document->createTextNode('{% endfor %}');
300+
$endFor = $this->document->createTextNode($this->builder->createEndFor());
297301
$node->parentNode->insertBefore($endFor, $node->nextSibling);
298302

299303
$node->removeAttribute('v-for');
@@ -324,11 +328,9 @@ private function getRootNode(DOMElement $element): \DOMNode
324328
foreach ($nodes as $node) {
325329
if ($node->nodeType === XML_TEXT_NODE) {
326330
continue;
327-
}
328-
elseif(in_array($node->nodeName, ['script', 'style'])) {
331+
} elseif (in_array($node->nodeName, ['script', 'style'])) {
329332
continue;
330-
}
331-
else {
333+
} else {
332334
$tagNodes++;
333335
$firstTagNode = $node;
334336
}
@@ -364,7 +366,7 @@ protected function replacePlaceholders(string $string)
364366

365367
protected function addSingleLineBanner(string $html)
366368
{
367-
return '{# '.implode('', $this->banner).' #}'."\n".$html;
369+
return $this->builder->createComment(implode('', $this->banner))."\n".$html;
368370
}
369371

370372
protected function addBanner(string $html)

src/Utils/TwigBuilder.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
namespace Paneon\VueToTwig\Utils;
4+
5+
class TwigBuilder
6+
{
7+
protected const OPEN = 0;
8+
protected const CLOSE = 1;
9+
10+
protected $options;
11+
12+
public function __construct(array $options = [])
13+
{
14+
$this->options = array_merge([
15+
'tag_comment' => ['{#', '#}'],
16+
'tag_block' => ['{%', '%}'],
17+
'tag_variable' => ['{{', '}}'],
18+
'whitespace_trim' => '-',
19+
'interpolation' => ['#{', '}'],
20+
], $options);
21+
}
22+
23+
public function createVariable($name, $assignment)
24+
{
25+
return $this->createBlock('set '.$name.' = '.$assignment);
26+
}
27+
28+
public function createIf(string $condition)
29+
{
30+
return $this->createBlock('if '.$condition);
31+
}
32+
33+
public function createElseIf(string $condition)
34+
{
35+
return $this->createBlock('elseif '.$condition);
36+
}
37+
38+
public function createElse()
39+
{
40+
return $this->createBlock('else');
41+
}
42+
43+
public function createEndIf()
44+
{
45+
return $this->createBlock('endif');
46+
}
47+
48+
public function createForItemInList(string $item, string $list)
49+
{
50+
return $this->createBlock('for '.$item.' in '.$list);
51+
}
52+
53+
public function createForKeyInList(string $key, string $list)
54+
{
55+
return $this->createBlock('for '.$key.' in '.$list);
56+
}
57+
58+
public function createFor(string $list, ?string $item = null, ?string $key = null)
59+
{
60+
if($item !== null && $key !== null) {
61+
return $this->createBlock( 'for '.$key.', '.$item.' in '.$list);
62+
}
63+
elseif($item !== null) {
64+
return $this->createForItemInList($item, $list);
65+
}
66+
elseif($key !== null) {
67+
return $this->createForKeyInList($key, $list);
68+
}
69+
70+
return null;
71+
}
72+
73+
public function createEndFor()
74+
{
75+
return $this->createBlock('endfor');
76+
}
77+
78+
public function createComment(string $comment)
79+
{
80+
return $this->options['tag_comment'][self::OPEN].' '.$comment.' '.$this->options['tag_comment'][self::CLOSE];
81+
}
82+
83+
public function createMultilineComment(array $comments)
84+
{
85+
return $this->options['tag_comment'][self::OPEN].' '.$comments.' '.$this->options['tag_comment'][self::CLOSE];
86+
}
87+
88+
public function createBlock($content)
89+
{
90+
return $this->options['tag_block'][self::OPEN].' '.$content.' '.$this->options['tag_block'][self::CLOSE];
91+
}
92+
}

tests/AbstractTestCase.php

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
use DirectoryIterator;
66
use DOMDocument;
7-
use Paneon\VueToTwig\Compiler;
87
use Monolog\Handler\StreamHandler;
98
use Monolog\Logger;
9+
use Paneon\VueToTwig\Compiler;
1010

1111
abstract class AbstractTestCase extends \PHPUnit\Framework\TestCase
1212
{
@@ -21,18 +21,17 @@ protected function createCompiler(string $template): Compiler
2121
protected function createLogger(): Logger
2222
{
2323
$logger = new Logger('test');
24-
$logger->pushHandler(new StreamHandler(__DIR__ . '/../var/dev/test.log'));
24+
$logger->pushHandler(new StreamHandler(__DIR__.'/../var/dev/test.log'));
2525

2626
return $logger;
2727
}
2828

29-
30-
protected function assertEqualHtml($expectedResult, $result): void
29+
protected function assertEqualHtml($expected, $actual)
3130
{
32-
$expectedResult = $this->normalizeHtml($expectedResult);
33-
$result = $this->normalizeHtml($result);
34-
35-
$this->assertEquals($expectedResult, $result);
31+
$this->assertEquals(
32+
$this->normalizeHtml($expected),
33+
$this->normalizeHtml($actual)
34+
);
3635
}
3736

3837
protected function createDocumentWithHtml(string $html): DOMDocument
@@ -45,22 +44,23 @@ protected function createDocumentWithHtml(string $html): DOMDocument
4544

4645
protected function normalizeHtml($html): string
4746
{
48-
$html = preg_replace('/<!--.*?-->/', '', $html);
49-
$html = preg_replace('/\s+/', ' ', $html);
47+
$html = preg_replace('/(\s)+/s', '\\1', $html);
5048

5149
// Trim node text
52-
$html = str_replace('> ', ">", $html);
53-
$html = str_replace(' <', "<", $html);
50+
$html = preg_replace('/\>[^\S ]+/s', ">", $html);
51+
$html = preg_replace('/[^\S ]+\</s', "<", $html);
5452

55-
// Remove duplicated new lines
56-
$html = str_replace("\n\n", "\n", $html);
53+
$html = preg_replace('/> </s', '><', $html);
54+
$html = preg_replace('/} </s', '}<', $html);
55+
$html = preg_replace('/> {/s', '>{', $html);
56+
$html = preg_replace('/} {/s', '}{', $html);
5757

58-
return trim($html);
58+
return $html;
5959
}
6060

6161
protected function loadFixturesFromDir(string $dir): array
6262
{
63-
$fixtureDir = __DIR__ . '/fixtures/' . $dir;
63+
$fixtureDir = __DIR__.'/fixtures/'.$dir;
6464

6565
$cases = [];
6666

tests/CompilerTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ public function setBannerWithSingleLineAddsBannerCommentToTheTopOfTheTwigFile()
3434
public function setBannerAddsMultipleCommentsToTheTopOfTheTwigFile()
3535
{
3636
$html = '<template><div>{{ someVariable }}</div></template>';
37-
$expected = '
38-
{#
37+
$expected = '{#
3938
# This file was generated using VueToTwig
4039
# Source: assets/js/SomeComponent.vue
4140
#}

tests/fixtures/vue-bind/bindings.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
<input type="radio" checked>
44
<img src="{{imageSrc}}">
55
</div>
6-
</div>
6+
</div>

0 commit comments

Comments
 (0)