Scalar   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 127
Duplicated Lines 0 %

Test Coverage

Coverage 95%

Importance

Changes 0
Metric Value
wmc 24
eloc 49
dl 0
loc 127
ccs 57
cts 60
cp 0.95
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getTargetOnMoreIndent() 0 3 1
A __construct() 0 15 3
A getScalar() 0 37 6
A build() 0 10 5
A getNumber() 0 5 5
A getTargetOnLessIndent() 0 6 3
A replaceSequences() 0 15 1
1
<?php
2
3
namespace Dallgoot\Yaml\Nodes;
4
5
use Dallgoot\Yaml\NodeFactory;
6
use Dallgoot\Yaml\Tag\TagFactory;
7
use Dallgoot\Yaml\NodeList;
8
use Dallgoot\Yaml\Regex;
9
use Dallgoot\Yaml\Loader;
10
use Dallgoot\Yaml\Nodes\Generic\NodeGeneric;
11
12
/**
13
 *
14
 * @author  Stéphane Rebai <[email protected]>
15
 * @license Apache 2.0
16
 * @link    https://github.com/dallgoot/yaml
17
 */
18
class Scalar extends NodeGeneric
19
{
20 7
    public function __construct(string $nodeString, int $line)
21
    {
22 7
        parent::__construct($nodeString, $line);
23 7
        $value = trim($nodeString);
24 7
        if ($value !== '') {
25 7
            $hasComment = strpos($value, ' #');
26 7
            if (!is_bool($hasComment)) {
27 1
                $realValue    = trim(substr($value, 0, $hasComment));
28 1
                $commentValue = trim(substr($value, $hasComment));
29 1
                $realNode = NodeFactory::get($realValue, $line);
30 1
                $realNode->indent = null;
31 1
                $commentNode = NodeFactory::get($commentValue, $line);
32 1
                $commentNode->indent = null;
33 1
                $this->add($realNode);
34 1
                $this->add($commentNode);
35
            }
36
        }
37
    }
38
39 2
    public function build(&$parent = null)
40
    {
41 2
        if (!is_null($this->tag)) {
42 1
            $tagged = TagFactory::transform($this->tag, $this);
43 1
            if ($tagged instanceof NodeGeneric || $tagged instanceof NodeList) {
44
                return $tagged->build();
45
            }
46 1
            return $tagged;
47
        }
48 1
        return is_null($this->value) ? $this->getScalar(trim($this->raw)) : $this->value->build();
49
    }
50
51 1
    public function getTargetOnLessIndent(NodeGeneric &$node): NodeGeneric
52
    {
53 1
        if ($node instanceof Scalar || $node instanceof Blank) {
54 1
            return $this->getParent();
55
        } else {
56 1
            return $this->getParent($node->indent);
57
        }
58
    }
59
60 1
    public function getTargetOnMoreIndent(NodeGeneric &$node): NodeGeneric
61
    {
62 1
        return $this->getParent();
63
    }
64
65
66
67
    /**
68
     * Returns the correct PHP type according to the string value
69
     *
70
     * @param string $v a string value
71
     *
72
     * @return mixed The value with appropriate PHP type
73
     * @throws \Exception if it happens in Regex::isDate or Regex::isNumber
74
     * @todo implement date as DateTime Object
75
     */
76 2
    public function getScalar(string $v, bool $onlyScalar = false)
77
    {
78
        /*
79
         10.3.2. Tag Resolution
80
81
The core schema tag resolution is an extension of the JSON schema tag resolution.
82
83
All nodes with the “!” non-specific tag are resolved, by the standard convention, to “tag:yaml.org,2002:seq”, “tag:yaml.org,2002:map”, or “tag:yaml.org,2002:str”, according to their kind.
84
85
Collections with the “?” non-specific tag (that is, untagged collections) are resolved to “tag:yaml.org,2002:seq” or “tag:yaml.org,2002:map” according to their kind.
86
87
Scalars with the “?” non-specific tag (that is, plain scalars) are matched with an extended list of regular expressions. However, in this case, if none of the regular expressions matches, the scalar is resolved to tag:yaml.org,2002:str (that is, considered to be a string).
88
 Regular expression       Resolved to tag
89
 null | Null | NULL | ~      tag:yaml.org,2002:null
90
 Empty      tag:yaml.org,2002:null
91
 true | True | TRUE | false | False | FALSE      tag:yaml.org,2002:bool
92
 [-+]? [0-9]+    tag:yaml.org,2002:int (Base 10)
93
 0o [0-7]+   tag:yaml.org,2002:int (Base 8)
94
 0x [0-9a-fA-F]+     tag:yaml.org,2002:int (Base 16)
95
 [-+]? ( \. [0-9]+ | [0-9]+ ( \. [0-9]* )? ) ( [eE] [-+]? [0-9]+ )?      tag:yaml.org,2002:float (Number)
96
 [-+]? ( \.inf | \.Inf | \.INF )     tag:yaml.org,2002:float (Infinity)
97
 \.nan | \.NaN | \.NAN   tag:yaml.org,2002:float (Not a number)
98
 *   tag:yaml.org,2002:str (Default)
99
 */
100 2
        if (Regex::isDate($v))   return ($this->getRoot()->getYamlObject()->getOptions() & Loader::NO_OBJECT_FOR_DATE) && !$onlyScalar ? date_create($v) : $v;
101 2
        if (Regex::isNumber($v)) return $this->getNumber($v);
102 2
        $types = [
103 2
            'yes'   => true,
104 2
            'no'    => false,
105 2
            'true'  => true,
106 2
            'false' => false,
107 2
            'null'  => null,
108 2
            '.inf'  => \INF,
109 2
            '-.inf' => -\INF,
110 2
            '.nan'  => \NAN
111 2
        ];
112 2
        return array_key_exists(strtolower($v), $types) ? $types[strtolower($v)] : $this->replaceSequences($v);
113
    }
114
115 1
    public function replaceSequences(string $value = ''): string
116
    {
117 1
        $replaceUnicodeSeq = function ($matches) {
118
            return json_decode('"' . $matches[1] . '"');
119 1
        };
120 1
        $replaceNonPrintable = function ($matches) {
121
            return $matches[1] . "";
122 1
        };
123 1
        return preg_replace_callback_array(
124 1
            [
125 1
                '/((?<![\\\\])\\\\x[0-9a-f]{2})/i' => $replaceUnicodeSeq,
126 1
                '/((?<![\\\\])\\\\u[0-9a-f]{4,})/i' => $replaceUnicodeSeq,
127 1
                '/(\\\\b|\\\\n|\\\\t|\\\\r)/' => $replaceNonPrintable
128 1
            ],
129 1
            $value
130 1
        );
131
    }
132
133
134
    /**
135
     * Returns the correct PHP type according to the string value
136
     *
137
     * @return int|float   The scalar value with appropriate PHP type
138
     * @todo or scientific notation matching the regular expression -? [1-9] ( \. [0-9]* [1-9] )? ( e [-+] [1-9] [0-9]* )?
139
     */
140 2
    private function getNumber(string $v)
141
    {
142 2
        if ((bool) preg_match(Regex::OCTAL_NUM, $v)) return intval(base_convert($v, 8, 10));
143 2
        if ((bool) preg_match(Regex::HEX_NUM, $v))   return intval(base_convert($v, 16, 10));
144 2
        return is_bool(strpos($v, '.')) || substr_count($v, '.') > 1 ? intval($v) : floatval($v);
145
    }
146
}
147