summaryrefslogtreecommitdiffstats
path: root/library/Icinga/Less/DeferredColorProp.php
blob: c9c39adf546235fbe4c2d610c4f19b2eaa4f23ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php

/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */

namespace Icinga\Less;

use Less_Exception_Compiler;
use Less_Tree_Call;
use Less_Tree_Color;
use Less_Tree_Keyword;
use Less_Tree_Value;
use Less_Tree_Variable;

class DeferredColorProp extends Less_Tree_Variable
{
    /** @var DeferredColorProp|ColorProp */
    protected $reference;

    protected $resolved = false;

    public function __construct($name, $variable, $index = null, $currentFileInfo = null)
    {
        parent::__construct($name, $index, $currentFileInfo);

        if ($variable instanceof Less_Tree_Variable) {
            $this->reference = self::fromVariable($variable);
        }
    }

    public function isResolved()
    {
        return $this->resolved;
    }

    public function getName()
    {
        $name = $this->name;
        if ($this->name[0] === '@') {
            $name = substr($this->name, 1);
        }

        return $name;
    }

    public function hasReference()
    {
        return $this->reference !== null;
    }

    public function getRef()
    {
        return $this->reference;
    }

    public function setReference($ref)
    {
        $this->reference = $ref;

        return $this;
    }

    public static function fromVariable(Less_Tree_Variable $variable)
    {
        $static = new static($variable->name, $variable->index, $variable->currentFileInfo);
        $static->evaluating = $variable->evaluating;
        $static->type = $variable->type;

        return $static;
    }

    public function compile($env)
    {
        if (! $this->hasReference()) {
            // This is never supposed to happen, however, we might have a deferred color prop
            // without a reference. In this case we can simply use the parent method.
            return parent::compile($env);
        }

        if ($this->isResolved()) {
            // The dependencies are already resolved, no need to traverse the frame stack over again!
            return $this;
        }

        if ($this->evaluating) { // Just like the parent method
            throw new Less_Exception_Compiler(
                "Recursive variable definition for " . $this->name,
                null,
                $this->index,
                $this->currentFileInfo
            );
        }

        $this->evaluating = true;

        foreach ($env->frames as $frame) {
            if (($v = $frame->variable($this->getRef()->name))) {
                $rv = $v->value;
                if ($rv instanceof Less_Tree_Value) {
                    $rv = $rv->compile($env);
                }

                // As we are at it anyway, let's cast the tree color to our color prop as well!
                if ($rv instanceof Less_Tree_Color) {
                    $rv = ColorProp::fromColor($rv);
                    $rv->setName($this->getRef()->getName());
                }

                $this->evaluating = false;
                $this->resolved = true;
                $this->setReference($rv);

                break;
            }
        }

        return $this;
    }

    public function genCSS($output)
    {
        if (! $this->hasReference()) {
            return; // Nothing to generate
        }

        $css = (new Less_Tree_Call(
            'var',
            [
                new Less_Tree_Keyword('--' . $this->getName()),
                $this->getRef() // Each of the references will be generated recursively
            ],
            $this->index
        ))->toCSS();

        $output->add($css);
    }
}