rolfedh-doc-utils 0.1.29__py3-none-any.whl → 0.1.31__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.
- callout_lib/converter_bullets.py +10 -2
- callout_lib/converter_deflist.py +37 -2
- callout_lib/detector.py +55 -21
- callout_lib/table_parser.py +299 -87
- convert_callouts_interactive.py +18 -3
- convert_callouts_to_deflist.py +137 -14
- doc_utils/version.py +1 -1
- doc_utils/warnings_report.py +237 -0
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/METADATA +1 -1
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/RECORD +14 -13
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/WHEEL +0 -0
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/entry_points.txt +0 -0
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/licenses/LICENSE +0 -0
- {rolfedh_doc_utils-0.1.29.dist-info → rolfedh_doc_utils-0.1.31.dist-info}/top_level.txt +0 -0
convert_callouts_to_deflist.py
CHANGED
|
@@ -22,6 +22,9 @@ from callout_lib import (
|
|
|
22
22
|
CommentConverter,
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
+
# Import warnings report generator
|
|
26
|
+
from doc_utils.warnings_report import generate_warnings_report
|
|
27
|
+
|
|
25
28
|
|
|
26
29
|
# Colors for output
|
|
27
30
|
class Colors:
|
|
@@ -40,11 +43,12 @@ class CalloutConverter:
|
|
|
40
43
|
"""Converts callout-style documentation to various formats."""
|
|
41
44
|
|
|
42
45
|
def __init__(self, dry_run: bool = False, verbose: bool = False, output_format: str = 'deflist',
|
|
43
|
-
max_comment_length: int = 120):
|
|
46
|
+
max_comment_length: int = 120, force: bool = False):
|
|
44
47
|
self.dry_run = dry_run
|
|
45
48
|
self.verbose = verbose
|
|
46
49
|
self.output_format = output_format # 'deflist', 'bullets', or 'comments'
|
|
47
50
|
self.max_comment_length = max_comment_length # Max length for inline comments
|
|
51
|
+
self.force = force # Force strip callouts even with warnings
|
|
48
52
|
self.changes_made = 0
|
|
49
53
|
self.warnings = [] # Collect warnings for summary
|
|
50
54
|
self.long_comment_warnings = [] # Warnings for comments exceeding max length
|
|
@@ -103,11 +107,50 @@ class CalloutConverter:
|
|
|
103
107
|
|
|
104
108
|
if not explanations:
|
|
105
109
|
self.log(f"No explanations found after block at line {block.start_line + 1}")
|
|
106
|
-
|
|
110
|
+
# Warn user about code blocks with callouts but no explanations
|
|
111
|
+
warning_msg = (
|
|
112
|
+
f"WARNING: {input_file.name} line {block.start_line + 1}: "
|
|
113
|
+
f"Code block has callouts {sorted(set(all_callout_nums))} but no explanations found after it. "
|
|
114
|
+
f"This may indicate: explanations are shared with another code block, "
|
|
115
|
+
f"explanations are in an unexpected location, or documentation error (missing explanations). "
|
|
116
|
+
f"Consider reviewing this block manually."
|
|
117
|
+
)
|
|
118
|
+
print_colored(warning_msg, Colors.YELLOW)
|
|
119
|
+
self.warnings.append(warning_msg)
|
|
120
|
+
|
|
121
|
+
# In force mode, strip callouts anyway
|
|
122
|
+
if not self.force:
|
|
123
|
+
continue
|
|
124
|
+
else:
|
|
125
|
+
self.log(f"FORCE MODE: Stripping callouts from block at line {block.start_line + 1} despite missing explanations")
|
|
126
|
+
|
|
127
|
+
# Just strip callouts without creating explanation list
|
|
128
|
+
converted_content = self.detector.remove_callouts_from_code(block.content)
|
|
129
|
+
|
|
130
|
+
# Replace in document
|
|
131
|
+
has_source_prefix = self.detector.CODE_BLOCK_START.match(new_lines[block.start_line])
|
|
132
|
+
if has_source_prefix:
|
|
133
|
+
content_start = block.start_line + 2 # After [source] and ----
|
|
134
|
+
else:
|
|
135
|
+
content_start = block.start_line + 1 # After ---- only
|
|
136
|
+
content_end = block.end_line
|
|
137
|
+
|
|
138
|
+
# Build new section with just code (no explanations)
|
|
139
|
+
new_section = (
|
|
140
|
+
new_lines[:content_start] +
|
|
141
|
+
converted_content +
|
|
142
|
+
[new_lines[content_end]] + # Keep closing delimiter
|
|
143
|
+
new_lines[content_end + 1:] # Keep rest of file
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
new_lines = new_section
|
|
147
|
+
conversions += 1
|
|
148
|
+
self.changes_made += 1
|
|
149
|
+
continue
|
|
107
150
|
|
|
108
151
|
# Validate callouts match
|
|
109
152
|
is_valid, code_nums, explanation_nums = self.detector.validate_callouts(callout_groups, explanations)
|
|
110
|
-
if not is_valid:
|
|
153
|
+
if not is_valid and explanations: # Only validate if we have explanations
|
|
111
154
|
# Format warning message with file and line numbers
|
|
112
155
|
line_range = f"{block.start_line + 1}-{block.end_line + 1}"
|
|
113
156
|
warning_msg = (
|
|
@@ -116,7 +159,12 @@ class CalloutConverter:
|
|
|
116
159
|
)
|
|
117
160
|
print_colored(warning_msg, Colors.YELLOW)
|
|
118
161
|
self.warnings.append(warning_msg)
|
|
119
|
-
|
|
162
|
+
|
|
163
|
+
# In force mode, convert anyway
|
|
164
|
+
if not self.force:
|
|
165
|
+
continue
|
|
166
|
+
else:
|
|
167
|
+
self.log(f"FORCE MODE: Converting block at line {block.start_line + 1} despite callout mismatch")
|
|
120
168
|
|
|
121
169
|
self.log(f"Converting block at line {block.start_line + 1}")
|
|
122
170
|
|
|
@@ -144,7 +192,7 @@ class CalloutConverter:
|
|
|
144
192
|
# Fall back to definition list
|
|
145
193
|
self.log(f"Falling back to definition list for block at line {block.start_line + 1}")
|
|
146
194
|
converted_content = self.detector.remove_callouts_from_code(block.content)
|
|
147
|
-
output_list = DefListConverter.convert(callout_groups, explanations)
|
|
195
|
+
output_list = DefListConverter.convert(callout_groups, explanations, self.detector.last_table_title)
|
|
148
196
|
use_deflist_fallback = True
|
|
149
197
|
else:
|
|
150
198
|
output_list = [] # No separate list after code block for comments
|
|
@@ -153,9 +201,9 @@ class CalloutConverter:
|
|
|
153
201
|
converted_content = self.detector.remove_callouts_from_code(block.content)
|
|
154
202
|
|
|
155
203
|
if self.output_format == 'bullets':
|
|
156
|
-
output_list = BulletListConverter.convert(callout_groups, explanations)
|
|
204
|
+
output_list = BulletListConverter.convert(callout_groups, explanations, self.detector.last_table_title)
|
|
157
205
|
else: # default to 'deflist'
|
|
158
|
-
output_list = DefListConverter.convert(callout_groups, explanations)
|
|
206
|
+
output_list = DefListConverter.convert(callout_groups, explanations, self.detector.last_table_title)
|
|
159
207
|
|
|
160
208
|
# Replace in document
|
|
161
209
|
# Check if block has [source] prefix
|
|
@@ -170,23 +218,40 @@ class CalloutConverter:
|
|
|
170
218
|
# For deflist/bullets format, remove old explanations and add new list
|
|
171
219
|
if self.output_format == 'comments' and not use_deflist_fallback:
|
|
172
220
|
# Remove old callout explanations (list or table format)
|
|
221
|
+
# Find where explanations/table actually starts to preserve content in between
|
|
222
|
+
if self.detector.last_table:
|
|
223
|
+
explanation_start_line = self.detector.last_table.start_line
|
|
224
|
+
else:
|
|
225
|
+
# List format: skip blank lines after code block
|
|
226
|
+
explanation_start_line = block.end_line + 1
|
|
227
|
+
while explanation_start_line < len(new_lines) and not new_lines[explanation_start_line].strip():
|
|
228
|
+
explanation_start_line += 1
|
|
229
|
+
|
|
173
230
|
new_section = (
|
|
174
231
|
new_lines[:content_start] +
|
|
175
232
|
converted_content +
|
|
176
233
|
[new_lines[content_end]] + # Keep closing delimiter
|
|
234
|
+
new_lines[content_end + 1:explanation_start_line] + # Preserve content between code and explanations
|
|
177
235
|
new_lines[explanation_end + 1:] # Skip explanations/table, keep rest
|
|
178
236
|
)
|
|
179
237
|
else:
|
|
180
238
|
# Remove old callout explanations and add new list
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
239
|
+
# Find where explanations/table actually starts
|
|
240
|
+
if self.detector.last_table:
|
|
241
|
+
# Table format: preserve content between code block and table start
|
|
242
|
+
explanation_start_line = self.detector.last_table.start_line
|
|
243
|
+
else:
|
|
244
|
+
# List format: skip blank lines after code block
|
|
245
|
+
explanation_start_line = block.end_line + 1
|
|
246
|
+
while explanation_start_line < len(new_lines) and not new_lines[explanation_start_line].strip():
|
|
247
|
+
explanation_start_line += 1
|
|
184
248
|
|
|
185
249
|
# Build the new section
|
|
186
250
|
new_section = (
|
|
187
251
|
new_lines[:content_start] +
|
|
188
252
|
converted_content +
|
|
189
253
|
[new_lines[content_end]] + # Keep closing delimiter
|
|
254
|
+
new_lines[content_end + 1:explanation_start_line] + # Preserve content between code and explanations
|
|
190
255
|
output_list +
|
|
191
256
|
new_lines[explanation_end + 1:]
|
|
192
257
|
)
|
|
@@ -377,6 +442,30 @@ Example transformation (deflist format):
|
|
|
377
442
|
type=Path,
|
|
378
443
|
help='Path to file containing directories/files to exclude, one per line'
|
|
379
444
|
)
|
|
445
|
+
parser.add_argument(
|
|
446
|
+
'--warnings-report',
|
|
447
|
+
dest='warnings_report',
|
|
448
|
+
action='store_true',
|
|
449
|
+
default=True,
|
|
450
|
+
help='Generate warnings report file (default: enabled)'
|
|
451
|
+
)
|
|
452
|
+
parser.add_argument(
|
|
453
|
+
'--no-warnings-report',
|
|
454
|
+
dest='warnings_report',
|
|
455
|
+
action='store_false',
|
|
456
|
+
help='Disable warnings report file generation'
|
|
457
|
+
)
|
|
458
|
+
parser.add_argument(
|
|
459
|
+
'--warnings-file',
|
|
460
|
+
type=Path,
|
|
461
|
+
default=Path('callout-warnings-report.adoc'),
|
|
462
|
+
help='Path for warnings report file (default: callout-warnings-report.adoc)'
|
|
463
|
+
)
|
|
464
|
+
parser.add_argument(
|
|
465
|
+
'--force',
|
|
466
|
+
action='store_true',
|
|
467
|
+
help='Force strip callouts from code blocks even with warnings (USE WITH CAUTION: only after reviewing and fixing callout issues)'
|
|
468
|
+
)
|
|
380
469
|
|
|
381
470
|
args = parser.parse_args()
|
|
382
471
|
|
|
@@ -414,9 +503,24 @@ Example transformation (deflist format):
|
|
|
414
503
|
|
|
415
504
|
print(f"Found {len(adoc_files)} AsciiDoc file(s) to process")
|
|
416
505
|
|
|
506
|
+
# If force mode is enabled, show warning and ask for confirmation
|
|
507
|
+
if args.force and not args.dry_run:
|
|
508
|
+
print_colored("\n⚠️ FORCE MODE ENABLED ⚠️", Colors.YELLOW)
|
|
509
|
+
print_colored("This will strip callouts from code blocks even when warnings are present.", Colors.YELLOW)
|
|
510
|
+
print_colored("You should only use this option AFTER:", Colors.YELLOW)
|
|
511
|
+
print_colored(" 1. Reviewing all warnings in the warnings report", Colors.YELLOW)
|
|
512
|
+
print_colored(" 2. Manually fixing callout issues where appropriate", Colors.YELLOW)
|
|
513
|
+
print_colored(" 3. Confirming that remaining warnings are acceptable", Colors.YELLOW)
|
|
514
|
+
print()
|
|
515
|
+
response = input("Are you sure you want to proceed with force mode? (yes/no): ").strip().lower()
|
|
516
|
+
if response not in ['yes', 'y']:
|
|
517
|
+
print_colored("Operation cancelled.", Colors.YELLOW)
|
|
518
|
+
sys.exit(0)
|
|
519
|
+
print()
|
|
520
|
+
|
|
417
521
|
# Create converter
|
|
418
522
|
converter = CalloutConverter(dry_run=args.dry_run, verbose=args.verbose, output_format=args.format,
|
|
419
|
-
max_comment_length=args.max_comment_length)
|
|
523
|
+
max_comment_length=args.max_comment_length, force=args.force)
|
|
420
524
|
|
|
421
525
|
# Process each file
|
|
422
526
|
files_processed = 0
|
|
@@ -459,9 +563,28 @@ Example transformation (deflist format):
|
|
|
459
563
|
|
|
460
564
|
# Display warning summary if any warnings were collected
|
|
461
565
|
if converter.warnings:
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
566
|
+
# Generate warnings report if enabled
|
|
567
|
+
if args.warnings_report:
|
|
568
|
+
try:
|
|
569
|
+
generate_warnings_report(converter.warnings, args.warnings_file)
|
|
570
|
+
print_colored(f"\n⚠️ {len(converter.warnings)} Warning(s) - See {args.warnings_file} for details", Colors.YELLOW)
|
|
571
|
+
print()
|
|
572
|
+
print_colored(f"Suggestion: Review and fix the callout issues listed in {args.warnings_file}, then rerun this command.", Colors.YELLOW)
|
|
573
|
+
except Exception as e:
|
|
574
|
+
print_colored(f"\n⚠️ {len(converter.warnings)} Warning(s):", Colors.YELLOW)
|
|
575
|
+
print_colored(f"Error generating warnings report: {e}", Colors.RED)
|
|
576
|
+
# Fall back to displaying warnings in console
|
|
577
|
+
for warning in converter.warnings:
|
|
578
|
+
print_colored(f" {warning}", Colors.YELLOW)
|
|
579
|
+
print()
|
|
580
|
+
print_colored("Suggestion: Fix the callout issues listed above and rerun this command.", Colors.YELLOW)
|
|
581
|
+
else:
|
|
582
|
+
# Console-only output (legacy behavior)
|
|
583
|
+
print_colored(f"\n⚠️ {len(converter.warnings)} Warning(s):", Colors.YELLOW)
|
|
584
|
+
for warning in converter.warnings:
|
|
585
|
+
print_colored(f" {warning}", Colors.YELLOW)
|
|
586
|
+
print()
|
|
587
|
+
print_colored("Suggestion: Fix the callout issues listed above and rerun this command.", Colors.YELLOW)
|
|
465
588
|
print()
|
|
466
589
|
|
|
467
590
|
if args.dry_run and files_modified > 0:
|
doc_utils/version.py
CHANGED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generate AsciiDoc warnings report for callout conversion issues.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import List, Dict, Set
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class WarningInfo:
|
|
11
|
+
"""Information about a specific warning."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, warning_type: str, file_name: str, line_info: str,
|
|
14
|
+
code_nums: List[int] = None, explanation_nums: List[int] = None):
|
|
15
|
+
self.warning_type = warning_type # 'mismatch' or 'missing'
|
|
16
|
+
self.file_name = file_name
|
|
17
|
+
self.line_info = line_info # e.g., "211" or "55-72"
|
|
18
|
+
self.code_nums = code_nums or []
|
|
19
|
+
self.explanation_nums = explanation_nums or []
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def parse_warning_message(warning_msg: str) -> WarningInfo:
|
|
23
|
+
"""
|
|
24
|
+
Parse a warning message to extract structured information.
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
- "WARNING: file.adoc lines 55-72: Callout mismatch: code has [1, 2], explanations have [1, 3]"
|
|
28
|
+
- "WARNING: file.adoc line 211: Code block has callouts [1, 2, 3, 4] but no explanations found..."
|
|
29
|
+
"""
|
|
30
|
+
import re
|
|
31
|
+
|
|
32
|
+
# Extract file name and line info
|
|
33
|
+
match = re.match(r'WARNING: (.+?) lines? ([\d-]+):', warning_msg)
|
|
34
|
+
if not match:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
file_name = match.group(1)
|
|
38
|
+
line_info = match.group(2)
|
|
39
|
+
|
|
40
|
+
# Determine warning type and extract callout numbers
|
|
41
|
+
if 'Callout mismatch' in warning_msg:
|
|
42
|
+
# Parse: "code has [1, 2], explanations have [1, 3]"
|
|
43
|
+
code_match = re.search(r'code has \[([^\]]+)\]', warning_msg)
|
|
44
|
+
exp_match = re.search(r'explanations have \[([^\]]+)\]', warning_msg)
|
|
45
|
+
|
|
46
|
+
code_nums = []
|
|
47
|
+
exp_nums = []
|
|
48
|
+
|
|
49
|
+
if code_match:
|
|
50
|
+
code_nums = [int(n.strip()) for n in code_match.group(1).split(',')]
|
|
51
|
+
if exp_match:
|
|
52
|
+
exp_nums = [int(n.strip()) for n in exp_match.group(1).split(',')]
|
|
53
|
+
|
|
54
|
+
return WarningInfo('mismatch', file_name, line_info, code_nums, exp_nums)
|
|
55
|
+
|
|
56
|
+
elif 'but no explanations found' in warning_msg:
|
|
57
|
+
# Parse: "Code block has callouts [1, 2, 3, 4] but no explanations found"
|
|
58
|
+
callouts_match = re.search(r'has callouts \[([^\]]+)\]', warning_msg)
|
|
59
|
+
|
|
60
|
+
code_nums = []
|
|
61
|
+
if callouts_match:
|
|
62
|
+
code_nums = [int(n.strip()) for n in callouts_match.group(1).split(',')]
|
|
63
|
+
|
|
64
|
+
return WarningInfo('missing', file_name, line_info, code_nums, [])
|
|
65
|
+
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def analyze_mismatch(code_nums: List[int], exp_nums: List[int]) -> List[str]:
|
|
70
|
+
"""
|
|
71
|
+
Analyze what's wrong with a callout mismatch.
|
|
72
|
+
|
|
73
|
+
Returns a list of issue descriptions.
|
|
74
|
+
"""
|
|
75
|
+
issues = []
|
|
76
|
+
code_set = set(code_nums)
|
|
77
|
+
exp_set = set(exp_nums)
|
|
78
|
+
|
|
79
|
+
# Check for duplicates in explanations
|
|
80
|
+
exp_counts = {}
|
|
81
|
+
for num in exp_nums:
|
|
82
|
+
exp_counts[num] = exp_counts.get(num, 0) + 1
|
|
83
|
+
|
|
84
|
+
duplicates = [num for num, count in exp_counts.items() if count > 1]
|
|
85
|
+
if duplicates:
|
|
86
|
+
for dup in duplicates:
|
|
87
|
+
count = exp_counts[dup]
|
|
88
|
+
issues.append(f"Duplicate callout: {dup} (appears {count} times in explanations)")
|
|
89
|
+
|
|
90
|
+
# Check for missing callouts (in code but not in explanations)
|
|
91
|
+
missing_in_exp = code_set - exp_set
|
|
92
|
+
if missing_in_exp:
|
|
93
|
+
for num in sorted(missing_in_exp):
|
|
94
|
+
issues.append(f"Missing callout: {num} (in code but not in explanations)")
|
|
95
|
+
|
|
96
|
+
# Check for extra callouts (in explanations but not in code)
|
|
97
|
+
extra_in_exp = exp_set - code_set
|
|
98
|
+
if extra_in_exp:
|
|
99
|
+
for num in sorted(extra_in_exp):
|
|
100
|
+
issues.append(f"Extra callout: {num} (in explanations but not in code)")
|
|
101
|
+
|
|
102
|
+
# Check for off-by-one errors
|
|
103
|
+
if code_nums and exp_nums:
|
|
104
|
+
code_start = min(code_nums)
|
|
105
|
+
exp_start = min(exp_nums)
|
|
106
|
+
if code_start != exp_start and not (missing_in_exp or extra_in_exp or duplicates):
|
|
107
|
+
issues.append(f"Off-by-one error (code starts at {code_start}, explanations start at {exp_start})")
|
|
108
|
+
|
|
109
|
+
return issues
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def generate_warnings_report(warnings: List[str], output_path: Path = None) -> str:
|
|
113
|
+
"""
|
|
114
|
+
Generate an AsciiDoc warnings report from warning messages.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
warnings: List of warning message strings
|
|
118
|
+
output_path: Path to write report file (if None, returns content only)
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
The report content as a string
|
|
122
|
+
"""
|
|
123
|
+
if not warnings:
|
|
124
|
+
return ""
|
|
125
|
+
|
|
126
|
+
# Parse all warnings
|
|
127
|
+
parsed_warnings = []
|
|
128
|
+
for warning in warnings:
|
|
129
|
+
parsed = parse_warning_message(warning)
|
|
130
|
+
if parsed:
|
|
131
|
+
parsed_warnings.append(parsed)
|
|
132
|
+
|
|
133
|
+
if not parsed_warnings:
|
|
134
|
+
return ""
|
|
135
|
+
|
|
136
|
+
# Group warnings by type
|
|
137
|
+
mismatch_warnings = [w for w in parsed_warnings if w.warning_type == 'mismatch']
|
|
138
|
+
missing_warnings = [w for w in parsed_warnings if w.warning_type == 'missing']
|
|
139
|
+
|
|
140
|
+
# Generate report content
|
|
141
|
+
lines = []
|
|
142
|
+
lines.append("= Callout Conversion Warnings Report")
|
|
143
|
+
lines.append(":toc:")
|
|
144
|
+
lines.append("")
|
|
145
|
+
lines.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
146
|
+
lines.append("")
|
|
147
|
+
|
|
148
|
+
# Summary
|
|
149
|
+
lines.append("== Summary")
|
|
150
|
+
lines.append("")
|
|
151
|
+
lines.append(f"Total warnings: {len(parsed_warnings)}")
|
|
152
|
+
if mismatch_warnings:
|
|
153
|
+
lines.append(f"- Callout mismatches: {len(mismatch_warnings)}")
|
|
154
|
+
if missing_warnings:
|
|
155
|
+
lines.append(f"- Missing explanations: {len(missing_warnings)}")
|
|
156
|
+
lines.append("")
|
|
157
|
+
lines.append("== Recommended Actions")
|
|
158
|
+
lines.append("")
|
|
159
|
+
lines.append("1. Review each warning below and fix callout issues where appropriate")
|
|
160
|
+
lines.append("2. For callout mismatches: Ensure code callouts match explanation numbers")
|
|
161
|
+
lines.append("3. For missing explanations: Check if explanations are shared with another block or missing")
|
|
162
|
+
lines.append("4. After fixing issues, rerun the conversion command")
|
|
163
|
+
lines.append("")
|
|
164
|
+
lines.append("== Force Mode Option")
|
|
165
|
+
lines.append("")
|
|
166
|
+
lines.append("CAUTION: Use this option sparingly and only after reviewing all warnings.")
|
|
167
|
+
lines.append("")
|
|
168
|
+
lines.append("If you've reviewed all warnings and confirmed that remaining issues are acceptable,")
|
|
169
|
+
lines.append("you can use the `--force` option to strip callouts from code blocks despite warnings:")
|
|
170
|
+
lines.append("")
|
|
171
|
+
lines.append("[source,bash]")
|
|
172
|
+
lines.append("----")
|
|
173
|
+
lines.append("convert-callouts-to-deflist --force modules/")
|
|
174
|
+
lines.append("----")
|
|
175
|
+
lines.append("")
|
|
176
|
+
lines.append("Force mode will:")
|
|
177
|
+
lines.append("")
|
|
178
|
+
lines.append("- Strip callouts from blocks with missing explanations (without creating explanation lists)")
|
|
179
|
+
lines.append("- Convert blocks with callout mismatches using available explanations")
|
|
180
|
+
lines.append("- Require confirmation before proceeding (unless in dry-run mode)")
|
|
181
|
+
lines.append("")
|
|
182
|
+
lines.append("IMPORTANT: Always work in a git branch and review changes with `git diff` before committing.")
|
|
183
|
+
lines.append("")
|
|
184
|
+
|
|
185
|
+
# Callout Mismatch section
|
|
186
|
+
if mismatch_warnings:
|
|
187
|
+
lines.append("== Callout Mismatch Warnings")
|
|
188
|
+
lines.append("")
|
|
189
|
+
lines.append("Callout numbers in code don't match explanation numbers.")
|
|
190
|
+
lines.append("")
|
|
191
|
+
|
|
192
|
+
for warning in mismatch_warnings:
|
|
193
|
+
lines.append(f"=== {warning.file_name}")
|
|
194
|
+
lines.append("")
|
|
195
|
+
lines.append(f"*Lines {warning.line_info}*")
|
|
196
|
+
lines.append("")
|
|
197
|
+
lines.append(f"Code has:: {warning.code_nums}")
|
|
198
|
+
lines.append(f"Explanations have:: {warning.explanation_nums}")
|
|
199
|
+
lines.append("")
|
|
200
|
+
|
|
201
|
+
issues = analyze_mismatch(warning.code_nums, warning.explanation_nums)
|
|
202
|
+
if issues:
|
|
203
|
+
lines.append("Issues detected::")
|
|
204
|
+
for issue in issues:
|
|
205
|
+
lines.append(f"- {issue}")
|
|
206
|
+
lines.append("")
|
|
207
|
+
|
|
208
|
+
# Missing Explanations section
|
|
209
|
+
if missing_warnings:
|
|
210
|
+
lines.append("== Missing Explanations Warnings")
|
|
211
|
+
lines.append("")
|
|
212
|
+
lines.append("Code blocks with callouts but no explanations found after them.")
|
|
213
|
+
lines.append("")
|
|
214
|
+
|
|
215
|
+
for warning in missing_warnings:
|
|
216
|
+
lines.append(f"=== {warning.file_name}")
|
|
217
|
+
lines.append("")
|
|
218
|
+
lines.append(f"*Line {warning.line_info}*")
|
|
219
|
+
lines.append("")
|
|
220
|
+
lines.append(f"Callouts in code:: {warning.code_nums}")
|
|
221
|
+
lines.append("")
|
|
222
|
+
lines.append("Possible causes::")
|
|
223
|
+
lines.append("- Explanations shared with another code block (e.g., in conditional sections)")
|
|
224
|
+
lines.append("- Explanations in unexpected location")
|
|
225
|
+
lines.append("- Documentation error (missing explanations)")
|
|
226
|
+
lines.append("")
|
|
227
|
+
lines.append("Action:: Review this block manually")
|
|
228
|
+
lines.append("")
|
|
229
|
+
|
|
230
|
+
content = '\n'.join(lines)
|
|
231
|
+
|
|
232
|
+
# Write to file if path provided
|
|
233
|
+
if output_path:
|
|
234
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
|
235
|
+
f.write(content)
|
|
236
|
+
|
|
237
|
+
return content
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
archive_unused_files.py,sha256=OJZrkqn70hiOXED218jMYPFNFWnsDpjsCYOmBRxYnHU,2274
|
|
2
2
|
archive_unused_images.py,sha256=fZeyEZtTd72Gbd3YBXTy5xoshAAM9qb4qFPMjhHL1Fg,1864
|
|
3
3
|
check_scannability.py,sha256=O6ROr-e624jVPvPpASpsWo0gTfuCFpA2mTSX61BjAEI,5478
|
|
4
|
-
convert_callouts_interactive.py,sha256=
|
|
5
|
-
convert_callouts_to_deflist.py,sha256=
|
|
4
|
+
convert_callouts_interactive.py,sha256=wi3EhxWYiUlq7orFiMK3aY2XluzS1tEZFSpVd4meQl4,21980
|
|
5
|
+
convert_callouts_to_deflist.py,sha256=JnYyluTQpEFOLnIVLH4qYrkrD19gtORVniQu162__YM,24715
|
|
6
6
|
doc_utils_cli.py,sha256=J3CE7cTDDCRGkhAknYejNWHhk5t9YFGt27WDVfR98Xk,5111
|
|
7
7
|
extract_link_attributes.py,sha256=wR2SmR2la-jR6DzDbas2PoNONgRZ4dZ6aqwzkwEv8Gs,3516
|
|
8
8
|
find_unused_attributes.py,sha256=77CxFdm72wj6SO81w-auMdDjnvF83jWy_qaM7DsAtBw,4263
|
|
@@ -10,11 +10,11 @@ format_asciidoc_spacing.py,sha256=nmWpw2dgwhd81LXyznq0rT8w6Z7cNRyGtPJGRyKFRdc,42
|
|
|
10
10
|
replace_link_attributes.py,sha256=Cpc4E-j9j-4_y0LOstAKYOPl02Ln_2bGNIeqp3ZVCdA,7624
|
|
11
11
|
validate_links.py,sha256=lWuK8sgfiFdfcUdSVAt_5U9JHVde_oa6peSUlBQtsac,6145
|
|
12
12
|
callout_lib/__init__.py,sha256=8B82N_z4D1LaZVYgd5jZR53QAabtgPzADOyGlnvihj0,665
|
|
13
|
-
callout_lib/converter_bullets.py,sha256=
|
|
13
|
+
callout_lib/converter_bullets.py,sha256=nfH0hz4p8qNM2F-MhtBjwH-lUYcNf2m1sdJebRlCxoo,4405
|
|
14
14
|
callout_lib/converter_comments.py,sha256=do0dH8uOyNFpn5CDEzR0jYYCMIPP3oPFM8cEB-Fp22c,9767
|
|
15
|
-
callout_lib/converter_deflist.py,sha256=
|
|
16
|
-
callout_lib/detector.py,sha256=
|
|
17
|
-
callout_lib/table_parser.py,sha256=
|
|
15
|
+
callout_lib/converter_deflist.py,sha256=LphSVdvCAcH1k7ysiBRQcrfaXRs48lmygSijYXVpu40,4942
|
|
16
|
+
callout_lib/detector.py,sha256=oU36eaSz-damdylPuOftTwNU5ZjVf8GMJ44txcFAFOM,15474
|
|
17
|
+
callout_lib/table_parser.py,sha256=ZucisADE8RDAk5HtIrttaPgBi6Hf8ZUpw7KzfbcmEjc,31450
|
|
18
18
|
doc_utils/__init__.py,sha256=qqZR3lohzkP63soymrEZPBGzzk6-nFzi4_tSffjmu_0,74
|
|
19
19
|
doc_utils/extract_link_attributes.py,sha256=U0EvPZReJQigNfbT-icBsVT6Li64hYki5W7MQz6qqbc,22743
|
|
20
20
|
doc_utils/file_utils.py,sha256=fpTh3xx759sF8sNocdn_arsP3KAv8XA6cTQTAVIZiZg,4247
|
|
@@ -27,11 +27,12 @@ doc_utils/unused_adoc.py,sha256=2cbqcYr1os2EhETUU928BlPRlsZVSdI00qaMhqjSIqQ,5263
|
|
|
27
27
|
doc_utils/unused_attributes.py,sha256=OHyAdaBD7aNo357B0SLBN5NC_jNY5TWXMwgtfJNh3X8,7621
|
|
28
28
|
doc_utils/unused_images.py,sha256=nqn36Bbrmon2KlGlcaruNjJJvTQ8_9H0WU9GvCW7rW8,1456
|
|
29
29
|
doc_utils/validate_links.py,sha256=iBGXnwdeLlgIT3fo3v01ApT5k0X2FtctsvkrE6E3VMk,19610
|
|
30
|
-
doc_utils/version.py,sha256=
|
|
30
|
+
doc_utils/version.py,sha256=pnEM8Q0l-kM56_u5y1indjEWaQx61Dkm50erPJRxqH8,203
|
|
31
31
|
doc_utils/version_check.py,sha256=-31Y6AN0KGi_CUCAVOOhf6bPO3r7SQIXPxxeffLAF0w,7535
|
|
32
|
-
|
|
33
|
-
rolfedh_doc_utils-0.1.
|
|
34
|
-
rolfedh_doc_utils-0.1.
|
|
35
|
-
rolfedh_doc_utils-0.1.
|
|
36
|
-
rolfedh_doc_utils-0.1.
|
|
37
|
-
rolfedh_doc_utils-0.1.
|
|
32
|
+
doc_utils/warnings_report.py,sha256=20yfwqBjOprfFhQwCujbcsvjJCbHHhmH84uAujm-y-o,8877
|
|
33
|
+
rolfedh_doc_utils-0.1.31.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
|
|
34
|
+
rolfedh_doc_utils-0.1.31.dist-info/METADATA,sha256=pVW5aKDus2NB85h5WhPjkhmDeFtge3_Woyc55w-aM40,8325
|
|
35
|
+
rolfedh_doc_utils-0.1.31.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
rolfedh_doc_utils-0.1.31.dist-info/entry_points.txt,sha256=vL_LlLKOiurRzchrq8iRUQG19Xi9lSAFVZGjO-xyErk,577
|
|
37
|
+
rolfedh_doc_utils-0.1.31.dist-info/top_level.txt,sha256=J4xtr3zoyCip27b3GnticFVZoyz5HHtgGqHQ-SZONCA,265
|
|
38
|
+
rolfedh_doc_utils-0.1.31.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|