Skip to content

Commit e544453

Browse files
authored
Merge pull request #26 from Paneon/master
Update master
2 parents 4e0a047 + d1e463a commit e544453

15 files changed

+389
-41
lines changed

README.md

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,50 @@ Compile vue files to twig templates with PHP
3838

3939
It's difficult to interpret JavaScript language features and translate them into twig.
4040

41-
For example string concatenation inside attribute binding does not work currently: :no_entry_sign:
41+
For example, string concatenation within attribute binding is not currently working properly: :no_entry_sign:
42+
43+
This example works:
4244

4345
```vue
44-
<div :style="{ fontSize: size + 'px' }"></div>
46+
<template>
47+
<div :style="'fontSize: ' + (size + 10) + 'px'"></div>
48+
</template>
49+
50+
<script>
51+
export default {
52+
props: {
53+
size: {
54+
type: number,
55+
required: true,
56+
},
57+
},
58+
};
59+
</script>
4560
```
4661

47-
But if you move this into a single property like (A) or (B), it will work.
62+
```twig
63+
<div style="{{ 'fontSize: ' ~ (size + 10) ~ 'px' }};"></div>
64+
```
65+
66+
But this example doesn't work correct:
4867

4968
```vue
50-
<!-- (A) -->
51-
<div :style="divStyleProperty"></div>
69+
<template>
70+
<div :style="'fontSize: ' + (foo.size + 10) + 'px'"></div>
71+
</template>
5272
53-
<!-- (B) -->
54-
<div :style="{ fontSize: fontSizeVariable }"></div>
73+
<script>
74+
export default {
75+
props: {
76+
foo: {
77+
type: object,
78+
required: true,
79+
},
80+
},
81+
};
82+
</script>
5583
```
84+
85+
```twig
86+
<div style="{{ 'fontSize: ' ~ (foo.size ~ 10) ~ 'px' }};"></div>
87+
```

src/Compiler.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ public function convert(): string
165165
$html = preg_replace('/<template>\s*(.*)\s*<\/template>/ism', '$1', $html);
166166
$html = preg_replace('/<\/?template[^>]*?>/i', '', $html);
167167

168+
$html = $this->builder->concatConvertHandler($html, $this->properties);
169+
168170
if ($this->stripWhitespace) {
169171
$html = $this->stripWhitespace($html);
170172
}
@@ -350,6 +352,10 @@ public function registerProperties(DOMElement $scriptElement): void
350352
$property->setIsRequired(true);
351353
}
352354

355+
if (preg_match('/type:\s*([a-z]+)/m', $definition, $matchType)) {
356+
$property->setType($matchType[1]);
357+
}
358+
353359
if (preg_match('/default:\s*(?<default>[^,$]+)\s*,?/mx', $definition, $matchDefault)) {
354360
$property->setDefault(trim($matchDefault['default']));
355361
}
@@ -358,13 +364,16 @@ public function registerProperties(DOMElement $scriptElement): void
358364
}
359365
}
360366

361-
$typeScriptRegexProps = '/\@Prop\(.*?default\s*\:\s*(?<defaultValue>\'(?:[^\n](?!(?<![\\\\])\'))*.?\'|"(?:[^\n](?!(?<![\\\\])"))*.?"|[a-zA-Z0-9_]+).*?\)[^;]*?(?<propName>[a-zA-Z0-9_$]+)\!?\:[^;\@]*;/msx';
362-
367+
$typeScriptRegexProps = '/\@Prop\s*\({(?<propOptions>.*?)}\)[^;]*?(?<propName>[a-zA-Z0-9_$]+)\!?\:\s*(?<propType>[a-zA-Z]+)[^;\@]*;/msx';
368+
$typeScriptRegexDefault = '/default\s*\:\s*(?<defaultValue>\'(?:.(?!(?<![\\\\])\'))*.?\'|"(?:.(?!(?<![\\\\])"))*.?"|[a-zA-Z0-9_]+)/msx';
363369
if (preg_match_all($typeScriptRegexProps, $content, $typeScriptMatches, PREG_SET_ORDER)) {
364370
$this->properties = [];
365371
foreach ($typeScriptMatches as $typeScriptMatch) {
366372
$property = new Property($typeScriptMatch['propName'], '', true);
367-
$property->setDefault(trim($typeScriptMatch['defaultValue']));
373+
if (preg_match($typeScriptRegexDefault, $typeScriptMatch['propOptions'], $defaultMatch)) {
374+
$property->setDefault(trim($defaultMatch['defaultValue']));
375+
}
376+
$property->setType(trim($typeScriptMatch['propType']));
368377
$this->properties[$typeScriptMatch['propName']] = $property;
369378
}
370379
}

