Passed
Push — master ( 7e7ce9...effeb7 )
by stéphane
02:19
created

NodeFactory::onNodeAction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 10
c 1
b 0
f 0
cc 2
nc 2
nop 2
crap 2
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 8
    final public static function get(string $nodeString, int $line = 0, bool $debug = false): NodeGeneric
25
    {
26 8
        $trimmed = ltrim($nodeString);
27 8
        $match = (bool) preg_match(Regex::KEY, $trimmed, $matches);
28 8
        $node = match(true) {
29 8
            $trimmed === '' => new Blank($nodeString, $line),
30 8
            str_starts_with($trimmed, '...') => new Nodes\DocEnd($nodeString, $line),
31 8
            $match => new Nodes\Key($nodeString, $line, $matches),
32 8
            default => self::onCharacter($trimmed[0], $nodeString, $line)
33 8
        };
34 7
        if ($debug) echo $line . ":" . get_class($node) . "\n";
35 7
        return $node;
36
    }
37
38
39 9
    private static function onCharacter(string $first, string $nodeString, int $line): NodeGeneric
40
    {
41 9
        return match ($first) {
42 9
            '-' => self::onHyphen($nodeString, $line),
43 9
            '>' => new Nodes\LiteralFolded($nodeString, $line),
44 9
            '|' => new Nodes\Literal($nodeString, $line),
45 9
            '"', "'" => self::onQuoted($first, $nodeString, $line),
46 9
            '#' => new Nodes\Comment(ltrim($nodeString), $line),
47 9
            '%' => self::onDirective($nodeString, $line),
48 9
            '{', '[' => self::onCompact($nodeString, $line),
49 9
            ':' => new Nodes\SetValue($nodeString, $line),
50 9
            '?' => new Nodes\SetKey($nodeString, $line),
51 9
            '*', '&' => self::onNodeAction($nodeString, $line),
52 9
            '!' => new Nodes\Tag($nodeString, $line),
53 9
            default => new Nodes\Scalar($nodeString, $line),
54 9
        };
55
    }
56
57
58
    /**
59
     * Return the correct Node Object between NodeComment OR NodeDirective
60
     *
61
     * @param      string   $nodeString  The node string
62
     * @param      integer  $line         The line
63
     *
64
     * @return     NodeGeneric
65
     */
66 2
    private static function onDirective(string $nodeString, int $line): NodeGeneric
67
    {
68
            if (
69 2
                (bool) preg_match(Regex::DIRECTIVE_TAG, $nodeString)
70 2
                || (bool) preg_match(Regex::DIRECTIVE_VERSION, $nodeString)
71
            ) {
72
                return new Nodes\Directive(ltrim($nodeString), $line);
73
            } else {
74 2
                throw new \ParseError("Invalid/Unknown Directive", 1);
75
            }
76
    }
77
78
    /**
79
     * Set $node type and value when $nodevalue starts with a quote (simple or double)
80
     *
81
     * @param string $nodeString The node value
82
     * @param int    $line       The line
83
     *
84
     * @return     NodeGeneric
85
     */
86 1
    private static function onQuoted(string $first, string $nodeString, int $line): NodeGeneric
87
    {
88 1
        return Regex::isProperlyQuoted(trim($nodeString)) ? new Nodes\Quoted($nodeString, $line)
89 1
            : new Nodes\Partial($nodeString, $line);
90
    }
91
92
    /**
93
     * Determines the Node type and value when a compact object/array syntax is found
94
     *
95
     * @param string $nodeString The value assumed to start with { or [ or characters
96
     * @param int    $line       The line
97
     *
98
     * @return     NodeGeneric
99
     */
100 7
    private static function onCompact(string $nodeString, int $line): NodeGeneric
101
    {
102 7
        json_decode($nodeString, false, 512, self::JSON_OPTIONS);
103 7
        if (json_last_error() === \JSON_ERROR_NONE) {
104 3
            return new Nodes\JSON($nodeString, $line);
105
        } else {
106 4
            $backtrack_setting = "pcre.backtrack_limit";
107 4
            ini_set($backtrack_setting, "-1");
108 4
            $isMapping  = (bool) preg_match(Regex::MAPPING, trim($nodeString));
109 4
            $isSequence = (bool) preg_match(Regex::SEQUENCE, trim($nodeString));
110 4
            ini_restore($backtrack_setting);
111
112 4
            return match(true) {
113 4
                $isMapping => new Nodes\CompactMapping($nodeString, $line),
114 4
                $isSequence => new Nodes\CompactSequence($nodeString, $line),
115 4
                default => new Nodes\Partial($nodeString, $line),
116 4
            };
117
        }
118
    }
119
120
    /**
121
     * Determines Node type and value when an hyphen "-" is found
122
     *
123
     * @param string $nodeString The node string value
124
     * @param int    $line       The line
125
     *
126
     * @return     NodeGeneric
127
     */
128 1
    private static function onHyphen(string $nodeString, int $line): NodeGeneric
129
    {
130 1
        return match(true) {
131 1
            str_starts_with($nodeString, '---') => new Nodes\DocStart($nodeString, $line),
132 1
            (bool) preg_match(Regex::ITEM, ltrim($nodeString)) => new Nodes\Item($nodeString, $line),
133 1
            default => new Nodes\Scalar($nodeString, $line),
134 1
        };
135
    }
136
137
    /**
138
     * Sets Node type and value according to $nodeString when one of these characters is found : !,&,*
139
     *
140
     * @param string $nodeString The node value
141
     * @param int    $line       The line
142
     *
143
     *@todo replace $action[0] with $first if applicable
144
     */
145 1
    private static function onNodeAction(string $nodeString, int $line): NodeGeneric
146
    {
147 1
        if (!((bool) preg_match(Regex::NODE_ACTIONS, trim($nodeString), $matches))) {
148 1
            return new Nodes\Scalar($nodeString, $line);
149
        }
150 1
        return new Nodes\Anchor($nodeString, $line);
151
    }
152
153
}
154