Skip to content

Commit d2d9c21

Browse files
authored
Merge pull request #27 from Paneon/master
Update master
2 parents e544453 + 8b09205 commit d2d9c21

15 files changed

+407
-1
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"php": ">=7.1",
1414
"ext-dom": "*",
1515
"ext-libxml": "*",
16+
"scssphp/scssphp": "1.1.1",
1617
"squizlabs/php_codesniffer": "^3.3",
1718
"ramsey/uuid": "^3.8"
1819
},

composer.lock

Lines changed: 62 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compiler.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Paneon\VueToTwig\Models\Replacements;
1717
use Paneon\VueToTwig\Models\Slot;
1818
use Paneon\VueToTwig\Utils\NodeHelper;
19+
use Paneon\VueToTwig\Utils\StyleBuilder;
1920
use Paneon\VueToTwig\Utils\TwigBuilder;
2021
use Psr\Log\LoggerInterface;
2122
use ReflectionException;
@@ -53,6 +54,11 @@ class Compiler
5354
*/
5455
protected $builder;
5556

57+
/**
58+
* @var StyleBuilder
59+
*/
60+
protected $styleBuilder;
61+
5662
/**
5763
* @var NodeHelper
5864
*/
@@ -94,6 +100,7 @@ class Compiler
94100
public function __construct(DOMDocument $document, LoggerInterface $logger)
95101
{
96102
$this->builder = new TwigBuilder();
103+
$this->styleBuilder = new StyleBuilder();
97104
$this->nodeHelper = new NodeHelper();
98105
$this->document = $document;
99106
$this->logger = $logger;
@@ -130,6 +137,8 @@ public function convert(): string
130137
/** @var DOMElement|null $scriptElement */
131138
$scriptElement = $this->document->getElementsByTagName('script')->item(0);
132139

140+
$styleBlocks = $this->document->getElementsByTagName('style');
141+
133142
$twigBlocks = $this->document->getElementsByTagName('twig');
134143

135144
if ($scriptElement) {
@@ -144,6 +153,13 @@ public function convert(): string
144153
}
145154
}
146155

156+
if ($styleBlocks->length) {
157+
foreach ($styleBlocks as $styleBlock) {
158+
/* @var DOMElement $styleBlock */
159+
$this->rawBlocks[] = $this->styleBuilder->compile($styleBlock);
160+
}
161+
}
162+
147163
if (!$templateElement) {
148164
throw new Exception('The template file does not contain a template tag.');
149165
}
@@ -203,6 +219,7 @@ public function convertNode(DOMNode $node, int $level = 0): DOMNode
203219
$this->stripEventHandlers($node);
204220
$this->handleSlots($node);
205221
$this->cleanupAttributes($node);
222+
$this->addScopedAttribute($node);
206223
}
207224

208225
// Registered Component
@@ -849,6 +866,13 @@ public function disableStyleInclude(): Compiler
849866
return $this;
850867
}
851868

869+
public function setStyleBlockOutputType(int $outputType): Compiler
870+
{
871+
$this->styleBuilder->setOutputType($outputType);
872+
873+
return $this;
874+
}
875+
852876
/**
853877
* @param mixed $value
854878
*/
@@ -997,4 +1021,13 @@ private function twigRemove(DOMElement $node): bool
9971021

9981022
return false;
9991023
}
1024+
1025+
private function addScopedAttribute(DOMElement $node): void
1026+
{
1027+
if (!$this->styleBuilder->hasScoped()) {
1028+
return;
1029+
}
1030+
$scopedAttribute = $this->styleBuilder->getScopedAttribute();
1031+
$node->setAttributeNode(new DOMAttr($scopedAttribute, ''));
1032+
}
10001033
}

