rolfedh-doc-utils 0.1.13__py3-none-any.whl → 0.1.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- doc_utils/extract_link_attributes.py +55 -13
- doc_utils/replace_link_attributes.py +27 -8
- extract_link_attributes.py +9 -1
- replace_link_attributes.py +19 -3
- {rolfedh_doc_utils-0.1.13.dist-info → rolfedh_doc_utils-0.1.15.dist-info}/METADATA +1 -1
- {rolfedh_doc_utils-0.1.13.dist-info → rolfedh_doc_utils-0.1.15.dist-info}/RECORD +10 -10
- {rolfedh_doc_utils-0.1.13.dist-info → rolfedh_doc_utils-0.1.15.dist-info}/WHEEL +0 -0
- {rolfedh_doc_utils-0.1.13.dist-info → rolfedh_doc_utils-0.1.15.dist-info}/entry_points.txt +0 -0
- {rolfedh_doc_utils-0.1.13.dist-info → rolfedh_doc_utils-0.1.15.dist-info}/licenses/LICENSE +0 -0
- {rolfedh_doc_utils-0.1.13.dist-info → rolfedh_doc_utils-0.1.15.dist-info}/top_level.txt +0 -0
|
@@ -85,10 +85,14 @@ def load_existing_attributes(file_path: str) -> Dict[str, str]:
|
|
|
85
85
|
return attributes
|
|
86
86
|
|
|
87
87
|
|
|
88
|
-
def find_link_macros(file_path: str) -> List[Tuple[str, str, str, int]]:
|
|
88
|
+
def find_link_macros(file_path: str, macro_type: str = 'both') -> List[Tuple[str, str, str, int]]:
|
|
89
89
|
"""
|
|
90
90
|
Find all link: and xref: macros containing attributes in their URLs.
|
|
91
91
|
|
|
92
|
+
Args:
|
|
93
|
+
file_path: Path to the file to scan
|
|
94
|
+
macro_type: Type of macros to find - 'link', 'xref', or 'both' (default: 'both')
|
|
95
|
+
|
|
92
96
|
Returns list of tuples: (full_macro, url, link_text, line_number)
|
|
93
97
|
"""
|
|
94
98
|
macros = []
|
|
@@ -97,10 +101,13 @@ def find_link_macros(file_path: str) -> List[Tuple[str, str, str, int]]:
|
|
|
97
101
|
for line_num, line in enumerate(f, 1):
|
|
98
102
|
# Pattern to match link: and xref: macros
|
|
99
103
|
# Matches: (link|xref):url[text] where url contains {attribute}
|
|
100
|
-
patterns = [
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
patterns = []
|
|
105
|
+
|
|
106
|
+
if macro_type in ('link', 'both'):
|
|
107
|
+
patterns.append(r'(link:([^[\]]*\{[^}]+\}[^[\]]*)\[([^\]]*)\])')
|
|
108
|
+
|
|
109
|
+
if macro_type in ('xref', 'both'):
|
|
110
|
+
patterns.append(r'(xref:([^[\]]*\{[^}]+\}[^[\]]*)\[([^\]]*)\])')
|
|
104
111
|
|
|
105
112
|
for pattern in patterns:
|
|
106
113
|
for match in re.finditer(pattern, line, re.IGNORECASE):
|
|
@@ -228,10 +235,15 @@ def select_link_text(url: str, variations: List[Tuple[str, str, str, int]], inte
|
|
|
228
235
|
return most_common[0]
|
|
229
236
|
|
|
230
237
|
|
|
231
|
-
def collect_all_macros(scan_dirs: List[str] = None) -> List[Tuple[str, str, str, str, int]]:
|
|
238
|
+
def collect_all_macros(scan_dirs: List[str] = None, macro_type: str = 'both', exclude_files: List[str] = None) -> List[Tuple[str, str, str, str, int]]:
|
|
232
239
|
"""
|
|
233
240
|
Collect all link/xref macros with attributes from all .adoc files.
|
|
234
241
|
|
|
242
|
+
Args:
|
|
243
|
+
scan_dirs: Directories to scan (default: current directory)
|
|
244
|
+
macro_type: Type of macros to find - 'link', 'xref', or 'both' (default: 'both')
|
|
245
|
+
exclude_files: List of file paths to exclude from scanning (typically all attributes files)
|
|
246
|
+
|
|
235
247
|
Returns: List[(file_path, full_macro, url, link_text, line_number)]
|
|
236
248
|
"""
|
|
237
249
|
if scan_dirs is None:
|
|
@@ -239,6 +251,13 @@ def collect_all_macros(scan_dirs: List[str] = None) -> List[Tuple[str, str, str,
|
|
|
239
251
|
|
|
240
252
|
all_macros = []
|
|
241
253
|
|
|
254
|
+
# Normalize all exclude file paths
|
|
255
|
+
exclude_paths = set()
|
|
256
|
+
if exclude_files:
|
|
257
|
+
for file in exclude_files:
|
|
258
|
+
if file: # Check for None or empty string
|
|
259
|
+
exclude_paths.add(os.path.abspath(file))
|
|
260
|
+
|
|
242
261
|
for scan_dir in scan_dirs:
|
|
243
262
|
for root, _, files in os.walk(scan_dir):
|
|
244
263
|
# Skip hidden directories and .archive
|
|
@@ -248,7 +267,10 @@ def collect_all_macros(scan_dirs: List[str] = None) -> List[Tuple[str, str, str,
|
|
|
248
267
|
for file in files:
|
|
249
268
|
if file.endswith('.adoc'):
|
|
250
269
|
file_path = os.path.join(root, file)
|
|
251
|
-
|
|
270
|
+
# Skip any attributes files to prevent self-referencing
|
|
271
|
+
if exclude_paths and os.path.abspath(file_path) in exclude_paths:
|
|
272
|
+
continue
|
|
273
|
+
macros = find_link_macros(file_path, macro_type)
|
|
252
274
|
for full_macro, url, link_text, line_num in macros:
|
|
253
275
|
all_macros.append((file_path, full_macro, url, link_text, line_num))
|
|
254
276
|
|
|
@@ -452,10 +474,20 @@ def extract_link_attributes(attributes_file: str = None,
|
|
|
452
474
|
interactive: bool = True,
|
|
453
475
|
dry_run: bool = False,
|
|
454
476
|
validate_links: bool = False,
|
|
455
|
-
fail_on_broken: bool = False
|
|
477
|
+
fail_on_broken: bool = False,
|
|
478
|
+
macro_type: str = 'both') -> bool:
|
|
456
479
|
"""
|
|
457
480
|
Main function to extract link attributes.
|
|
458
481
|
|
|
482
|
+
Args:
|
|
483
|
+
attributes_file: Path to attributes file
|
|
484
|
+
scan_dirs: Directories to scan
|
|
485
|
+
interactive: Enable interactive mode
|
|
486
|
+
dry_run: Preview changes without modifying files
|
|
487
|
+
validate_links: Validate URLs before extraction
|
|
488
|
+
fail_on_broken: Exit if broken links found
|
|
489
|
+
macro_type: Type of macros to process - 'link', 'xref', or 'both' (default: 'both')
|
|
490
|
+
|
|
459
491
|
Returns: True if successful, False otherwise
|
|
460
492
|
"""
|
|
461
493
|
# Find or confirm attributes file
|
|
@@ -489,17 +521,27 @@ def extract_link_attributes(attributes_file: str = None,
|
|
|
489
521
|
existing_attrs = load_existing_attributes(attributes_file)
|
|
490
522
|
spinner.stop(f"Loaded {len(existing_attrs)} existing attributes")
|
|
491
523
|
|
|
492
|
-
#
|
|
493
|
-
|
|
524
|
+
# Find all attributes files to exclude from processing
|
|
525
|
+
all_attribute_files = find_attribute_files()
|
|
526
|
+
|
|
527
|
+
# Notify user about excluded files if there are multiple
|
|
528
|
+
if len(all_attribute_files) > 1:
|
|
529
|
+
print(f"Excluding {len(all_attribute_files)} attributes files from processing:")
|
|
530
|
+
for f in all_attribute_files:
|
|
531
|
+
print(f" - {f}")
|
|
532
|
+
|
|
533
|
+
# Collect all macros, excluding ALL attributes files
|
|
534
|
+
macro_desc = {'link': 'link', 'xref': 'xref', 'both': 'link and xref'}[macro_type]
|
|
535
|
+
spinner = Spinner(f"Scanning for {macro_desc} macros with attributes")
|
|
494
536
|
spinner.start()
|
|
495
|
-
all_macros = collect_all_macros(scan_dirs)
|
|
537
|
+
all_macros = collect_all_macros(scan_dirs, macro_type, exclude_files=all_attribute_files)
|
|
496
538
|
spinner.stop()
|
|
497
539
|
|
|
498
540
|
if not all_macros:
|
|
499
|
-
print("No
|
|
541
|
+
print(f"No {macro_desc} macros with attributes found.")
|
|
500
542
|
return True
|
|
501
543
|
|
|
502
|
-
print(f"Found {len(all_macros)}
|
|
544
|
+
print(f"Found {len(all_macros)} {macro_desc} macros with attributes")
|
|
503
545
|
|
|
504
546
|
# Group by URL
|
|
505
547
|
spinner = Spinner("Grouping macros by URL")
|
|
@@ -65,8 +65,18 @@ def resolve_nested_attributes(attributes: Dict[str, str], max_iterations: int =
|
|
|
65
65
|
return attributes
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def replace_link_attributes_in_file(file_path: Path, attributes: Dict[str, str], dry_run: bool = False) -> int:
|
|
69
|
-
"""
|
|
68
|
+
def replace_link_attributes_in_file(file_path: Path, attributes: Dict[str, str], dry_run: bool = False, macro_type: str = 'both') -> int:
|
|
69
|
+
"""
|
|
70
|
+
Replace attribute references within link macros in a single file.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
file_path: Path to the file to process
|
|
74
|
+
attributes: Dictionary of attribute definitions
|
|
75
|
+
dry_run: Preview changes without modifying files
|
|
76
|
+
macro_type: Type of macros to process - 'link', 'xref', or 'both' (default: 'both')
|
|
77
|
+
|
|
78
|
+
Returns: Number of replacements made
|
|
79
|
+
"""
|
|
70
80
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
71
81
|
content = f.read()
|
|
72
82
|
|
|
@@ -75,14 +85,23 @@ def replace_link_attributes_in_file(file_path: Path, attributes: Dict[str, str],
|
|
|
75
85
|
|
|
76
86
|
# Find all link macros containing attributes in the URL portion only
|
|
77
87
|
# Match link: and xref: macros, capturing URL and text separately
|
|
78
|
-
link_patterns = [
|
|
88
|
+
link_patterns = []
|
|
89
|
+
|
|
90
|
+
if macro_type in ('link', 'both'):
|
|
79
91
|
# link:url[text] - replace only in URL portion
|
|
80
|
-
(r'link:([^[\]]*)\[([^\]]*)\]', 'link')
|
|
92
|
+
link_patterns.append((r'link:([^[\]]*)\[([^\]]*)\]', 'link'))
|
|
93
|
+
|
|
94
|
+
if macro_type in ('xref', 'both'):
|
|
81
95
|
# xref:target[text] - replace only in target portion
|
|
82
|
-
(r'xref:([^[\]]*)\[([^\]]*)\]', 'xref')
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
link_patterns.append((r'xref:([^[\]]*)\[([^\]]*)\]', 'xref'))
|
|
97
|
+
|
|
98
|
+
# Handle empty text cases based on macro type
|
|
99
|
+
if macro_type == 'both':
|
|
100
|
+
link_patterns.append((r'(link|xref):([^[\]]*)\[\]', 'empty_text'))
|
|
101
|
+
elif macro_type == 'link':
|
|
102
|
+
link_patterns.append((r'(link):([^[\]]*)\[\]', 'empty_text'))
|
|
103
|
+
elif macro_type == 'xref':
|
|
104
|
+
link_patterns.append((r'(xref):([^[\]]*)\[\]', 'empty_text'))
|
|
86
105
|
|
|
87
106
|
for pattern, link_type in link_patterns:
|
|
88
107
|
matches = list(re.finditer(pattern, content))
|
extract_link_attributes.py
CHANGED
|
@@ -77,6 +77,13 @@ Examples:
|
|
|
77
77
|
help='Exit extraction if broken links are found in attributes (requires --validate-links)'
|
|
78
78
|
)
|
|
79
79
|
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
'--macro-type',
|
|
82
|
+
choices=['link', 'xref', 'both'],
|
|
83
|
+
default='both',
|
|
84
|
+
help='Type of macros to process: link, xref, or both (default: both)'
|
|
85
|
+
)
|
|
86
|
+
|
|
80
87
|
args = parser.parse_args()
|
|
81
88
|
|
|
82
89
|
try:
|
|
@@ -86,7 +93,8 @@ Examples:
|
|
|
86
93
|
interactive=not args.non_interactive,
|
|
87
94
|
dry_run=args.dry_run,
|
|
88
95
|
validate_links=args.validate_links,
|
|
89
|
-
fail_on_broken=args.fail_on_broken
|
|
96
|
+
fail_on_broken=args.fail_on_broken,
|
|
97
|
+
macro_type=args.macro_type
|
|
90
98
|
)
|
|
91
99
|
|
|
92
100
|
if not success:
|
replace_link_attributes.py
CHANGED
|
@@ -102,6 +102,12 @@ def main():
|
|
|
102
102
|
type=str,
|
|
103
103
|
help='Path to attributes.adoc file (skips interactive selection)'
|
|
104
104
|
)
|
|
105
|
+
parser.add_argument(
|
|
106
|
+
'--macro-type',
|
|
107
|
+
choices=['link', 'xref', 'both'],
|
|
108
|
+
default='both',
|
|
109
|
+
help='Type of macros to process: link, xref, or both (default: both)'
|
|
110
|
+
)
|
|
105
111
|
|
|
106
112
|
args = parser.parse_args()
|
|
107
113
|
|
|
@@ -149,8 +155,18 @@ def main():
|
|
|
149
155
|
adoc_files = find_adoc_files(repo_root)
|
|
150
156
|
spinner.stop()
|
|
151
157
|
|
|
152
|
-
#
|
|
153
|
-
|
|
158
|
+
# Find ALL attributes files to exclude from processing
|
|
159
|
+
all_attribute_files = find_attributes_files(repo_root)
|
|
160
|
+
exclude_paths = {f.resolve() for f in all_attribute_files}
|
|
161
|
+
|
|
162
|
+
# Notify user about excluded files if there are multiple
|
|
163
|
+
if len(all_attribute_files) > 1:
|
|
164
|
+
print(f"Excluding {len(all_attribute_files)} attributes files from processing:")
|
|
165
|
+
for f in all_attribute_files:
|
|
166
|
+
print(f" - {f.relative_to(repo_root)}")
|
|
167
|
+
|
|
168
|
+
# Exclude ALL attributes files, not just the selected one
|
|
169
|
+
adoc_files = [f for f in adoc_files if f.resolve() not in exclude_paths]
|
|
154
170
|
|
|
155
171
|
print(f"Found {len(adoc_files)} AsciiDoc files to process")
|
|
156
172
|
|
|
@@ -165,7 +181,7 @@ def main():
|
|
|
165
181
|
spinner.start()
|
|
166
182
|
|
|
167
183
|
for file_path in adoc_files:
|
|
168
|
-
replacements = replace_link_attributes_in_file(file_path, attributes, args.dry_run)
|
|
184
|
+
replacements = replace_link_attributes_in_file(file_path, attributes, args.dry_run, args.macro_type)
|
|
169
185
|
if replacements > 0:
|
|
170
186
|
rel_path = file_path.relative_to(repo_root)
|
|
171
187
|
total_replacements += replacements
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
archive_unused_files.py,sha256=h7CRwSPBVCOQs0hn_ASD4EXz8QJFcAO2x3KX9FVhXNM,1974
|
|
2
2
|
archive_unused_images.py,sha256=4GSVPYkxqFoY-isy47P_1AhD1ziXgmajFiBGCtZ3olg,1564
|
|
3
3
|
check_scannability.py,sha256=MvGLW4UGGcx-jZLsVRYXpXNAIEQyJZZnsN99zJzbtyc,5178
|
|
4
|
-
extract_link_attributes.py,sha256=
|
|
4
|
+
extract_link_attributes.py,sha256=grPvVwOF9kqIOZ_uxYtJTkO3C2DNtIpKNPp6LlGK3Xs,3216
|
|
5
5
|
find_unused_attributes.py,sha256=IUJKJr_MzxBXqg9rafUs9Kwi8AbU0x-H0AVflc1dhCU,3288
|
|
6
6
|
format_asciidoc_spacing.py,sha256=_XpHqxYWm1AnZLUK_cDpfAJtsDCDF0b66m3opfYnIuU,3912
|
|
7
|
-
replace_link_attributes.py,sha256=
|
|
7
|
+
replace_link_attributes.py,sha256=lJHrzIRJOmdt5WzCD0Lf-v9lOJDXBV7b75bOFZLNDPQ,7324
|
|
8
8
|
validate_links.py,sha256=409fTAyBGTUrp6iSWuJ9AXExcdz8dC_4QeA_RvCIhus,5845
|
|
9
9
|
doc_utils/__init__.py,sha256=qqZR3lohzkP63soymrEZPBGzzk6-nFzi4_tSffjmu_0,74
|
|
10
|
-
doc_utils/extract_link_attributes.py,sha256=
|
|
10
|
+
doc_utils/extract_link_attributes.py,sha256=U0EvPZReJQigNfbT-icBsVT6Li64hYki5W7MQz6qqbc,22743
|
|
11
11
|
doc_utils/file_utils.py,sha256=fpTh3xx759sF8sNocdn_arsP3KAv8XA6cTQTAVIZiZg,4247
|
|
12
12
|
doc_utils/format_asciidoc_spacing.py,sha256=XnVJekaj39aDzjV3xFKl58flM41AaJzejxNYJIIAMz0,10139
|
|
13
|
-
doc_utils/replace_link_attributes.py,sha256=
|
|
13
|
+
doc_utils/replace_link_attributes.py,sha256=gmAs68_njBqEz-Qni-UGgeYEDTMxlTWk_IOm76FONNE,7279
|
|
14
14
|
doc_utils/scannability.py,sha256=XwlmHqDs69p_V36X7DLjPTy0DUoLszSGqYjJ9wE-3hg,982
|
|
15
15
|
doc_utils/spinner.py,sha256=lJg15qzODiKoR0G6uFIk2BdVNgn9jFexoTRUMrjiWvk,3554
|
|
16
16
|
doc_utils/topic_map_parser.py,sha256=tKcIO1m9r2K6dvPRGue58zqMr0O2zKU1gnZMzEE3U6o,4571
|
|
@@ -18,9 +18,9 @@ doc_utils/unused_adoc.py,sha256=2cbqcYr1os2EhETUU928BlPRlsZVSdI00qaMhqjSIqQ,5263
|
|
|
18
18
|
doc_utils/unused_attributes.py,sha256=EjTtWIKW_aXsR1JOgw5RSDVAqitJ_NfRMVOXVGaiWTY,5282
|
|
19
19
|
doc_utils/unused_images.py,sha256=nqn36Bbrmon2KlGlcaruNjJJvTQ8_9H0WU9GvCW7rW8,1456
|
|
20
20
|
doc_utils/validate_links.py,sha256=iBGXnwdeLlgIT3fo3v01ApT5k0X2FtctsvkrE6E3VMk,19610
|
|
21
|
-
rolfedh_doc_utils-0.1.
|
|
22
|
-
rolfedh_doc_utils-0.1.
|
|
23
|
-
rolfedh_doc_utils-0.1.
|
|
24
|
-
rolfedh_doc_utils-0.1.
|
|
25
|
-
rolfedh_doc_utils-0.1.
|
|
26
|
-
rolfedh_doc_utils-0.1.
|
|
21
|
+
rolfedh_doc_utils-0.1.15.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
|
|
22
|
+
rolfedh_doc_utils-0.1.15.dist-info/METADATA,sha256=wUhG5aOP3eUggSenYO_D3bS8R4wCI7abvg1F7gWgR3E,7386
|
|
23
|
+
rolfedh_doc_utils-0.1.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
24
|
+
rolfedh_doc_utils-0.1.15.dist-info/entry_points.txt,sha256=2J4Ojc3kkuArpe2xcUOPc0LxSWCmnctvw8hy8zpnbO4,418
|
|
25
|
+
rolfedh_doc_utils-0.1.15.dist-info/top_level.txt,sha256=1w0JWD7w7gnM5Sga2K4fJieNZ7CHPTAf0ozYk5iIlmo,182
|
|
26
|
+
rolfedh_doc_utils-0.1.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|