rolfedh-doc-utils 0.1.13__tar.gz → 0.1.15__tar.gz
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.
- {rolfedh_doc_utils-0.1.13/rolfedh_doc_utils.egg-info → rolfedh_doc_utils-0.1.15}/PKG-INFO +1 -1
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/extract_link_attributes.py +55 -13
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/replace_link_attributes.py +27 -8
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/extract_link_attributes.py +9 -1
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/pyproject.toml +1 -1
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/replace_link_attributes.py +19 -3
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15/rolfedh_doc_utils.egg-info}/PKG-INFO +1 -1
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/rolfedh_doc_utils.egg-info/SOURCES.txt +1 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_extract_link_attributes.py +31 -1
- rolfedh_doc_utils-0.1.15/tests/test_replace_link_attributes.py +215 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/LICENSE +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/README.md +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/__init__.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/file_utils.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/format_asciidoc_spacing.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/scannability.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/spinner.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/topic_map_parser.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/unused_adoc.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/doc_utils/validate_links.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/find_unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/format_asciidoc_spacing.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/rolfedh_doc_utils.egg-info/dependency_links.txt +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/rolfedh_doc_utils.egg-info/entry_points.txt +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/rolfedh_doc_utils.egg-info/requires.txt +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/rolfedh_doc_utils.egg-info/top_level.txt +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/setup.cfg +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/setup.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_auto_discovery.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_cli_entry_points.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_file_utils.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_fixture_archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_fixture_archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_fixture_check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_parse_exclude_list.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_symlink_handling.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_topic_map_parser.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_validate_links.py +0 -0
- {rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/validate_links.py +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))
|
|
@@ -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:
|
|
@@ -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
|
{rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/rolfedh_doc_utils.egg-info/SOURCES.txt
RENAMED
|
@@ -39,6 +39,7 @@ tests/test_fixture_archive_unused_files.py
|
|
|
39
39
|
tests/test_fixture_archive_unused_images.py
|
|
40
40
|
tests/test_fixture_check_scannability.py
|
|
41
41
|
tests/test_parse_exclude_list.py
|
|
42
|
+
tests/test_replace_link_attributes.py
|
|
42
43
|
tests/test_symlink_handling.py
|
|
43
44
|
tests/test_topic_map_parser.py
|
|
44
45
|
tests/test_unused_attributes.py
|
|
@@ -90,6 +90,36 @@ Regular link: link:https://example.com/guide.html[Guide]
|
|
|
90
90
|
macros = find_link_macros(str(test_file))
|
|
91
91
|
assert len(macros) == 0
|
|
92
92
|
|
|
93
|
+
def test_find_only_link_macros(self, tmp_path):
|
|
94
|
+
"""Test finding only link macros when macro_type='link'."""
|
|
95
|
+
test_file = tmp_path / "test.adoc"
|
|
96
|
+
test_file.write_text("""
|
|
97
|
+
= Test Document
|
|
98
|
+
|
|
99
|
+
See link:https://example.com/{version}/guide.html[Guide].
|
|
100
|
+
Also check xref:{base-url}/intro.html[Intro].
|
|
101
|
+
""")
|
|
102
|
+
|
|
103
|
+
macros = find_link_macros(str(test_file), macro_type='link')
|
|
104
|
+
|
|
105
|
+
assert len(macros) == 1
|
|
106
|
+
assert macros[0][0] == "link:https://example.com/{version}/guide.html[Guide]"
|
|
107
|
+
|
|
108
|
+
def test_find_only_xref_macros(self, tmp_path):
|
|
109
|
+
"""Test finding only xref macros when macro_type='xref'."""
|
|
110
|
+
test_file = tmp_path / "test.adoc"
|
|
111
|
+
test_file.write_text("""
|
|
112
|
+
= Test Document
|
|
113
|
+
|
|
114
|
+
See link:https://example.com/{version}/guide.html[Guide].
|
|
115
|
+
Also check xref:{base-url}/intro.html[Intro].
|
|
116
|
+
""")
|
|
117
|
+
|
|
118
|
+
macros = find_link_macros(str(test_file), macro_type='xref')
|
|
119
|
+
|
|
120
|
+
assert len(macros) == 1
|
|
121
|
+
assert macros[0][0] == "xref:{base-url}/intro.html[Intro]"
|
|
122
|
+
|
|
93
123
|
|
|
94
124
|
class TestGenerateAttributeName:
|
|
95
125
|
"""Tests for generate_attribute_name function."""
|
|
@@ -317,7 +347,7 @@ And xref:{base-url}/intro.html[Introduction] for overview.
|
|
|
317
347
|
|
|
318
348
|
# Check output
|
|
319
349
|
captured = capsys.readouterr()
|
|
320
|
-
assert "Found 3 link
|
|
350
|
+
assert "Found 3 link and xref macros" in captured.out
|
|
321
351
|
assert "Grouped into 2 unique URLs" in captured.out
|
|
322
352
|
assert "[DRY RUN]" in captured.out
|
|
323
353
|
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Tests for replace_link_attributes module."""
|
|
3
|
+
|
|
4
|
+
import tempfile
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import pytest
|
|
7
|
+
from doc_utils.replace_link_attributes import (
|
|
8
|
+
load_attributes,
|
|
9
|
+
resolve_nested_attributes,
|
|
10
|
+
replace_link_attributes_in_file,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestLoadAttributes:
|
|
15
|
+
"""Tests for load_attributes function."""
|
|
16
|
+
|
|
17
|
+
def test_load_basic_attributes(self, tmp_path):
|
|
18
|
+
"""Test loading basic attribute definitions."""
|
|
19
|
+
attr_file = tmp_path / "attributes.adoc"
|
|
20
|
+
attr_file.write_text("""
|
|
21
|
+
// Common attributes
|
|
22
|
+
:product-name: My Product
|
|
23
|
+
:version: 1.0
|
|
24
|
+
:docs-url: https://docs.example.com
|
|
25
|
+
""")
|
|
26
|
+
|
|
27
|
+
attrs = load_attributes(attr_file)
|
|
28
|
+
|
|
29
|
+
assert len(attrs) == 3
|
|
30
|
+
assert attrs["product-name"] == "My Product"
|
|
31
|
+
assert attrs["version"] == "1.0"
|
|
32
|
+
assert attrs["docs-url"] == "https://docs.example.com"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TestResolveNestedAttributes:
|
|
36
|
+
"""Tests for resolve_nested_attributes function."""
|
|
37
|
+
|
|
38
|
+
def test_resolve_simple_nesting(self):
|
|
39
|
+
"""Test resolving simple nested attributes."""
|
|
40
|
+
attributes = {
|
|
41
|
+
"base-url": "https://example.com",
|
|
42
|
+
"docs-url": "{base-url}/docs",
|
|
43
|
+
"guide-url": "{docs-url}/guide.html"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
resolved = resolve_nested_attributes(attributes)
|
|
47
|
+
|
|
48
|
+
assert resolved["base-url"] == "https://example.com"
|
|
49
|
+
assert resolved["docs-url"] == "https://example.com/docs"
|
|
50
|
+
assert resolved["guide-url"] == "https://example.com/docs/guide.html"
|
|
51
|
+
|
|
52
|
+
def test_no_nesting(self):
|
|
53
|
+
"""Test attributes without nesting."""
|
|
54
|
+
attributes = {
|
|
55
|
+
"url1": "https://example.com",
|
|
56
|
+
"url2": "https://another.com"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
resolved = resolve_nested_attributes(attributes)
|
|
60
|
+
|
|
61
|
+
assert resolved == attributes
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class TestReplaceLinkAttributesInFile:
|
|
65
|
+
"""Tests for replace_link_attributes_in_file function."""
|
|
66
|
+
|
|
67
|
+
def test_replace_in_link_macro(self, tmp_path):
|
|
68
|
+
"""Test replacing attributes in link: macros."""
|
|
69
|
+
test_file = tmp_path / "test.adoc"
|
|
70
|
+
test_file.write_text("""
|
|
71
|
+
= Test Document
|
|
72
|
+
|
|
73
|
+
See link:{docs-url}/guide.html[User Guide] for details.
|
|
74
|
+
""")
|
|
75
|
+
|
|
76
|
+
attributes = {"docs-url": "https://docs.example.com"}
|
|
77
|
+
|
|
78
|
+
count = replace_link_attributes_in_file(test_file, attributes, dry_run=False)
|
|
79
|
+
|
|
80
|
+
assert count == 1
|
|
81
|
+
content = test_file.read_text()
|
|
82
|
+
assert "link:https://docs.example.com/guide.html[User Guide]" in content
|
|
83
|
+
assert "{docs-url}" not in content
|
|
84
|
+
|
|
85
|
+
def test_replace_in_xref_macro(self, tmp_path):
|
|
86
|
+
"""Test replacing attributes in xref: macros."""
|
|
87
|
+
test_file = tmp_path / "test.adoc"
|
|
88
|
+
test_file.write_text("""
|
|
89
|
+
= Test Document
|
|
90
|
+
|
|
91
|
+
Check xref:{base-path}/intro.adoc[Introduction].
|
|
92
|
+
""")
|
|
93
|
+
|
|
94
|
+
attributes = {"base-path": "modules"}
|
|
95
|
+
|
|
96
|
+
count = replace_link_attributes_in_file(test_file, attributes, dry_run=False)
|
|
97
|
+
|
|
98
|
+
assert count == 1
|
|
99
|
+
content = test_file.read_text()
|
|
100
|
+
assert "xref:modules/intro.adoc[Introduction]" in content
|
|
101
|
+
|
|
102
|
+
def test_preserve_link_text(self, tmp_path):
|
|
103
|
+
"""Test that link text is preserved unchanged."""
|
|
104
|
+
test_file = tmp_path / "test.adoc"
|
|
105
|
+
test_file.write_text("""
|
|
106
|
+
= Test
|
|
107
|
+
|
|
108
|
+
link:{url}/page.html[Custom Link Text]
|
|
109
|
+
""")
|
|
110
|
+
|
|
111
|
+
attributes = {"url": "https://example.com"}
|
|
112
|
+
|
|
113
|
+
replace_link_attributes_in_file(test_file, attributes, dry_run=False)
|
|
114
|
+
|
|
115
|
+
content = test_file.read_text()
|
|
116
|
+
assert "[Custom Link Text]" in content
|
|
117
|
+
|
|
118
|
+
def test_dry_run_no_changes(self, tmp_path):
|
|
119
|
+
"""Test that dry-run mode doesn't modify files."""
|
|
120
|
+
test_file = tmp_path / "test.adoc"
|
|
121
|
+
original_content = """
|
|
122
|
+
link:{url}/page.html[Link]
|
|
123
|
+
"""
|
|
124
|
+
test_file.write_text(original_content)
|
|
125
|
+
|
|
126
|
+
attributes = {"url": "https://example.com"}
|
|
127
|
+
|
|
128
|
+
replace_link_attributes_in_file(test_file, attributes, dry_run=True)
|
|
129
|
+
|
|
130
|
+
# File should be unchanged
|
|
131
|
+
assert test_file.read_text() == original_content
|
|
132
|
+
|
|
133
|
+
def test_macro_type_link_only(self, tmp_path):
|
|
134
|
+
"""Test processing only link: macros."""
|
|
135
|
+
test_file = tmp_path / "test.adoc"
|
|
136
|
+
test_file.write_text("""
|
|
137
|
+
= Test Document
|
|
138
|
+
|
|
139
|
+
link:{docs-url}/guide.html[Guide]
|
|
140
|
+
xref:{base-path}/intro.adoc[Intro]
|
|
141
|
+
""")
|
|
142
|
+
|
|
143
|
+
attributes = {
|
|
144
|
+
"docs-url": "https://docs.example.com",
|
|
145
|
+
"base-path": "modules"
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
count = replace_link_attributes_in_file(test_file, attributes, dry_run=False, macro_type='link')
|
|
149
|
+
|
|
150
|
+
assert count == 1
|
|
151
|
+
content = test_file.read_text()
|
|
152
|
+
assert "link:https://docs.example.com/guide.html[Guide]" in content
|
|
153
|
+
assert "xref:{base-path}/intro.adoc[Intro]" in content # xref unchanged
|
|
154
|
+
|
|
155
|
+
def test_macro_type_xref_only(self, tmp_path):
|
|
156
|
+
"""Test processing only xref: macros."""
|
|
157
|
+
test_file = tmp_path / "test.adoc"
|
|
158
|
+
test_file.write_text("""
|
|
159
|
+
= Test Document
|
|
160
|
+
|
|
161
|
+
link:{docs-url}/guide.html[Guide]
|
|
162
|
+
xref:{base-path}/intro.adoc[Intro]
|
|
163
|
+
""")
|
|
164
|
+
|
|
165
|
+
attributes = {
|
|
166
|
+
"docs-url": "https://docs.example.com",
|
|
167
|
+
"base-path": "modules"
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
count = replace_link_attributes_in_file(test_file, attributes, dry_run=False, macro_type='xref')
|
|
171
|
+
|
|
172
|
+
assert count == 1
|
|
173
|
+
content = test_file.read_text()
|
|
174
|
+
assert "link:{docs-url}/guide.html[Guide]" in content # link unchanged
|
|
175
|
+
assert "xref:modules/intro.adoc[Intro]" in content
|
|
176
|
+
|
|
177
|
+
def test_macro_type_both(self, tmp_path):
|
|
178
|
+
"""Test processing both link: and xref: macros."""
|
|
179
|
+
test_file = tmp_path / "test.adoc"
|
|
180
|
+
test_file.write_text("""
|
|
181
|
+
= Test Document
|
|
182
|
+
|
|
183
|
+
link:{docs-url}/guide.html[Guide]
|
|
184
|
+
xref:{base-path}/intro.adoc[Intro]
|
|
185
|
+
""")
|
|
186
|
+
|
|
187
|
+
attributes = {
|
|
188
|
+
"docs-url": "https://docs.example.com",
|
|
189
|
+
"base-path": "modules"
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
count = replace_link_attributes_in_file(test_file, attributes, dry_run=False, macro_type='both')
|
|
193
|
+
|
|
194
|
+
assert count == 2
|
|
195
|
+
content = test_file.read_text()
|
|
196
|
+
assert "link:https://docs.example.com/guide.html[Guide]" in content
|
|
197
|
+
assert "xref:modules/intro.adoc[Intro]" in content
|
|
198
|
+
|
|
199
|
+
def test_multiple_attributes_in_url(self, tmp_path):
|
|
200
|
+
"""Test replacing multiple attributes in a single URL."""
|
|
201
|
+
test_file = tmp_path / "test.adoc"
|
|
202
|
+
test_file.write_text("""
|
|
203
|
+
link:{base-url}/{version}/guide.html[Guide]
|
|
204
|
+
""")
|
|
205
|
+
|
|
206
|
+
attributes = {
|
|
207
|
+
"base-url": "https://example.com",
|
|
208
|
+
"version": "v2.0"
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
count = replace_link_attributes_in_file(test_file, attributes, dry_run=False)
|
|
212
|
+
|
|
213
|
+
assert count == 2
|
|
214
|
+
content = test_file.read_text()
|
|
215
|
+
assert "link:https://example.com/v2.0/guide.html[Guide]" in content
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/rolfedh_doc_utils.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/rolfedh_doc_utils.egg-info/requires.txt
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/rolfedh_doc_utils.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_fixture_archive_unused_files.py
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_fixture_archive_unused_images.py
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.13 → rolfedh_doc_utils-0.1.15}/tests/test_fixture_check_scannability.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|