src/Utils/StyleBuilder.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Paneon\VueToTwig\Utils;
6+
7+
use DOMElement;
8+
use Exception;
9+
use Ramsey\Uuid\Uuid;
10+
use ScssPhp\ScssPhp\Compiler as ScssCompiler;
11+
12+
class StyleBuilder
13+
{
14+
public const STYLE_NO = 0;
15+
public const STYLE_SCOPED = 1;
16+
public const STYLE = 2;
17+
public const STYLE_ALL = 3;
18+
19+
/**
20+
* @var int
21+
*/
22+
private $outputType;
23+
24+
/**
25+
* @var ScssCompiler|null
26+
*/
27+
private $scssCompiler;
28+
29+
/**
30+
* @var bool
31+
*/
32+
private $hasScoped;
33+
34+
/**
35+
* @var string|null
36+
*/
37+
private $scopedAttribute;
38+
39+
/**
40+
* StyleBuilder constructor.
41+
*
42+
* @throws Exception
43+
*/
44+
public function __construct()
45+
{
46+
$this->outputType = self::STYLE_ALL;
47+
$this->scssCompiler = null;
48+
$this->hasScoped = false;
49+
$this->scopedAttribute = 'data-v-' . substr(md5(Uuid::uuid4()->toString()), 0, 8);
50+
}
51+
52+
public function setOutputType(int $outputType): void
53+
{
54+
$this->outputType = $outputType;
55+
}
56+
57+
public function compile(?DOMElement $styleElement): ?string
58+
{
59+
if (!$styleElement instanceof DOMElement
60+
|| ($styleElement->hasAttribute('scoped') && !($this->outputType & self::STYLE_SCOPED))
61+
|| (!$styleElement->hasAttribute('scoped') && !($this->outputType & self::STYLE))) {
62+
return null;
63+
}
64+
65+
$style = $styleElement->textContent;
66+
67+
if ($styleElement->hasAttribute('lang') && $styleElement->getAttribute('lang') === 'scss') {
68+
if ($this->scssCompiler === null) {
69+
$this->scssCompiler = new ScssCompiler();
70+
}
71+
$style = $this->scssCompiler->compile($style);
72+
}
73+
74+
if ($styleElement->hasAttribute('scoped')) {
75+
$this->hasScoped = true;
76+
$style = preg_replace('/((?:^|[^},]*?)\S+)(\s*[{,])/i', '$1[' . $this->scopedAttribute . ']$2', $style);
77+
}
78+
79+
return '<style>' . $style . '</style>';
80+
}
81+
82+
public function hasScoped(): ?bool
83+
{
84+
return $this->hasScoped;
85+
}
86+
87+
public function getScopedAttribute(): string
88+
{
89+
return $this->scopedAttribute;
90+
}
91+
}

tests/CompilerStyleBlockTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Paneon\VueToTwig\Tests;
4+
5+
use Exception;
6+
7+
class CompilerStyleBlockTest extends AbstractTestCase
8+
{
9+
/**
10+
* @dataProvider dataProvider
11+
*
12+
* @param mixed $html
13+
* @param mixed $expected
14+
*
15+
* @throws Exception
16+
*/
17+
public function testStyleBlock($html, $expected)
18+
{
19+
$compiler = $this->createCompiler($html);
20+
21+
$actual = $compiler->convert();
22+
23+
$actual = preg_replace('/data-v-[0-9a-z]{8}/', 'data-v-12345678', $actual);
24+
25+
$this->assertEqualHtml($expected, $actual);
26+
}
27+
28+
/**
29+
* @return array
30+
*/
31+
public function dataProvider()
32+
{
33+
return $this->loadFixturesFromDir('style-block');
34+
}
35+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<style>
2+
.foo[data-v-12345678] {
3+
color: red;
4+
}
5+
.bar[data-v-12345678],
6+
.baz[data-v-12345678] {
7+
color: blue;
8+
}
9+
.foo:after[data-v-12345678] {
10+
display: none;
11+
}
12+
.root .bar[data-v-12345678] {
13+
text-decoration: underline;
14+
}
15+
</style>
16+
<div class="root {{ class|default('') }}" data-v-12345678="" style="{{ style|default('') }}">
17+
<div class="foo" data-v-12345678="">
18+
foo
19+
</div>
20+
<div class="bar" data-v-12345678="">
21+
bar
22+
</div>
23+
<div class="baz" data-v-12345678="">
24+
baz
25+
</div>
26+
</div>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<template>
2+
<div class="root">
3+
<div class="foo">
4+
foo
5+
</div>
6+
<div class="bar">
7+
bar
8+
</div>
9+
<div class="baz">
10+
baz
11+
</div>
12+
</div>
13+
</template>
14+
15+
<style scoped>
16+
.foo {
17+
color: red;
18+
}
19+
.bar,
20+
.baz {
21+
color: blue;
22+
}
23+
.foo:after {
24+
display: none;
25+
}
26+
.root .bar {
27+
text-decoration: underline;
28+
}
29+
</style>
30+
31+
<script>
32+
export default {
33+
}
34+
</script>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<style>.foo[data-v-12345678] { color: red; } .foo__bar[data-v-12345678] { color: blue; } .foo__baz[data-v-12345678] { color: #00FF00; }</style>
2+
<div data-v-12345678="" class="{{ class|default('') }}" style="{{ style|default('') }}">
3+
<div class="foo__bar" data-v-12345678="">
4+
baz
5+
</div>
6+
</div>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<template>
2+
<div>
3+
<div class="foo__bar">
4+
baz
5+
</div>
6+
</div>
7+
</template>
8+
9+
<style lang="scss" scoped>
10+
$green: #00FF00;
11+
.foo {
12+
color: red;
13+
&__bar {
14+
color: blue;
15+
}
16+
&__baz {
17+
color: $green;
18+
}
19+
}
20+
</style>
21+
22+
<script>
23+
export default {
24+
}
25+
</script>

0 commit comments

Comments
 (0)