src/Models/Concat.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Paneon\VueToTwig\Models;
6+
7+
use Exception;
8+
use Ramsey\Uuid\Uuid;
9+
10+
class Concat
11+
{
12+
public const CONCAT_REGEX = '/__CONCAT_[a-f0-9]{8}_[a-f0-9]{4}_[a-f0-9]{4}_[a-f0-9]{4}_[a-f0-9]{12}__/';
13+
14+
/**
15+
* @var string
16+
*/
17+
protected $uuid;
18+
19+
/**
20+
* @var string
21+
*/
22+
protected $value;
23+
24+
/**
25+
* @var bool
26+
*/
27+
protected $isNumeric;
28+
29+
/**
30+
* Slot constructor.
31+
*
32+
* @throws Exception
33+
*/
34+
public function __construct(string $value, bool $isNumeric)
35+
{
36+
$this->uuid = Uuid::uuid4()->toString();
37+
$this->value = $value;
38+
$this->isNumeric = $isNumeric;
39+
}
40+
41+
public function getValue(): string
42+
{
43+
return $this->value;
44+
}
45+
46+
public function setValue(string $value): void
47+
{
48+
$this->value = $value;
49+
}
50+
51+
public function isNumeric(): bool
52+
{
53+
return $this->isNumeric;
54+
}
55+
56+
public function setIsNumeric(bool $isNumeric): void
57+
{
58+
$this->isNumeric = $isNumeric;
59+
}
60+
61+
public function getConcatContentVariableString(): string
62+
{
63+
return '__CONCAT_' . str_replace('-', '_', $this->uuid) . '__';
64+
}
65+
66+
public function getUuid(): string
67+
{
68+
return $this->uuid;
69+
}
70+
}

src/Models/Property.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ class Property
3131
*/
3232
protected $default;
3333

34+
/**
35+
* @var string|null
36+
*/
37+
protected $type;
38+
3439
/**
3540
* Property constructor.
3641
*/
@@ -85,4 +90,14 @@ public function setDefault(string $default): void
8590
{
8691
$this->default = $default;
8792
}
93+
94+
public function getType(): ?string
95+
{
96+
return $this->type;
97+
}
98+
99+
public function setType(?string $type): void
100+
{
101+
$this->type = $type;
102+
}
88103
}

src/Utils/TwigBuilder.php

Lines changed: 115 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Paneon\VueToTwig\Utils;
66

7+
use Exception;
8+
use Paneon\VueToTwig\Models\Concat;
79
use Paneon\VueToTwig\Models\Property;
810
use Paneon\VueToTwig\Models\Replacements;
911
use ReflectionException;
@@ -18,6 +20,11 @@ class TwigBuilder
1820
*/
1921
protected $options;
2022

