Passed
Branch main (02a65c)
by Jean-Christophe
13:46
created

JSX::parseTextNode()   B

Complexity

Conditions 9
Paths 7

Size

Total Lines 17
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 9.0294

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 9
eloc 14
c 1
b 0
f 1
nc 7
nop 3
dl 0
loc 17
ccs 13
cts 14
cp 0.9286
crap 9.0294
rs 8.0555
1
<?php
2
namespace PHPMV\utils;
3
4
use PHPMV\js\JavascriptUtils;
5
use PHPMV\react\ReactJS;
6
7
/**
8
 * PHPMV\utils$JSX
9
 * This class is part of Ubiquity
10
 *
11
 * @author jc
12
 * @version 1.0.0
13
 *
14
 */
15
class JSX {
16
17
	public static $reactCreateElement = 'React.createElement';
18
19
	private static $jsDetect = [
20
		'onBlur' => 0,
21
		'onChange' => 0,
22
		'onDblclick' => 0,
23
		'onClick' => 0,
24
		'onSubmit' => 0,
25
		'value' => 0,
26
		'items' => 0,
27
		'defaultValue' => 0,
28
		'dangerouslySetInnerHTML' => 0
29
	];
30
31 5
	private static function getName(string $name, ReactJS $react): string {
32 5
		return $react->components[$name] ?? '"' . $name . '"';
33
	}
34
35
	private static $attributes = [
36
		'classname' => 'className',
37
		'onblur' => 'onBlur',
38
		'onclick' => 'onClick',
39
		'onchange' => 'onChange',
40
		'onsubmit' => 'onSubmit',
41
		'defaultvalue' => 'defaultValue',
42
		'dangerouslysetinnerhtml' => 'dangerouslySetInnerHTML',
43
		'htmlfor' => 'htmlFor'
44
	];
45
46 5
	private static function cleanJSONFunctions(string $json): string {
47 5
		return \str_replace([
48 5
			'"!!%',
49
			'%!!"'
50 5
		], '', $json);
51
	}
52
53 4
	private static function hasBraces(string $str): bool {
54 4
		return (\substr($str, 0, 1) === '{' && \substr($str, - 1) === '}');
55
	}
56
57 5
	private static function nodeToJs(\DOMNode $root, ?ReactJS $react): string {
58 5
		$attributes = [];
59 5
		$name = $root->nodeName;
60
61 5
		if ($root->hasAttributes()) {
62 4
			$attrs = $root->attributes;
63
64 4
			foreach ($attrs as $i => $attr) {
65 4
				$attrName = self::$attributes[$attr->name] ?? $attr->name;
66 4
				$attrValue = $attr->value;
67 4
				if (isset(self::$jsDetect[$attrName])) {
68 3
					if (self::hasBraces($attrValue)) {
69 3
						$attrValue = \substr($attrValue, 1, - 1);
70
					}
71 3
					$attributes[$attrName] = '!!%' . $attrValue . '%!!';
72
				} else {
73 4
					$attributes[$attrName] = $attrValue;
74
				}
75
			}
76
		}
77 5
		$childrenStr = self::getChildrenStr($root, $react);
78 5
		return self::$reactCreateElement . "(" . ((isset($react)) ? self::getName($name, $react) : $name) . "," . self::cleanJSONFunctions(JavascriptUtils::toJSON($attributes)) . "$childrenStr)";
79
	}
80
81 5
	private static function getChildrenStr(\DOMNode $root, ?ReactJS $react): string {
82 5
		$children = [];
83
84 5
		$childNodes = $root->childNodes;
85 5
		$open = null;
86 5
		for ($i = 0; $i < $childNodes->length; $i ++) {
87 4
			$child = $childNodes->item($i);
88 4
			if ($child->nodeType == XML_TEXT_NODE) {
89 4
				$v = \trim($child->nodeValue);
90 4
				if ($v != null) {
91 4
					self::parseTextNode($v, $children, $open);
92
				}
93
			} else {
94 3
				if ($open != '') {
95 1
					$open .= self::nodeToJs($child, $react);
96
				} else {
97 3
					$children[] = self::nodeToJs($child, $react);
98
				}
99
			}
100
		}
101 5
		return (count($children) > 0) ? (',' . implode(',', $children)) : '';
102
	}
103
104 4
	private static function parseTextNode(string $v, array &$children, ?string &$open) {
105 4
		$parts = \preg_split('@(\{.*?\})@', $v, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
106 4
		if ($parts && \count($parts) > 0) {
107 4
			foreach ($parts as $ev) {
108 4
				if (self::hasBraces($ev)) {
109 3
					$children[] = \substr($ev, 1, - 1);
110 4
				} elseif (\substr($ev, 0, 1) === '{') {
111 1
					$open = \substr($ev, 1);
112 4
				} elseif ($open != '' && \substr($ev, - 1) === '}') {
113 1
					$children[] = $open . \substr($ev, 0, - 1);
114 1
					$open = '';
115 4
				} elseif (\trim($ev) != null) {
116 3
					$children[] = '"' . $ev . '"';
117
				}
118
			}
119
		} else {
120
			$children[] = "`$v`";
121
		}
122 4
	}
123
124 5
	public static function toJs(string $html, ?ReactJS $react = null): string {
125 5
		\libxml_use_internal_errors(true);
126 5
		$dom = new \DOMDocument('1.0', 'UTF-8');
127 5
		$dom->loadHTML(\mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
0 ignored issues
show
Bug introduced by
It seems like mb_convert_encoding($htm...TML-ENTITIES', 'UTF-8') can also be of type array; however, parameter $source of DOMDocument::loadHTML() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

127
		$dom->loadHTML(/** @scrutinizer ignore-type */ \mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
Loading history...
128 5
		return self::nodeToJs($dom->documentElement, $react);
129
	}
130
}
131