Passed
Push — master ( 36bd6b...41f581 )
by stéphane
12:53
created

NodeFactory   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Test Coverage

Coverage 93.88%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 51
dl 0
loc 146
ccs 46
cts 49
cp 0.9388
rs 10
c 1
b 0
f 0
wmc 28

8 Methods

Rating   Name   Duplication   Size   Complexity  
A onHyphen() 0 6 3
A onSpecial() 0 10 4
B get() 0 22 7
A onCompact() 0 8 4
A onSetElement() 0 4 2
A onQuoted() 0 4 2
A onNodeAction() 0 10 3
A onLiteral() 0 7 3
1
<?php
2
3
namespace Dallgoot\Yaml;
4
5
use Dallgoot\Yaml\Nodes;
6
use Dallgoot\Yaml\Regex;
7
use Dallgoot\Yaml\Nodes\NodeGeneric;
8
9
/**
10
 * Analyzes $nodeString
11
 * determines the appropriate NodeType
12
 * constructs it
13
 * and returns it
14
 *
15
 * @author  Stéphane Rebai <[email protected]>
16
 * @license Apache 2.0
17
 * @link    https://github.com/dallgoot/yaml
18
 */
19
final class NodeFactory
20
{
21
    private const JSON_OPTIONS = \JSON_PARTIAL_OUTPUT_ON_ERROR|\JSON_UNESCAPED_SLASHES;
22
23 5
    final public static function get($nodeString = null, $line = 0):NodeGeneric
24
    {
25 5
        $trimmed = ltrim($nodeString);
26 5
        if ($trimmed === '')                                return new Nodes\Blank($nodeString, $line);
27 5
        elseif (substr($trimmed, 0, 3) === '...')           return new Nodes\DocEnd($nodeString, $line);
28 5
        elseif ((bool) preg_match(Regex::KEY, $trimmed, $matches)) return new Nodes\Key($nodeString, $line, $matches);
29
        else {
30 5
            $first = $trimmed[0];
31 5
            $stringGroups = ['-',         '>|' ,   '"\'',    "#%" ,    "{[" ,       ":?" ,       '*&!'];
32 5
            $methodGroups = ['Hyphen','Literal','Quoted','Special','Compact','SetElement','NodeAction'];
33 5
            foreach ($stringGroups as $groupIndex => $stringRef) {
34 5
                if (is_int(strpos($stringRef, $first))) {
35 1
                    $methodName = 'on'.$methodGroups[$groupIndex];
36
                    try {
37 1
                        return self::$methodName($first, $nodeString, $line);
38
                    } catch (\Throwable $e) {
39
                        throw new \Exception(" could not create a Node ($methodName) for '$nodeString'", 1, $e);
40
                    }
41
                }
42
            }
43
        }
44 5
        return new Nodes\Scalar($nodeString, $line);
45
    }
46
47
    /**
48
     * Return the correct Node Object between NodeComment OR NodeDirective
49
     *
50
     * @param      string   $nodeString  The node string
51
     * @param      integer  $line         The line
52
     *
53
     * @return     NodeGeneric
54
     */
55 1
    final private static function onSpecial(string $first, string $nodeString, int $line):NodeGeneric
56
    {
57 1
        if ($first === "#") {
58 1
            return new Nodes\Comment(ltrim($nodeString), $line);
59
        } else {
60 1
            if (preg_match(Regex::DIRECTIVE_TAG, $nodeString)
61 1
                || preg_match(Regex::DIRECTIVE_VERSION, $nodeString)) {
62 1
                return new Nodes\Directive(ltrim($nodeString), $line);
63
            } else {
64
                throw new \ParseError("Invalid/Unknown Directive", 1);
65
            }
66
        }
67
    }
68
69
    /**
70
     * Set $node type and value when $nodevalue starts with a quote (simple or double)
71
     *
72
     * @param string $nodeString The node value
73
     * @param int    $line       The line
74
     *
75
     * @return     NodeGeneric
76
     */
77 1
    final private static function onQuoted(string $first, string $nodeString, int $line):NodeGeneric
78
    {
79 1
        return Regex::isProperlyQuoted(trim($nodeString)) ? new Nodes\Quoted($nodeString, $line)
80 1
                                                          : new Nodes\Partial($nodeString, $line);
81
    }
82
83
    /**
84
     * Set $node type and value when NodeValue starts with a Set characters "?:"
85
     *
86
     * @param string $nodeString The node value
87
     * @param int    $line       The line
88
     *
89
     * @return     NodeGeneric
90
     */
91 1
    final private static function onSetElement(string $first, string $nodeString, int $line):NodeGeneric
92
    {
93 1
        return $first === '?' ? new Nodes\SetKey($nodeString, $line)
94 1
                              : new Nodes\SetValue($nodeString, $line);
95
    }
96
97
    /**
98
     * Determines the Node type and value when a compact object/array syntax is found
99
     *
100
     * @param string $nodeString The value assumed to start with { or [ or characters
101
     * @param int    $line       The line
102
     *
103
     * @return     NodeGeneric
104
     */
105 2
    final private static function onCompact(string $first, string $nodeString, int $line):NodeGeneric
106
    {
107 2
        json_decode($nodeString, false, 512, self::JSON_OPTIONS);
108 2
        if (json_last_error() === \JSON_ERROR_NONE)             return new Nodes\JSON($nodeString, $line);
109 1
        elseif ((bool) preg_match(Regex::MAPPING, trim($nodeString)))  return new Nodes\CompactMapping($nodeString, $line);
110 1
        elseif ((bool) preg_match(Regex::SEQUENCE, trim($nodeString))) return new Nodes\CompactSequence($nodeString, $line);
111
        else {
112 1
            return new Nodes\Partial($nodeString, $line);
113
        }
114
    }
115
116
    /**
117
     * Determines Node type and value when an hyphen "-" is found
118
     *
119
     * @param string $nodeString The node string value
120
     * @param int    $line       The line
121
     *
122
     * @return     NodeGeneric
123
     */
124 1
    final private static function onHyphen(string $first, string $nodeString, int $line):NodeGeneric
125
    {
126 1
        if (substr($nodeString, 0, 3) === '---')              return new Nodes\DocStart($nodeString, $line);
127 1
        elseif ((bool) preg_match(Regex::ITEM, ltrim($nodeString)))  return new Nodes\Item($nodeString, $line);
128
        else {
129 1
            return new Nodes\Scalar($nodeString, $line);
130
        }
131
    }
132
133
    /**
134
     * Sets Node type and value according to $nodeString when one of these characters is found : !,&,*
135
     *
136
     * @param string $nodeString The node value
137
     * @param int    $line       The line
138
     *
139
     *@todo replace $action[0] with $first if applicable
140
     */
141 1
    final private static function onNodeAction(string $first, string $nodeString, int $line):NodeGeneric
142
    {
143 1
        if (!((bool) preg_match(Regex::NODE_ACTIONS, trim($nodeString), $matches))) {
144 1
            return new Nodes\Scalar($nodeString, $line);
145
        }
146
        // $action = trim($matches['action']);//var_dump($matches);
147 1
        switch ($first) {
148 1
            case '!': return new Nodes\Tag   ($nodeString, $line);
149
            default :
150 1
                return new Nodes\Anchor($nodeString, $line);
151
            // case '&': return new NodeAnchor($nodeString, $line);
152
            // case '*': return new NodeAnchor($nodeString, $line);
153
            // default:
154
            //     throw new \ParseError("Not a action node !! '$action[0]' on line:$line".gettype($first));
155
        }
156
    }
157
158 2
    final private static function onLiteral(string $first, string $nodeString, int $line):NodeGeneric
159
    {
160 2
        switch ($first) {
161 2
            case '>': return new Nodes\LiteralFolded($nodeString, $line);
162 2
            case '|': return new Nodes\Literal($nodeString, $line);
163
            default:
164 1
                throw new \ParseError("Not a literal node !! '$first' on line:$line");
165
        }
166
    }
167
168
}