Skip to content

Commit ab8da93

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 1c26b97 + 5777817 commit ab8da93

8 files changed

Lines changed: 999 additions & 66 deletions

src/CssAttributeTokenBuilder.php

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
namespace Gt\CssXPath;
4+
5+
class CssAttributeTokenBuilder {
6+
/**
7+
* @return array<string, mixed>
8+
*/
9+
public function build(string $content, ?callable $transform):array {
10+
$operatorData = $this->extractOperator($content);
11+
$token = $this->buildMatchPayload(
12+
"attribute",
13+
$operatorData["name"],
14+
$transform
15+
);
16+
17+
if($operatorData["operator"] === null) {
18+
return $token;
19+
}
20+
21+
$token["detail"] = [
22+
$this->buildMatchPayload(
23+
"attribute_equals",
24+
$operatorData["operator"],
25+
$transform
26+
),
27+
$this->buildMatchPayload(
28+
"attribute_value",
29+
$operatorData["value"],
30+
$transform
31+
),
32+
];
33+
return $token;
34+
}
35+
36+
/**
37+
* @return array{name: string, operator: string|null, value: string}
38+
*/
39+
private function extractOperator(string $content):array {
40+
$operators = ["~=", "$=", "|=", "^=", "*=", "="];
41+
$quote = null;
42+
$length = strlen($content);
43+
44+
for($index = 0; $index < $length; $index++) {
45+
$char = $content[$index];
46+
if($quote !== null) {
47+
if($char === $quote) {
48+
$quote = null;
49+
}
50+
51+
continue;
52+
}
53+
54+
if($char === "'" || $char === '"') {
55+
$quote = $char;
56+
continue;
57+
}
58+
59+
$matchedOperator = $this->matchOperator(
60+
$content,
61+
$index,
62+
$operators
63+
);
64+
if($matchedOperator === null) {
65+
continue;
66+
}
67+
68+
return [
69+
"name" => trim(substr($content, 0, $index)),
70+
"operator" => $matchedOperator,
71+
"value" => trim(
72+
substr($content, $index + strlen($matchedOperator))
73+
),
74+
];
75+
}
76+
77+
return [
78+
"name" => trim($content),
79+
"operator" => null,
80+
"value" => "",
81+
];
82+
}
83+
84+
/**
85+
* @param array<int, string> $operators
86+
*/
87+
private function matchOperator(
88+
string $content,
89+
int $index,
90+
array $operators
91+
):?string {
92+
foreach($operators as $operator) {
93+
if(substr($content, $index, strlen($operator)) === $operator) {
94+
return $operator;
95+
}
96+
}
97+
98+
return null;
99+
}
100+
101+
/** @return array<string, string> */
102+
private function buildMatchPayload(
103+
string $groupKey,
104+
string $match,
105+
?callable $transform
106+
):array {
107+
if($transform) {
108+
return $transform($groupKey, $match);
109+
}
110+
111+
return ["type" => $groupKey, "content" => $match];
112+
}
113+
}

0 commit comments

Comments
 (0)