Completed
Push — master ( 436c2d...f2d1ff )
by Josh
03:48
created

Helper::setTaskState()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 15
ccs 9
cts 9
cp 1
rs 9.9666
cc 1
nc 1
nop 4
crap 1
1
<?php declare(strict_types=1);
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2020 The s9e authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Plugins\TaskLists;
9
10
use s9e\TextFormatter\Parser;
11
use s9e\TextFormatter\Parser\Tag;
12
13
class Helper
14
{
15 7
	public static function filterListItem(Parser $parser, Tag $listItem, string $text): void
16
	{
17
		// Test whether the list item is followed by a task checkbox
18 7
		$pos  = $listItem->getPos() + $listItem->getLen();
19 7
		$pos += strspn($text, ' ', $pos);
20 7
		$str  = substr($text, $pos, 3);
21 7
		if (!preg_match('/\\[[ Xx]\\]/', $str))
22
		{
23 1
			return;
24
		}
25
26
		// Create a tag for the task and assign it a random ID
27 7
		$taskId    = uniqid();
28 7
		$taskState = ($str === '[ ]') ? 'unchecked' : 'checked';
29
30 7
		$task = $parser->addSelfClosingTag('TASK', $pos, 3);
31 7
		$task->setAttribute('id',    $taskId);
32 7
		$task->setAttribute('state', $taskState);
33
34 7
		$listItem->cascadeInvalidationTo($task);
35
	}
36
37
	/**
38
	* Return stats from a parsed representation
39
	*
40
	* @param  string $xml Parsed XML
41
	* @return array       Number of "checked" and "unchecked" tasks
42
	*/
43 3
	public static function getStats(string $xml): array
44
	{
45 3
		$stats = ['checked' => 0, 'unchecked' => 0];
46
47 3
		preg_match_all('((?<=<)TASK(?: [^=]++="[^"]*+")*? state="\\K\\w++)', $xml, $m);
48 3
		foreach ($m[0] as $state)
49
		{
50 2
			if (!isset($stats[$state]))
51
			{
52 1
				$stats[$state] = 0;
53
			}
54 2
			++$stats[$state];
55
		}
56
57 3
		return $stats;
58
	}
59
60
	/**
61
	* Mark given task checked in XML
62
	*
63
	* @param  string $xml Parsed XML
64
	* @param  string $id  Task's ID
65
	* @return string      Updated XML
66
	*/
67 7
	public static function checkTask(string $xml, string $id): string
68
	{
69 7
		return self::setTaskState($xml, $id, 'checked', 'x');
70
	}
71
72
	/**
73
	* Mark given task unchecked in XML
74
	*
75
	* @param  string $xml Parsed XML
76
	* @param  string $id  Task's ID
77
	* @return string      Updated XML
78
	*/
79 1
	public static function uncheckTask(string $xml, string $id): string
80
	{
81 1
		return self::setTaskState($xml, $id, 'unchecked', ' ');
82
	}
83
84
	/**
85
	* Change the state and marker of given task in XML
86
	*
87
	* @param  string $xml    Parsed XML
88
	* @param  string $id     Task's ID
89
	* @param  string $state  Task's state ("checked" or "unchecked")
90
	* @param  string $marker State marker ("x" or " ")
91
	* @return string         Updated XML
92
	*/
93 8
	protected static function setTaskState(string $xml, string $id, string $state, string $marker): string
94
	{
95 8
		return preg_replace_callback(
96 8
			'((?<=<)TASK(?: [^=]++="[^"]*+")*? id="' . preg_quote($id) . '"\\K([^>]*+)>[^<]*+(?=</TASK>))',
97
			function ($m) use ($state, $marker)
98
			{
99 6
				preg_match_all('( ([^=]++)="[^"]*+")', $m[1], $m);
100
101 6
				$attributes          = array_combine($m[1], $m[0]);
102 6
				$attributes['state'] = ' state="' . $state . '"';
103 6
				ksort($attributes);
104
105 6
				return implode('', $attributes) . '>[' . $marker . ']';
106 8
			},
107
			$xml
108
		);
109
	}
110
}