Replace compiled Less colors with CSS var() function calls

This commit is contained in:
Eric Lippmann 2021-12-01 14:24:57 +01:00
parent 3166d112f1
commit d82fc24766
4 changed files with 246 additions and 0 deletions

View File

@ -0,0 +1,99 @@
<?php
namespace Icinga\Less;
use Less_Tree_Call;
use Less_Tree_Color;
use Less_Tree_Keyword;
class ColorProp extends Less_Tree_Color
{
/** @var Less_Tree_Color */
protected $color;
/** @var int */
protected $index;
/** @var string */
protected $origin;
public function __construct()
{
}
/**
* @param Less_Tree_Color $color
*
* @return self
*/
public static function fromColor(Less_Tree_Color $color)
{
$self = new self();
$self->color = $color;
foreach ($color as $k => $v) {
$self->$k = $v;
}
return $self;
}
/**
* @return int
*/
public function getIndex()
{
return $this->index;
}
/**
* @param int $index
*
* @return $this
*/
public function setIndex($index)
{
$this->index = $index;
return $this;
}
/**
* @return string
*/
public function getOrigin()
{
return $this->origin;
}
/**
* @param string $origin
*
* @return $this
*/
public function setOrigin($origin)
{
$this->origin = $origin;
return $this;
}
public function compile()
{
return $this;
}
public function genCSS($output)
{
$css = (new Less_Tree_Call(
'var',
[
new Less_Tree_Keyword('--' . $this->getOrigin()),
$this->color
],
$this->getIndex()
))->toCSS();
$output->add($css);
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace Icinga\Less;
use Less_Tree;
use Less_Tree_Color;
use Less_Tree_Variable;
class ColorPropOrVariable extends Less_Tree
{
public $type = 'Variable';
/** @var Less_Tree_Variable */
protected $variable;
/**
* @return Less_Tree_Variable
*/
public function getVariable()
{
return $this->variable;
}
/**
* @param Less_Tree_Variable $variable
*
* @return $this
*/
public function setVariable(Less_Tree_Variable $variable)
{
$this->variable = $variable;
return $this;
}
public function compile($env)
{
$v = $this->getVariable();
$compiled = $v->compile($env);
if ($compiled instanceof Less_Tree_Color) {
return ColorProp::fromColor($compiled)
->setIndex($v->index)
->setOrigin(substr($v->name, 1));
}
return $compiled;
}
}

View File

@ -0,0 +1,96 @@
<?php
namespace Icinga\Less;
use Less_VisitorReplacing;
use LogicException;
/**
* Replace compiled Less colors with CSS var() function calls
*/
class Visitor extends Less_VisitorReplacing
{
public $isPreEvalVisitor = true;
/**
* Whether calling var() CSS function
*
* If that's the case, don't try to replace compiled Less colors with CSS var() function calls.
*
* @var bool|string
*/
protected $callingVar = false;
/**
* Whether defining a variable
*
* If that's the case, don't try to replace compiled Less colors with CSS var() function calls.
*
* @var bool|string
*/
protected $definingVar = false;
public function visitCall($c)
{
if ($c->name === 'var') {
if ($this->callingVar !== false) {
throw new LogicException('Already calling var');
}
$this->callingVar = spl_object_hash($c);
}
return $c;
}
public function visitCallOut($c)
{
if ($this->callingVar !== false && $this->callingVar === spl_object_hash($c)) {
$this->callingVar = false;
}
}
public function visitDetachedRuleset($rs)
{
// A detached ruleset is a variable definition in the first place,
// so just reset that we define a variable.
$this->definingVar = false;
return $rs;
}
public function visitRule($r)
{
if ($r->name[0] === '@' && $r->variable) {
if ($this->definingVar !== false) {
throw new LogicException('Already defining a variable');
}
$this->definingVar = spl_object_hash($r);
}
return $r;
}
public function visitRuleOut($r)
{
if ($this->definingVar !== false && $this->definingVar === spl_object_hash($r)) {
$this->definingVar = false;
}
}
public function visitVariable($v)
{
if ($this->callingVar !== false || $this->definingVar !== false) {
return $v;
}
return (new ColorPropOrVariable())
->setVariable($v);
}
public function run($node)
{
return $this->visitObj($node);
}
}

View File

@ -3,6 +3,7 @@
namespace Icinga\Util;
use Icinga\Less\Visitor;
use Less_Tree_Anonymous;
use Less_Tree_Expression;
use Less_Tree_Quoted;
@ -16,6 +17,7 @@ class LessParser extends lessc
public function __construct()
{
$this->registerFunction('extract-variable-default', [$this, 'extractVariableDefault']);
$this->setOption('plugins', [new Visitor()]);
}
/**