23+
/**
24+
* @var Concat[]
25+
*/
26+
protected $concat = [];
27+
2128
/**
2229
* TwigBuilder constructor.
2330
*
@@ -231,8 +238,6 @@ private function refactorConditionPart(string $condition): string
231238
$condition = str_replace('.length', '|length', $condition);
232239
$condition = str_replace('.trim', '|trim', $condition);
233240

234-
// $condition = $this->convertConcat($condition);
235-
236241
foreach (Replacements::getConstants() as $constant => $value) {
237242
$condition = str_replace($value, Replacements::getSanitizedConstant($constant), $condition);
238243
}
@@ -279,33 +284,6 @@ public function refactorTextNode(string $content): string
279284
return $refactoredContent;
280285
}
281286

282-
public function convertConcat(string $content): string
283-
{
284-
if (preg_match_all('/(\S*)(\s*\+\s*(\S+))+/', $content, $matches, PREG_SET_ORDER)) {
285-
foreach ($matches as $match) {
286-
$parts = explode('+', $match[0]);
287-
$lastPart = null;
288-
$convertedContent = '';
289-
foreach ($parts as $part) {
290-
$part = trim($part);
291-
if ($lastPart !== null) {
292-
if (is_numeric($lastPart) && is_numeric($part)) {
293-
$convertedContent .= ' + ' . $part;
294-
} else {
295-
$convertedContent .= ' ~ ' . $part;
296-
}
297-
} else {
298-
$convertedContent = $part;
299-
}
300-
$lastPart = $part;
301-
}
302-
$content = str_replace($match[0], $convertedContent, $content);
303-
}
304-
}
305-
306-
return $content;
307-
}
308-
309287
private function convertTemplateString(string $content): string
310288
{
311289
if (preg_match_all('/`([^`]+)`/', $content, $matches, PREG_SET_ORDER)) {
@@ -325,7 +303,7 @@ public function createVariableOutput(string $varName, ?string $fallbackVariableN
325303
return '{{ ' . $varName . '|default(' . $fallbackVariableName . ') }}';
326304
}
327305

328-
return '{{ ' . $varName . ' }}';
306+
return '{{ ' . $varName . '|default(\'\') }}';
329307
}
330308

331309
public function prepareBindingOutput(string $value, bool $twigOutput = true): string
@@ -340,4 +318,111 @@ public function prepareBindingOutput(string $value, bool $twigOutput = true): st
340318

341319
return $open . ' ' . $value . ' ' . $close;
342320
}
321+
322+
/**
323+
* @param Property[] $properties
324+
*
325+
* @throws Exception
326+
*/
327+
public function concatConvertHandler(string $content, array $properties): string
328+
{
329+
preg_match_all('/{{(.*?)}}/sm', $content, $outputTerms);
330+
foreach ($outputTerms[1] as $outputTerm) {
331+
$oldOutputTerm = $outputTerm;
332+
333+
while (preg_match('/\(([^()]*)\)/', $outputTerm, $chambersTerm)) {
334+
$outputTerm = str_replace(
335+
'(' . $chambersTerm[1] . ')',
336+
$this->convertConcat($chambersTerm[1], $properties),
337+
$outputTerm
338+
);
339+
}
340+
341+
$concat = $this->replaceConcatCharacter($outputTerm, $properties);
342+
$newOutputTerm = $concat->getValue() ?? '';
343+
344+
while (preg_match_all(Concat::CONCAT_REGEX, $newOutputTerm, $chambersTerms)) {
345+
foreach ($chambersTerms[0] as $chambersTerm) {
346+
$newOutputTerm = str_replace(
347+
$chambersTerm,
348+
$this->concat[$chambersTerm]->getValue(),
349+
$newOutputTerm
350+
);
351+
}
352+
}
353+
354+
$content = str_replace('{{' . $oldOutputTerm . '}}', '{{' . $newOutputTerm . '}}', $content);
355+
356+
$this->concat = [];
357+
}
358+
359+
return $content;
360+
}
361+
362+
/**
363+
* @param Property[] $properties
364+
*
365+
* @throws Exception
366+
*/
367+
private function convertConcat(string $content, array $properties): string
368+
{
369+
$concat = $this->replaceConcatCharacter($content, $properties);
370+
371+
$concat->setValue('(' . $concat->getValue() . ')');
372+
373+
$concatId = $concat->getConcatContentVariableString();
374+
$this->concat[$concatId] = $concat;
375+
376+
return $concatId;
377+
}
378+
379+
/**
380+
* @param Property[] $properties
381+
*
382+
* @throws Exception
383+
*/
384+
private function replaceConcatCharacter(string $content, array $properties): Concat
385+
{
386+
$parts = explode('+', $content);
387+
$isNumericConcat = true;
388+
389+
foreach ($parts as $part) {
390+
$isNumericConcat = $isNumericConcat && $this->isNumeric($part, $properties);
391+
}
392+
393+
return new Concat(
394+
implode($isNumericConcat ? '+' : '~', $parts),
395+
$isNumericConcat
396+
);
397+
}
398+
399+
/**
400+
* @param Property[] $properties
401+
*/
402+
private function isNumeric(string $value, array $properties): bool
403+
{
404+
$value = trim($value);
405+
406+
foreach ($properties as $property) {
407+
if (strtolower($property->getName()) === strtolower($value)) {
408+
return $property->getType() && strtolower($property->getType()) === 'number';
409+
}
410+
}
411+
412+
if (isset($this->concat[$value])) {
413+
return $this->concat[$value]->isNumeric();
414+
}
415+
416+
$mathematicsParts = preg_split('/[-*\/%]+/', $value);
417+
if (count($mathematicsParts) > 1) {
418+
$isNumeric = true;
419+
foreach ($mathematicsParts as $mathematicsPart) {
420+
$isNumeric = $isNumeric && $this->isNumeric($mathematicsPart, $properties);
421+
}
422+
423+
return $isNumeric;
424+
}
425+
426+
return is_numeric($value);
427+
}
343428
}

0 commit comments

Comments
 (0)