Passed
Push — master ( 20a3c1...d391f6 )
by Josh
02:08
created

FunctionCache::addFromXSL()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 26
rs 9.5222
cc 5
nc 4
nop 1
1
<?php declare(strict_types=1);
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2022 The s9e authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Configurator\JavaScript;
9
10
use s9e\SweetDOM\Document;
11
use s9e\TextFormatter\Configurator\Helpers\AVTHelper;
12
13
class FunctionCache
14
{
15
	protected array $cache = [];
16
17
	/**
18
	* @var array Map of JavaScript interfaces that may be useful to Google Closure Compiler
19
	*/
20
	public array $elementInterfaces = [
21
		'iframe' => 'HTMLIFrameElement',
22
		'script' => 'HTMLScriptElement'
23
	];
24
25
	/**
26
	* Add all live preview events from given XSL
27
	*/
28
	public function addFromXSL(string $xsl): void
29
	{
30
		$dom = new Document;
31
		$dom->loadXML($xsl);
32
33
		foreach ($dom->query('//@*[starts-with(name(), "data-s9e-livepreview-on")]') as $attribute)
34
		{
35
			$js  = $attribute->textContent;
0 ignored issues
show
Unused Code introduced by
The assignment to $js is dead and can be removed.
Loading history...
36
			$avt = AVTHelper::parse($attribute->textContent);
37
			if (count($avt) !== 1 || $avt[0][0] !== 'literal')
38
			{
39
				continue;
40
			}
41
42
			// Use the unescaped value from AVTHelper
43
			$js  = $avt[0][1];
44
			$key = (string) Hasher::quickHash($js);
45
46
			// Make sure the code ends with a semicolon or a brace
47
			if (!preg_match('([;}]$)', $js))
48
			{
49
				$js .= ';';
50
			}
51
52
			$this->cache[$key]['code']       = $js;
53
			$this->cache[$key]['elements'][] = $attribute->parentNode->tagName;
54
		}
55
	}
56
57
	/**
58
	* @return string Current cache as a JSON object
59
	*/
60
	public function getJSON(): string
61
	{
62
		$cache = [];
63
		foreach ($this->cache as $key => $entry)
64
		{
65
			$types = [];
66
			foreach ($entry['elements'] as $nodeName)
67
			{
68
				// Use the element's JavaScript interface if known, otherwise just use Element
69
				$types[] = '!' . ($this->elementInterfaces[$nodeName] ?? 'Element');
70
			}
71
			$types = array_unique($types);
72
			sort($types);
73
74
			$cache[$key] = json_encode((string) $key) . ':/**@this {' . implode('|', $types) . '}*/function(){' . $entry['code'] . '}';
75
		}
76
		ksort($cache);
77
78
		return '{' . implode(',', $cache) . '}';
79
	}
80
}