Removed modules/contrib/media module to allow update to the core media module
[yaffs-website] / vendor / nikic / php-parser / lib / PhpParser / JsonDecoder.php
1 <?php declare(strict_types=1);
2
3 namespace PhpParser;
4
5 class JsonDecoder
6 {
7     /** @var \ReflectionClass[] Node type to reflection class map */
8     private $reflectionClassCache;
9
10     public function decode(string $json) {
11         $value = json_decode($json, true);
12         if (json_last_error()) {
13             throw new \RuntimeException('JSON decoding error: ' . json_last_error_msg());
14         }
15
16         return $this->decodeRecursive($value);
17     }
18
19     private function decodeRecursive($value) {
20         if (\is_array($value)) {
21             if (isset($value['nodeType'])) {
22                 if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc') {
23                     return $this->decodeComment($value);
24                 }
25                 return $this->decodeNode($value);
26             }
27             return $this->decodeArray($value);
28         }
29         return $value;
30     }
31
32     private function decodeArray(array $array) : array {
33         $decodedArray = [];
34         foreach ($array as $key => $value) {
35             $decodedArray[$key] = $this->decodeRecursive($value);
36         }
37         return $decodedArray;
38     }
39
40     private function decodeNode(array $value) : Node {
41         $nodeType = $value['nodeType'];
42         if (!\is_string($nodeType)) {
43             throw new \RuntimeException('Node type must be a string');
44         }
45
46         $reflectionClass = $this->reflectionClassFromNodeType($nodeType);
47         /** @var Node $node */
48         $node = $reflectionClass->newInstanceWithoutConstructor();
49
50         if (isset($value['attributes'])) {
51             if (!\is_array($value['attributes'])) {
52                 throw new \RuntimeException('Attributes must be an array');
53             }
54
55             $node->setAttributes($this->decodeArray($value['attributes']));
56         }
57
58         foreach ($value as $name => $subNode) {
59             if ($name === 'nodeType' || $name === 'attributes') {
60                 continue;
61             }
62
63             $node->$name = $this->decodeRecursive($subNode);
64         }
65
66         return $node;
67     }
68
69     private function decodeComment(array $value) : Comment {
70         $className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class;
71         if (!isset($value['text'])) {
72             throw new \RuntimeException('Comment must have text');
73         }
74
75         return new $className(
76             $value['text'], $value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1
77         );
78     }
79
80     private function reflectionClassFromNodeType(string $nodeType) : \ReflectionClass {
81         if (!isset($this->reflectionClassCache[$nodeType])) {
82             $className = $this->classNameFromNodeType($nodeType);
83             $this->reflectionClassCache[$nodeType] = new \ReflectionClass($className);
84         }
85         return $this->reflectionClassCache[$nodeType];
86     }
87
88     private function classNameFromNodeType(string $nodeType) : string {
89         $className = 'PhpParser\\Node\\' . strtr($nodeType, '_', '\\');
90         if (class_exists($className)) {
91             return $className;
92         }
93
94         $className .= '_';
95         if (class_exists($className)) {
96             return $className;
97         }
98
99         throw new \RuntimeException("Unknown node type \"$nodeType\"");
100     }
101 }