Skip to content

Commit 30e0284

Browse files
authored
Update test badge
split: 39dd7c399e46a9a22490c061a2c91d3ef1579af6
1 parent 283a64a commit 30e0284

8 files changed

Lines changed: 197 additions & 36 deletions

Formatter/AbstractFormat.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ protected function getDebugInfo($element)
233233
/**
234234
* @param string|ElementInterface $element
235235
* @param bool $noDebug
236-
* @param $element
236+
* @param $element
237237
*
238238
* @return string
239239
*/
@@ -460,13 +460,16 @@ protected function formatDynamicValue($formattedName, $value)
460460
return 'null';
461461
}
462462

463-
if ($value instanceof ExpressionElement &&
464-
in_array(($code = strtolower($value->getValue())), ['true', 'false', 'null', 'undefined'])
465-
) {
466-
return $code;
463+
if ($value instanceof ExpressionElement) {
464+
$code = strtolower($value->getValue());
465+
466+
if (in_array($code, ['true', 'false', 'null', 'undefined'])) {
467+
return $code;
468+
}
467469
}
468470

469471
$code = $this->formatAssignmentValue($value);
472+
470473
if ($value instanceof ExpressionElement && $value->isEscaped()) {
471474
return $this->exportHelper('array_escape', [$formattedName, $code]);
472475
}

Formatter/AssignmentContainerInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
namespace Phug\Formatter;
44

55
use Phug\Formatter\Element\AssignmentElement;
6+
use Phug\Util\AttributesOrderInterface;
67

7-
interface AssignmentContainerInterface extends ElementInterface
8+
interface AssignmentContainerInterface extends ElementInterface, AttributesOrderInterface
89
{
910
public function getName();
1011

Formatter/Element/AbstractAssignmentContainerElement.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@
44

55
use Phug\Formatter\AbstractElement;
66
use Phug\Formatter\AssignmentContainerInterface;
7+
use Phug\Util\Partial\AttributesOrderTrait;
78
use SplObjectStorage;
89

910
abstract class AbstractAssignmentContainerElement extends AbstractElement implements AssignmentContainerInterface
1011
{
12+
use AttributesOrderTrait;
13+
14+
/**
15+
* @var SplObjectStorage<AssignmentElement>
16+
*/
1117
private $assignments;
1218

1319
/**
@@ -19,6 +25,10 @@ abstract class AbstractAssignmentContainerElement extends AbstractElement implem
1925
*/
2026
public function addAssignment(AssignmentElement $element)
2127
{
28+
if ($element->getOrder() === null) {
29+
$element->setOrder($this->getNextAttributeIndex());
30+
}
31+
2232
$element->setContainer($this);
2333
$this->getAssignments()->attach($element);
2434

@@ -42,7 +52,7 @@ public function removedAssignment(AssignmentElement $element)
4252
/**
4353
* Return markup assignments list.
4454
*
45-
* @return SplObjectStorage[AssignmentElement]
55+
* @return SplObjectStorage<AssignmentElement>
4656
*/
4757
public function getAssignments()
4858
{

Formatter/Element/AssignmentElement.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,31 @@
77
use Phug\Formatter\AssignmentContainerInterface;
88
use Phug\Parser\NodeInterface as ParserNode;
99
use Phug\Util\AttributesInterface;
10+
use Phug\Util\OrderableInterface;
1011
use Phug\Util\Partial\AttributeTrait;
1112
use Phug\Util\Partial\NameTrait;
13+
use Phug\Util\Partial\OrderTrait;
14+
use SplObjectStorage;
1215

13-
class AssignmentElement extends AbstractElement implements AttributesInterface
16+
class AssignmentElement extends AbstractElement implements AttributesInterface, OrderableInterface
1417
{
1518
use AttributeTrait;
1619
use NameTrait;
20+
use OrderTrait;
1721

1822
/**
1923
* AssignmentElement constructor.
2024
*
2125
* @param string $name
22-
* @param \SplObjectStorage|null $attributes
23-
* @param AssignmentContainerInterface|null $markup
26+
* @param SplObjectStorage|null $attributes
27+
* @param AssignmentContainerInterface|null $container
2428
* @param ParserNode|null $originNode
2529
* @param NodeInterface|null $parent
2630
* @param array|null $children
2731
*/
2832
public function __construct(
2933
$name,
30-
\SplObjectStorage $attributes = null,
34+
SplObjectStorage $attributes = null,
3135
AssignmentContainerInterface $container = null,
3236
ParserNode $originNode = null,
3337
NodeInterface $parent = null,

Formatter/Element/AttributeElement.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44

55
use Phug\Ast\NodeInterface;
66
use Phug\Parser\NodeInterface as ParserNode;
7+
use Phug\Util\OrderableInterface;
78
use Phug\Util\Partial\NameTrait;
9+
use Phug\Util\Partial\OrderTrait;
810
use Phug\Util\Partial\VariadicTrait;
911

10-
class AttributeElement extends AbstractValueElement
12+
class AttributeElement extends AbstractValueElement implements OrderableInterface
1113
{
1214
use NameTrait;
15+
use OrderTrait;
1316
use VariadicTrait;
1417

1518
/**

Formatter/Element/MarkupElement.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Phug\Util\AttributesInterface;
88
use Phug\Util\Partial\AttributeTrait;
99
use Phug\Util\Partial\NameTrait;
10+
use SplObjectStorage;
1011

1112
class MarkupElement extends AbstractMarkupElement implements AttributesInterface
1213
{
@@ -21,17 +22,17 @@ class MarkupElement extends AbstractMarkupElement implements AttributesInterface
2122
/**
2223
* MarkupElement constructor.
2324
*
24-
* @param string $name
25-
* @param bool $autoClosed
26-
* @param \SplObjectStorage|null $attributes
27-
* @param ParserNode|null $originNode
28-
* @param NodeInterface|null $parent
29-
* @param array|null $children
25+
* @param string $name
26+
* @param bool $autoClosed
27+
* @param SplObjectStorage|null $attributes
28+
* @param ParserNode|null $originNode
29+
* @param NodeInterface|null $parent
30+
* @param array|null $children
3031
*/
3132
public function __construct(
3233
$name,
3334
$autoClosed = false,
34-
\SplObjectStorage $attributes = null,
35+
SplObjectStorage $attributes = null,
3536
ParserNode $originNode = null,
3637
NodeInterface $parent = null,
3738
array $children = null

Formatter/Format/XmlFormat.php

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

33
namespace Phug\Formatter\Format;
44

5+
use Closure;
56
use Generator;
7+
use InvalidArgumentException;
68
use Phug\Formatter;
79
use Phug\Formatter\AbstractFormat;
810
use Phug\Formatter\AssignmentContainerInterface;
@@ -20,6 +22,7 @@
2022
use Phug\FormatterException;
2123
use Phug\Util\AttributesInterface;
2224
use Phug\Util\Joiner;
25+
use Phug\Util\OrderedValue;
2326
use SplObjectStorage;
2427

2528
class XmlFormat extends AbstractFormat
@@ -268,17 +271,66 @@ protected function yieldAssignmentElement(AssignmentElement $element)
268271

269272
/* @var MarkupElement $markup */
270273
$markup = $element->getContainer();
274+
$attributeOrder = $this->hasOption('attribute_precedence')
275+
? $this->getOption('attribute_precedence')
276+
: 'assignment';
277+
278+
switch ($attributeOrder) {
279+
case 'assignment':
280+
case 'assignments':
281+
$arguments = array_merge(
282+
$markup instanceof AttributesInterface
283+
? $this->formatMarkupAttributes($markup)
284+
: [],
285+
$markup instanceof AssignmentContainerInterface
286+
? $this->formatAttributeAssignments($markup)
287+
: []
288+
);
289+
break;
271290

272-
$arguments = $markup instanceof AssignmentContainerInterface
273-
? $this->formatAttributeAssignments($markup)
274-
: [];
291+
case 'attribute':
292+
case 'attributes':
293+
$arguments = array_merge(
294+
$markup instanceof AssignmentContainerInterface
295+
? $this->formatAttributeAssignments($markup)
296+
: [],
297+
$markup instanceof AttributesInterface
298+
? $this->formatMarkupAttributes($markup)
299+
: []
300+
);
301+
break;
275302

276-
$arguments = array_merge(
277-
$markup instanceof AttributesInterface
278-
? $this->formatMarkupAttributes($markup)
279-
: [],
280-
$arguments
281-
);
303+
case 'left':
304+
$arguments = $this->getSortedAttributes($markup, static function (OrderedValue $a, OrderedValue $b) {
305+
return $b->getOrder() - $a->getOrder();
306+
});
307+
break;
308+
309+
case 'right':
310+
$arguments = $this->getSortedAttributes($markup, static function (OrderedValue $a, OrderedValue $b) {
311+
return $a->getOrder() - $b->getOrder();
312+
});
313+
break;
314+
315+
default:
316+
if (!is_callable($attributeOrder)) {
317+
throw new InvalidArgumentException(
318+
'Option attribute_precedence must be '.
319+
'"assignment" (default), "attribute", "left", "right" or a callable.'
320+
);
321+
}
322+
323+
$arguments = array_map(static function ($argument) {
324+
return $argument instanceof OrderedValue ? $argument->getValue() : $argument;
325+
}, $attributeOrder(
326+
$markup instanceof AssignmentContainerInterface
327+
? $this->formatOrderedAttributeAssignments($markup)
328+
: [],
329+
$markup instanceof AttributesInterface
330+
? $this->formatOrderedMarkupAttributes($markup)
331+
: []
332+
));
333+
}
282334

283335
foreach ($markup->getAssignments() as $assignment) {
284336
/* @var AssignmentElement $assignment */
@@ -303,22 +355,48 @@ protected function formatAttributeAssignments(AssignmentContainerInterface $mark
303355
$arguments = [];
304356

305357
foreach ($this->yieldAssignmentAttributes($markup) as $attribute) {
306-
$checked = method_exists($attribute, 'isChecked') && $attribute->isChecked();
358+
$arguments[] = $this->formatInnerCodeValue($attribute);
359+
}
307360

308-
while (method_exists($attribute, 'getValue')) {
309-
$attribute = $attribute->getValue();
310-
}
361+
return $arguments;
362+
}
311363

312-
$arguments[] = $this->formatCode($attribute, $checked);
364+
/**
365+
* @param AssignmentContainerInterface $markup
366+
*
367+
* @return list<OrderedValue<string>>
368+
*/
369+
protected function formatOrderedAttributeAssignments(AssignmentContainerInterface $markup)
370+
{
371+
$arguments = [];
372+
373+
foreach ($this->yieldAssignmentOrderedAttributes($markup) as $attribute => $order) {
374+
$arguments[] = new OrderedValue($this->formatInnerCodeValue($attribute), $order);
313375
}
314376

315377
return $arguments;
316378
}
317379

380+
/**
381+
* @param AbstractValueElement|mixed $value
382+
*
383+
* @return string
384+
*/
385+
protected function formatInnerCodeValue($value)
386+
{
387+
$checked = method_exists($value, 'isChecked') && $value->isChecked();
388+
389+
while (method_exists($value, 'getValue')) {
390+
$value = $value->getValue();
391+
}
392+
393+
return $this->formatCode($value, $checked);
394+
}
395+
318396
/**
319397
* @param AssignmentContainerInterface $markup
320398
*
321-
* @return Generator|AbstractValueElement[]
399+
* @return Generator<AbstractValueElement>
322400
*/
323401
protected function yieldAssignmentAttributes(AssignmentContainerInterface $markup)
324402
{
@@ -333,10 +411,28 @@ protected function yieldAssignmentAttributes(AssignmentContainerInterface $marku
333411
}
334412
}
335413

414+
/**
415+
* @param AssignmentContainerInterface $markup
416+
*
417+
* @return Generator<AbstractValueElement, int|null>
418+
*/
419+
protected function yieldAssignmentOrderedAttributes(AssignmentContainerInterface $markup)
420+
{
421+
foreach ($markup->getAssignmentsByName('attributes') as $attributesAssignment) {
422+
/* @var AssignmentElement $attributesAssignment */
423+
foreach ($attributesAssignment->getAttributes() as $attribute) {
424+
/* @var AbstractValueElement $attribute */
425+
yield $attribute => $attributesAssignment->getOrder();
426+
}
427+
428+
$markup->removedAssignment($attributesAssignment);
429+
}
430+
}
431+
336432
/**
337433
* @param AttributesInterface $markup
338434
*
339-
* @return array<string>
435+
* @return list<string>
340436
*/
341437
protected function formatMarkupAttributes(AttributesInterface $markup)
342438
{
@@ -353,6 +449,26 @@ protected function formatMarkupAttributes(AttributesInterface $markup)
353449
return $arguments;
354450
}
355451

452+
/**
453+
* @param AttributesInterface $markup
454+
*
455+
* @return list<OrderedValue<string>>
456+
*/
457+
protected function formatOrderedMarkupAttributes(AttributesInterface $markup)
458+
{
459+
$arguments = [];
460+
$attributes = $markup->getAttributes();
461+
462+
foreach ($attributes as $attribute) {
463+
/* @var AttributeElement $attribute */
464+
$arguments[] = new OrderedValue($this->formatAttributeAsArrayItem($attribute), $attribute->getOrder());
465+
}
466+
467+
$attributes->removeAll($attributes);
468+
469+
return $arguments;
470+
}
471+
356472
/**
357473
* @param AssignmentElement $element
358474
*
@@ -441,4 +557,27 @@ protected function formatMarkupElement(MarkupElement $element)
441557
? $this->getIndent().$tag.$this->getNewLine()
442558
: $tag;
443559
}
560+
561+
/**
562+
* @param AssignmentContainerInterface|AttributesInterface|mixed $markup
563+
* @param Closure(OrderedValue, OrderedValue): int $sorter
564+
*
565+
* @return list<string>
566+
*/
567+
private function getSortedAttributes($markup, Closure $sorter)
568+
{
569+
$arguments = array_merge(
570+
$markup instanceof AssignmentContainerInterface
571+
? $this->formatOrderedAttributeAssignments($markup)
572+
: [],
573+
$markup instanceof AttributesInterface
574+
? $this->formatOrderedMarkupAttributes($markup)
575+
: []
576+
);
577+
usort($arguments, $sorter);
578+
579+
return array_map(static function (OrderedValue $value) {
580+
return $value->getValue();
581+
}, $arguments);
582+
}
444583
}

0 commit comments

Comments
 (0)