Skip to content

Commit 95ca9fe

Browse files
DOC-5093 separated out hugotools module and added iterator filter
1 parent 1709be3 commit 95ca9fe

File tree

2 files changed

+130
-116
lines changed

2 files changed

+130
-116
lines changed

build/image_report.py

Lines changed: 1 addition & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,10 @@
11
"""Image report
22
"""
33

4-
from enum import Enum
5-
from typing import Iterator, Match
4+
from pylibs.hugotools import ShortcodeIterator
65

7-
import re
86
import argparse
97

10-
shortcode_re_pattern_start = r"(\n)|\{\{[<%]\s*"
11-
shortcode_re_body = "(/)?([\w\-]+)\s*(.+?)?"
12-
shortcode_re_pattern_end = r"\s*[>%]\}\}"
13-
14-
shortcode_re_pattern = (
15-
shortcode_re_pattern_start +
16-
shortcode_re_body +
17-
shortcode_re_pattern_end
18-
)
19-
20-
21-
class ShortcodeTagType(Enum):
22-
"""Specifies open or close shortcode tag."""
23-
OPEN = 1
24-
CLOSE = 2
25-
26-
27-
class ShortcodeInfo:
28-
"""Represents the information in a shortcode.
29-
"""
30-
tag_type: ShortcodeTagType
31-
tag: str
32-
param_text: str
33-
pos_params: list[str]
34-
named_params: dict[str, str]
35-
36-
def parse_params(self, param_str: str):
37-
param_re = r'"(([^"]|(?<=\\)")*)"|((\w+)=([^"\s]+))|((\w+)="(([^"]|(?<=\\)")*)")|([^"=\s]+)'
38-
39-
for match in re.finditer(param_re, param_str):
40-
if match is None:
41-
self.pos_params = []
42-
self.named_params = {}
43-
return
44-
elif match[1]:
45-
self.pos_params.append(match[1])
46-
elif match[3]:
47-
self.named_params[match[4]] = match[5]
48-
elif match[6]:
49-
self.named_params[match[7]] = match[8]
50-
elif match[10]:
51-
self.pos_params.append(match[10])
52-
53-
def __init__(
54-
self, tag: str,
55-
tag_type: ShortcodeTagType,
56-
param_text: str = ""
57-
):
58-
self.tag = tag
59-
self.tag_type = tag_type
60-
# self.param_text = param_text
61-
self.pos_params = []
62-
self.named_params = {}
63-
self.parse_params(param_text or "")
64-
65-
def __str__(self) -> str:
66-
type_text: str
67-
68-
if self.tag_type == ShortcodeTagType.OPEN:
69-
type_text = "OPEN"
70-
else:
71-
type_text = "CLOSE"
72-
73-
result = f"{type_text} {self.tag}"
74-
75-
if self.pos_params or self.named_params:
76-
result += ":"
77-
78-
for pos_param in self.pos_params:
79-
result += f"\n '{pos_param}'"
80-
81-
for named_param, named_value in self.named_params.items():
82-
result += f"\n {named_param} = {named_value}"
83-
84-
return result
85-
86-
87-
class ShortcodeIterator:
88-
"""Iterates through all shortcodes in a string.
89-
"""
90-
re_iterator: Iterator[Match[str]]
91-
linenum: int
92-
93-
def __init__(self, text: str):
94-
self.re_iterator = re.finditer(shortcode_re_pattern, text)
95-
self.linenum = 1
96-
97-
def __iter__(self):
98-
return self
99-
100-
def __next__(self) -> tuple[ShortcodeInfo, int]:
101-
next_match = self.re_iterator.__next__()
102-
103-
while True:
104-
if next_match[1]:
105-
self.linenum += 1
106-
next_match = self.re_iterator.__next__()
107-
elif next_match[2]:
108-
result = ShortcodeInfo(
109-
next_match[3], ShortcodeTagType.CLOSE
110-
)
111-
112-
return (result, self.linenum)
113-
else:
114-
result = ShortcodeInfo(
115-
next_match[3],
116-
ShortcodeTagType.OPEN,
117-
next_match[4]
118-
)
119-
120-
return (result, self.linenum)
121-
122-
1238
parser = argparse.ArgumentParser(
1249
"Image report",
12510
"Scans a folder and report all Hugo image shortcodes found"

build/pylibs/hugotools.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
from enum import Enum
2+
from typing import Iterator, Match, Callable
3+
4+
import re
5+
6+
shortcode_re_pattern_start = r"(\n)|\{\{[<%]\s*"
7+
shortcode_re_body = r"(/)?([\w\-]+)\s*(.+?)?"
8+
shortcode_re_pattern_end = r"\s*[>%]\}\}"
9+
10+
shortcode_re_pattern = (
11+
shortcode_re_pattern_start +
12+
shortcode_re_body +
13+
shortcode_re_pattern_end
14+
)
15+
16+
17+
class ShortcodeTagType(Enum):
18+
"""Specifies open or close shortcode tag."""
19+
OPEN = 1
20+
CLOSE = 2
21+
22+
23+
class ShortcodeInfo:
24+
"""Represents the information in a shortcode.
25+
"""
26+
tag_type: ShortcodeTagType
27+
tag: str
28+
pos_params: list[str]
29+
named_params: dict[str, str]
30+
31+
def parse_params(self, param_str: str):
32+
param_re = "|".join([
33+
r'"(([^"]|(?<=\\)")*)"',
34+
r'((\w+)=([^"\s]+))',
35+
r'((\w+)="(([^"]|(?<=\\)")*)")',
36+
r'([^"=\s]+)'
37+
])
38+
39+
for match in re.finditer(param_re, param_str):
40+
if match is None:
41+
self.pos_params = []
42+
self.named_params = {}
43+
return
44+
45+
if match[1]:
46+
self.pos_params.append(re.sub(r'\\"', '"', match[1]))
47+
elif match[3]:
48+
self.named_params[match[4]] = match[5]
49+
elif match[6]:
50+
self.named_params[match[7]] = re.sub(r'\\"', '"', match[8])
51+
elif match[10]:
52+
self.pos_params.append(match[10])
53+
54+
def __init__(
55+
self, tag: str,
56+
tag_type: ShortcodeTagType,
57+
param_text: str = ""
58+
):
59+
self.tag = tag
60+
self.tag_type = tag_type
61+
self.pos_params = []
62+
self.named_params = {}
63+
self.parse_params(param_text or "")
64+
65+
def __str__(self) -> str:
66+
type_text: str
67+
68+
if self.tag_type == ShortcodeTagType.OPEN:
69+
type_text = "OPEN"
70+
else:
71+
type_text = "CLOSE"
72+
73+
result = f"{type_text} {self.tag}"
74+
75+
if self.pos_params or self.named_params:
76+
result += ":"
77+
78+
for pos_param in self.pos_params:
79+
result += f"\n '{pos_param}'"
80+
81+
for named_param, named_value in self.named_params.items():
82+
result += f"\n {named_param} = {named_value}"
83+
84+
return result
85+
86+
87+
class ShortcodeIterator:
88+
"""Iterates through all shortcodes in a string.
89+
"""
90+
re_iterator: Iterator[Match[str]]
91+
linenum: int
92+
sc_filter: Callable[[ShortcodeInfo], bool]
93+
94+
def __init__(
95+
self,
96+
text: str,
97+
sc_filter: Callable[[ShortcodeInfo], bool] = lambda x: True
98+
):
99+
self.re_iterator = re.finditer(shortcode_re_pattern, text)
100+
self.sc_filter = lambda self, x: sc_filter(x)
101+
self.linenum = 1
102+
103+
def __iter__(self):
104+
return self
105+
106+
def __next__(self) -> tuple[ShortcodeInfo, int]:
107+
next_match = self.re_iterator.__next__()
108+
109+
while True:
110+
if next_match[1]:
111+
self.linenum += 1
112+
elif next_match[2]:
113+
result = ShortcodeInfo(
114+
next_match[3], ShortcodeTagType.CLOSE
115+
)
116+
117+
if self.sc_filter(self, result):
118+
return (result, self.linenum)
119+
else:
120+
result = ShortcodeInfo(
121+
next_match[3],
122+
ShortcodeTagType.OPEN,
123+
next_match[4]
124+
)
125+
126+
if self.sc_filter(self, result):
127+
return (result, self.linenum)
128+
129+
next_match = self.re_iterator.__next__()

0 commit comments

Comments
 (0)