Test Failed
Branch master (bee4a6)
by stéphane
14:37
created

NodeFactory::get()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10
dl 0
loc 13
rs 9.9332
c 1
b 0
f 0
cc 2
nc 2
nop 3
1
<?php
2
3
namespace Dallgoot\Yaml;
4
5
use Dallgoot\Yaml\Nodes as Nodes;
6
use Dallgoot\Yaml\Nodes\Blank;
7
use Dallgoot\Yaml\Regex;
8
use Dallgoot\Yaml\Nodes\Generic\NodeGeneric;
9
10
/**
11
 * Analyzes $nodeString
12
 * determines the appropriate NodeType
13
 * constructs it
14
 * and returns it
15
 *
16
 * @author  Stéphane Rebai <[email protected]>
17
 * @license Apache 2.0
18
 * @link    https://github.com/dallgoot/yaml
19
 */
20
class NodeFactory
21
{
22
    private const JSON_OPTIONS = \JSON_PARTIAL_OUTPUT_ON_ERROR | \JSON_UNESCAPED_SLASHES;
23
24
    final public static function get(string $nodeString, int $line = 0, bool $debug = false): NodeGeneric
25
    {
26
        $node = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $node is dead and can be removed.
Loading history...
27
        $trimmed = ltrim($nodeString);
28
        $match = (bool) preg_match(Regex::KEY, $trimmed, $matches);
29
        $node = match(true) {
30
            $trimmed === '' => new Blank($nodeString, $line),
31
            str_starts_with($trimmed, '...') => new Nodes\DocEnd($nodeString, $line),
32
            $match => new Nodes\Key($nodeString, $line, $matches),
33
            default => self::onCharacter($trimmed[0], $nodeString, $line)
34
        };
35
        if ($debug) echo $line . ":" . get_class($node) . "\n";
0 ignored issues
show
Bug introduced by
$node of type null is incompatible with the type object expected by parameter $object of get_class(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

35
        if ($debug) echo $line . ":" . get_class(/** @scrutinizer ignore-type */ $node) . "\n";
Loading history...
36
        return $node;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $node returns the type null which is incompatible with the type-hinted return Dallgoot\Yaml\Nodes\Generic\NodeGeneric.
Loading history...
37
    }
38
39
40
    private static function onCharacter(string $first, string $nodeString, int $line): NodeGeneric
41
    {
42
        return match ($first) {
43
            '-' => self::onHyphen($nodeString, $line),
44
            '>' => new Nodes\LiteralFolded($nodeString, $line),
45
            '|' => new Nodes\Literal($nodeString, $line),
46
            '"', "'" => self::onQuoted($first, $nodeString, $line),
47
            '#' => new Nodes\Comment(ltrim($nodeString), $line),
48
            '%' => self::onDirective($nodeString, $line),
49
            '{', '[' => self::onCompact($nodeString, $line),
50
            ':' => new Nodes\SetValue($nodeString, $line),
51
            '?' => new Nodes\SetKey($nodeString, $line),
52
            '*', '&' => self::onNodeAction($nodeString, $line),
53
            '!' => new Nodes\Tag($nodeString, $line),
54
            default => new Nodes\Scalar($nodeString, $line),
55
        };
56
    }
57
58
59
    /**
60
     * Return the correct Node Object between NodeComment OR NodeDirective
61
     *
62
     * @param      string   $nodeString  The node string
63
     * @param      integer  $line         The line
64
     *
65
     * @return     NodeGeneric
66
     */
67
    private static function onDirective(string $nodeString, int $line): NodeGeneric
68
    {
69
            if (
70
                (bool) preg_match(Regex::DIRECTIVE_TAG, $nodeString)
71
                || (bool) preg_match(Regex::DIRECTIVE_VERSION, $nodeString)
72
            ) {
73
                return new Nodes\Directive(ltrim($nodeString), $line);
74
            } else {
75
                throw new \ParseError("Invalid/Unknown Directive", 1);
76
            }
77
    }
78
79
    /**
80
     * Set $node type and value when $nodevalue starts with a quote (simple or double)
81
     *
82
     * @param string $nodeString The node value
83
     * @param int    $line       The line
84
     *
85
     * @return     NodeGeneric
86
     */
87
    private static function onQuoted(string $first, string $nodeString, int $line): NodeGeneric
0 ignored issues
show
Unused Code introduced by
The parameter $first is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

87
    private static function onQuoted(/** @scrutinizer ignore-unused */ string $first, string $nodeString, int $line): NodeGeneric

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
88
    {
89
        return Regex::isProperlyQuoted(trim($nodeString)) ? new Nodes\Quoted($nodeString, $line)
90
            : new Nodes\Partial($nodeString, $line);
91
    }
92
93
    /**
94
     * Determines the Node type and value when a compact object/array syntax is found
95
     *
96
     * @param string $nodeString The value assumed to start with { or [ or characters
97
     * @param int    $line       The line
98
     *
99
     * @return     NodeGeneric
100
     */
101
    private static function onCompact(string $nodeString, int $line): NodeGeneric
102
    {
103
        json_decode($nodeString, false, 512, self::JSON_OPTIONS);
104
        if (json_last_error() === \JSON_ERROR_NONE) {
105
            return new Nodes\JSON($nodeString, $line);
106
        } else {
107
            $backtrack_setting = "pcre.backtrack_limit";
108
            ini_set($backtrack_setting, "-1");
109
            $isMapping  = (bool) preg_match(Regex::MAPPING, trim($nodeString));
110
            $isSequence = (bool) preg_match(Regex::SEQUENCE, trim($nodeString));
111
            ini_restore($backtrack_setting);
112
113
            return match(true) {
114
                $isMapping => new Nodes\CompactMapping($nodeString, $line),
115
                $isSequence => new Nodes\CompactSequence($nodeString, $line),
116
                default => new Nodes\Partial($nodeString, $line),
117
            };
118
        }
119
    }
120
121
    /**
122
     * Determines Node type and value when an hyphen "-" is found
123
     *
124
     * @param string $nodeString The node string value
125
     * @param int    $line       The line
126
     *
127
     * @return     NodeGeneric
128
     */
129
    private static function onHyphen(string $nodeString, int $line): NodeGeneric
130
    {
131
        return match(true) {
132
            str_starts_with($nodeString, '---') => new Nodes\DocStart($nodeString, $line),
133
            (bool) preg_match(Regex::ITEM, ltrim($nodeString)) => new Nodes\Item($nodeString, $line),
134
            default => new Nodes\Scalar($nodeString, $line),
135
        };
136
    }
137
138
    /**
139
     * Sets Node type and value according to $nodeString when one of these characters is found : !,&,*
140
     *
141
     * @param string $nodeString The node value
142
     * @param int    $line       The line
143
     *
144
     *@todo replace $action[0] with $first if applicable
145
     */
146
    private static function onNodeAction(string $nodeString, int $line): NodeGeneric
147
    {
148
        if (!((bool) preg_match(Regex::NODE_ACTIONS, trim($nodeString), $matches))) {
149
            return new Nodes\Scalar($nodeString, $line);
150
        }
151
        return new Nodes\Anchor($nodeString, $line);
152
    }
153
154
}
155