rolfedh-doc-utils 0.1.12__tar.gz → 0.1.14__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.12/rolfedh_doc_utils.egg-info → rolfedh_doc_utils-0.1.14}/PKG-INFO +1 -1
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/extract_link_attributes.py +58 -25
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/replace_link_attributes.py +27 -8
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/extract_link_attributes.py +9 -1
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/pyproject.toml +1 -1
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/replace_link_attributes.py +7 -1
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14/rolfedh_doc_utils.egg-info}/PKG-INFO +1 -1
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/rolfedh_doc_utils.egg-info/SOURCES.txt +1 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_extract_link_attributes.py +36 -3
- rolfedh_doc_utils-0.1.14/tests/test_replace_link_attributes.py +215 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/LICENSE +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/README.md +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/__init__.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/file_utils.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/format_asciidoc_spacing.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/scannability.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/spinner.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/topic_map_parser.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/unused_adoc.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/doc_utils/validate_links.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/find_unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/format_asciidoc_spacing.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/rolfedh_doc_utils.egg-info/dependency_links.txt +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/rolfedh_doc_utils.egg-info/entry_points.txt +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/rolfedh_doc_utils.egg-info/requires.txt +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/rolfedh_doc_utils.egg-info/top_level.txt +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/setup.cfg +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/setup.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_auto_discovery.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_cli_entry_points.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_file_utils.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_fixture_archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_fixture_archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_fixture_check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_parse_exclude_list.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_symlink_handling.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_topic_map_parser.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_validate_links.py +0 -0
- {rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/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,14 @@ 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') -> 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
|
+
|
|
235
246
|
Returns: List[(file_path, full_macro, url, link_text, line_number)]
|
|
236
247
|
"""
|
|
237
248
|
if scan_dirs is None:
|
|
@@ -248,7 +259,7 @@ def collect_all_macros(scan_dirs: List[str] = None) -> List[Tuple[str, str, str,
|
|
|
248
259
|
for file in files:
|
|
249
260
|
if file.endswith('.adoc'):
|
|
250
261
|
file_path = os.path.join(root, file)
|
|
251
|
-
macros = find_link_macros(file_path)
|
|
262
|
+
macros = find_link_macros(file_path, macro_type)
|
|
252
263
|
for full_macro, url, link_text, line_num in macros:
|
|
253
264
|
all_macros.append((file_path, full_macro, url, link_text, line_num))
|
|
254
265
|
|
|
@@ -257,13 +268,14 @@ def collect_all_macros(scan_dirs: List[str] = None) -> List[Tuple[str, str, str,
|
|
|
257
268
|
|
|
258
269
|
def create_attributes(url_groups: Dict[str, List[Tuple[str, str, str, int]]],
|
|
259
270
|
existing_attrs: Dict[str, str],
|
|
260
|
-
interactive: bool = True) -> Dict[str, str]:
|
|
271
|
+
interactive: bool = True) -> Tuple[Dict[str, str], Dict[str, str]]:
|
|
261
272
|
"""
|
|
262
|
-
Create new attributes for each unique URL.
|
|
273
|
+
Create new attributes for each unique URL and track existing ones.
|
|
263
274
|
|
|
264
|
-
Returns:
|
|
275
|
+
Returns: Tuple[new_attributes, existing_matching_attributes]
|
|
265
276
|
"""
|
|
266
277
|
new_attributes = {}
|
|
278
|
+
existing_matching_attributes = {}
|
|
267
279
|
existing_attr_names = set(existing_attrs.keys())
|
|
268
280
|
counter = 1
|
|
269
281
|
|
|
@@ -273,6 +285,7 @@ def create_attributes(url_groups: Dict[str, List[Tuple[str, str, str, int]]],
|
|
|
273
285
|
for attr_name, attr_value in existing_attrs.items():
|
|
274
286
|
if url in attr_value:
|
|
275
287
|
existing_attr = attr_name
|
|
288
|
+
existing_matching_attributes[attr_name] = attr_value
|
|
276
289
|
break
|
|
277
290
|
|
|
278
291
|
if existing_attr:
|
|
@@ -296,7 +309,7 @@ def create_attributes(url_groups: Dict[str, List[Tuple[str, str, str, int]]],
|
|
|
296
309
|
|
|
297
310
|
print(f"Created attribute: :{attr_name}: {attr_value}")
|
|
298
311
|
|
|
299
|
-
return new_attributes
|
|
312
|
+
return new_attributes, existing_matching_attributes
|
|
300
313
|
|
|
301
314
|
|
|
302
315
|
def update_attribute_file(file_path: str, new_attributes: Dict[str, str], dry_run: bool = False):
|
|
@@ -450,10 +463,20 @@ def extract_link_attributes(attributes_file: str = None,
|
|
|
450
463
|
interactive: bool = True,
|
|
451
464
|
dry_run: bool = False,
|
|
452
465
|
validate_links: bool = False,
|
|
453
|
-
fail_on_broken: bool = False
|
|
466
|
+
fail_on_broken: bool = False,
|
|
467
|
+
macro_type: str = 'both') -> bool:
|
|
454
468
|
"""
|
|
455
469
|
Main function to extract link attributes.
|
|
456
470
|
|
|
471
|
+
Args:
|
|
472
|
+
attributes_file: Path to attributes file
|
|
473
|
+
scan_dirs: Directories to scan
|
|
474
|
+
interactive: Enable interactive mode
|
|
475
|
+
dry_run: Preview changes without modifying files
|
|
476
|
+
validate_links: Validate URLs before extraction
|
|
477
|
+
fail_on_broken: Exit if broken links found
|
|
478
|
+
macro_type: Type of macros to process - 'link', 'xref', or 'both' (default: 'both')
|
|
479
|
+
|
|
457
480
|
Returns: True if successful, False otherwise
|
|
458
481
|
"""
|
|
459
482
|
# Find or confirm attributes file
|
|
@@ -488,16 +511,17 @@ def extract_link_attributes(attributes_file: str = None,
|
|
|
488
511
|
spinner.stop(f"Loaded {len(existing_attrs)} existing attributes")
|
|
489
512
|
|
|
490
513
|
# Collect all macros
|
|
491
|
-
|
|
514
|
+
macro_desc = {'link': 'link', 'xref': 'xref', 'both': 'link and xref'}[macro_type]
|
|
515
|
+
spinner = Spinner(f"Scanning for {macro_desc} macros with attributes")
|
|
492
516
|
spinner.start()
|
|
493
|
-
all_macros = collect_all_macros(scan_dirs)
|
|
517
|
+
all_macros = collect_all_macros(scan_dirs, macro_type)
|
|
494
518
|
spinner.stop()
|
|
495
519
|
|
|
496
520
|
if not all_macros:
|
|
497
|
-
print("No
|
|
521
|
+
print(f"No {macro_desc} macros with attributes found.")
|
|
498
522
|
return True
|
|
499
523
|
|
|
500
|
-
print(f"Found {len(all_macros)}
|
|
524
|
+
print(f"Found {len(all_macros)} {macro_desc} macros with attributes")
|
|
501
525
|
|
|
502
526
|
# Group by URL
|
|
503
527
|
spinner = Spinner("Grouping macros by URL")
|
|
@@ -505,15 +529,15 @@ def extract_link_attributes(attributes_file: str = None,
|
|
|
505
529
|
url_groups = group_macros_by_url(all_macros)
|
|
506
530
|
spinner.stop(f"Grouped into {len(url_groups)} unique URLs")
|
|
507
531
|
|
|
508
|
-
# Create new attributes
|
|
509
|
-
new_attributes = create_attributes(url_groups, existing_attrs, interactive)
|
|
532
|
+
# Create new attributes and track existing ones
|
|
533
|
+
new_attributes, existing_matching_attributes = create_attributes(url_groups, existing_attrs, interactive)
|
|
510
534
|
|
|
511
|
-
if not new_attributes:
|
|
512
|
-
print("No new attributes to create.")
|
|
535
|
+
if not new_attributes and not existing_matching_attributes:
|
|
536
|
+
print("No new attributes to create and no existing attributes match found URLs.")
|
|
513
537
|
return True
|
|
514
538
|
|
|
515
539
|
# Validate new attributes before writing if requested
|
|
516
|
-
if validate_links and not dry_run:
|
|
540
|
+
if validate_links and not dry_run and new_attributes:
|
|
517
541
|
print("\nValidating new link attributes...")
|
|
518
542
|
spinner = Spinner("Validating new URLs")
|
|
519
543
|
spinner.start()
|
|
@@ -543,10 +567,11 @@ def extract_link_attributes(attributes_file: str = None,
|
|
|
543
567
|
print("\nStopping due to broken URLs in new attributes (--fail-on-broken)")
|
|
544
568
|
return False
|
|
545
569
|
|
|
546
|
-
# Update attribute file
|
|
547
|
-
|
|
570
|
+
# Update attribute file (only if there are new attributes)
|
|
571
|
+
if new_attributes:
|
|
572
|
+
update_attribute_file(attributes_file, new_attributes, dry_run)
|
|
548
573
|
|
|
549
|
-
# Prepare file updates
|
|
574
|
+
# Prepare file updates (include both new and existing matching attributes)
|
|
550
575
|
all_attributes = {**existing_attrs, **new_attributes}
|
|
551
576
|
file_updates = prepare_file_updates(url_groups, all_attributes)
|
|
552
577
|
|
|
@@ -560,6 +585,14 @@ def extract_link_attributes(attributes_file: str = None,
|
|
|
560
585
|
if dry_run:
|
|
561
586
|
print("\n[DRY RUN] No files were modified. Run without --dry-run to apply changes.")
|
|
562
587
|
else:
|
|
563
|
-
|
|
588
|
+
total_processed = len(new_attributes) + len(existing_matching_attributes)
|
|
589
|
+
if new_attributes and existing_matching_attributes:
|
|
590
|
+
print(f"\nSuccessfully processed {total_processed} link attributes:")
|
|
591
|
+
print(f" - Created {len(new_attributes)} new attributes")
|
|
592
|
+
print(f" - Replaced macros using {len(existing_matching_attributes)} existing attributes")
|
|
593
|
+
elif new_attributes:
|
|
594
|
+
print(f"\nSuccessfully extracted {len(new_attributes)} link attributes")
|
|
595
|
+
elif existing_matching_attributes:
|
|
596
|
+
print(f"\nSuccessfully replaced macros using {len(existing_matching_attributes)} existing link attributes")
|
|
564
597
|
|
|
565
598
|
return True
|
|
@@ -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
|
|
|
@@ -165,7 +171,7 @@ def main():
|
|
|
165
171
|
spinner.start()
|
|
166
172
|
|
|
167
173
|
for file_path in adoc_files:
|
|
168
|
-
replacements = replace_link_attributes_in_file(file_path, attributes, args.dry_run)
|
|
174
|
+
replacements = replace_link_attributes_in_file(file_path, attributes, args.dry_run, args.macro_type)
|
|
169
175
|
if replacements > 0:
|
|
170
176
|
rel_path = file_path.relative_to(repo_root)
|
|
171
177
|
total_replacements += replacements
|
{rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/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."""
|
|
@@ -217,9 +247,10 @@ class TestCreateAttributes:
|
|
|
217
247
|
}
|
|
218
248
|
existing_attrs = {}
|
|
219
249
|
|
|
220
|
-
new_attrs = create_attributes(url_groups, existing_attrs, interactive=False)
|
|
250
|
+
new_attrs, existing_matched = create_attributes(url_groups, existing_attrs, interactive=False)
|
|
221
251
|
|
|
222
252
|
assert len(new_attrs) == 2
|
|
253
|
+
assert len(existing_matched) == 0
|
|
223
254
|
# Check that attributes were created
|
|
224
255
|
attr_values = list(new_attrs.values())
|
|
225
256
|
assert any("link:https://example.com/{version}/guide.html[Guide]" in v for v in attr_values)
|
|
@@ -236,9 +267,11 @@ class TestCreateAttributes:
|
|
|
236
267
|
"existing-link": "link:https://example.com/guide.html[Existing Guide]"
|
|
237
268
|
}
|
|
238
269
|
|
|
239
|
-
new_attrs = create_attributes(url_groups, existing_attrs, interactive=False)
|
|
270
|
+
new_attrs, existing_matched = create_attributes(url_groups, existing_attrs, interactive=False)
|
|
240
271
|
|
|
241
272
|
assert len(new_attrs) == 0
|
|
273
|
+
assert len(existing_matched) == 1
|
|
274
|
+
assert "existing-link" in existing_matched
|
|
242
275
|
captured = capsys.readouterr()
|
|
243
276
|
assert "already has attribute" in captured.out
|
|
244
277
|
|
|
@@ -314,7 +347,7 @@ And xref:{base-url}/intro.html[Introduction] for overview.
|
|
|
314
347
|
|
|
315
348
|
# Check output
|
|
316
349
|
captured = capsys.readouterr()
|
|
317
|
-
assert "Found 3 link
|
|
350
|
+
assert "Found 3 link and xref macros" in captured.out
|
|
318
351
|
assert "Grouped into 2 unique URLs" in captured.out
|
|
319
352
|
assert "[DRY RUN]" in captured.out
|
|
320
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.12 → rolfedh_doc_utils-0.1.14}/rolfedh_doc_utils.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/rolfedh_doc_utils.egg-info/requires.txt
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/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.12 → rolfedh_doc_utils-0.1.14}/tests/test_fixture_archive_unused_files.py
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/tests/test_fixture_archive_unused_images.py
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.12 → rolfedh_doc_utils-0.1.14}/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
|