rolfedh-doc-utils 0.1.23__py3-none-any.whl → 0.1.25__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.
@@ -3,18 +3,24 @@
3
3
  convert-callouts-to-deflist - Convert AsciiDoc callouts to definition list format
4
4
 
5
5
  Converts code blocks with callout-style annotations (<1>, <2>, etc.) to cleaner
6
- definition list format with "where:" prefix.
6
+ definition list format with "where:" prefix, bulleted list format, or inline comments.
7
7
 
8
8
  This tool automatically scans all .adoc files in the current directory (recursively)
9
9
  by default, or you can specify a specific file or directory.
10
10
  """
11
11
 
12
- import re
13
12
  import sys
14
13
  import argparse
15
14
  from pathlib import Path
16
- from typing import List, Dict, Tuple, Optional
17
- from dataclasses import dataclass
15
+ from typing import List, Tuple
16
+
17
+ # Import from callout_lib
18
+ from callout_lib import (
19
+ CalloutDetector,
20
+ DefListConverter,
21
+ BulletListConverter,
22
+ CommentConverter,
23
+ )
18
24
 
19
25
 
20
26
  # Colors for output
@@ -30,302 +36,30 @@ def print_colored(message: str, color: str = Colors.NC) -> None:
30
36
  print(f"{color}{message}{Colors.NC}")
31
37
 
32
38
 
33
- @dataclass
34
- class Callout:
35
- """Represents a callout with its number and explanation text."""
36
- number: int
37
- lines: List[str] # List of lines to preserve formatting
38
- is_optional: bool = False
39
-
40
-
41
- @dataclass
42
- class CalloutGroup:
43
- """Represents one or more callouts that share the same code line."""
44
- code_line: str # The actual code line (without callouts)
45
- callout_numbers: List[int] # List of callout numbers on this line
46
-
47
-
48
- @dataclass
49
- class CodeBlock:
50
- """Represents a code block with its content and metadata."""
51
- start_line: int
52
- end_line: int
53
- delimiter: str
54
- content: List[str]
55
- language: Optional[str] = None
56
-
57
-
58
39
  class CalloutConverter:
59
- """Converts callout-style documentation to definition list format."""
60
-
61
- # Pattern for code block start: [source,language] or [source] with optional attributes
62
- # Matches: [source], [source,java], [source,java,subs="..."], [source,java,options="..."], etc.
63
- CODE_BLOCK_START = re.compile(r'^\[source(?:,\s*(\w+))?(?:[,\s]+[^\]]+)?\]')
64
-
65
- # Pattern for callout number in code block (can appear multiple times per line)
66
- CALLOUT_IN_CODE = re.compile(r'<(\d+)>')
40
+ """Converts callout-style documentation to various formats."""
67
41
 
68
- # Pattern for callout explanation line: <1> Explanation text
69
- CALLOUT_EXPLANATION = re.compile(r'^<(\d+)>\s+(.+)$')
70
-
71
- # Pattern to detect user-replaceable values in angle brackets
72
- # Excludes heredoc syntax (<<) and comparison operators
73
- USER_VALUE_PATTERN = re.compile(r'(?<!<)<([a-zA-Z][^>]*)>')
74
-
75
- def __init__(self, dry_run: bool = False, verbose: bool = False):
42
+ def __init__(self, dry_run: bool = False, verbose: bool = False, output_format: str = 'deflist',
43
+ max_comment_length: int = 120):
76
44
  self.dry_run = dry_run
77
45
  self.verbose = verbose
46
+ self.output_format = output_format # 'deflist', 'bullets', or 'comments'
47
+ self.max_comment_length = max_comment_length # Max length for inline comments
78
48
  self.changes_made = 0
79
49
  self.warnings = [] # Collect warnings for summary
50
+ self.long_comment_warnings = [] # Warnings for comments exceeding max length
51
+
52
+ # Initialize detector and converters
53
+ self.detector = CalloutDetector()
80
54
 
81
55
  def log(self, message: str):
82
56
  """Print message if verbose mode is enabled."""
83
57
  if self.verbose:
84
58
  print(f"[INFO] {message}")
85
59
 
86
- def find_code_blocks(self, lines: List[str]) -> List[CodeBlock]:
87
- """Find all code blocks in the document."""
88
- blocks = []
89
- i = 0
90
-
91
- while i < len(lines):
92
- # Check for [source] prefix first
93
- match = self.CODE_BLOCK_START.match(lines[i])
94
- if match:
95
- language = match.group(1)
96
- start = i
97
- i += 1
98
-
99
- # Find the delimiter line (---- or ....)
100
- if i < len(lines) and lines[i].strip() in ['----', '....']:
101
- delimiter = lines[i].strip()
102
- i += 1
103
- content_start = i
104
-
105
- # Find the closing delimiter
106
- while i < len(lines):
107
- if lines[i].strip() == delimiter:
108
- content = lines[content_start:i]
109
- blocks.append(CodeBlock(
110
- start_line=start,
111
- end_line=i,
112
- delimiter=delimiter,
113
- content=content,
114
- language=language
115
- ))
116
- break
117
- i += 1
118
- # Check for plain delimited blocks without [source] prefix
119
- elif lines[i].strip() in ['----', '....']:
120
- delimiter = lines[i].strip()
121
- start = i
122
- i += 1
123
- content_start = i
124
-
125
- # Find the closing delimiter
126
- while i < len(lines):
127
- if lines[i].strip() == delimiter:
128
- content = lines[content_start:i]
129
- # Only add if block contains callouts
130
- if any(self.CALLOUT_IN_CODE.search(line) for line in content):
131
- blocks.append(CodeBlock(
132
- start_line=start,
133
- end_line=i,
134
- delimiter=delimiter,
135
- content=content,
136
- language=None
137
- ))
138
- break
139
- i += 1
140
- i += 1
141
-
142
- return blocks
143
-
144
- def extract_callouts_from_code(self, content: List[str]) -> List[CalloutGroup]:
145
- """
146
- Extract callout numbers from code block content.
147
- Returns list of CalloutGroups, where each group contains:
148
- - The code line (with user-replaceable value if found, or full line)
149
- - List of callout numbers on that line
150
-
151
- Multiple callouts on the same line are grouped together to be merged
152
- in the definition list.
153
- """
154
- groups = []
155
-
156
- for line in content:
157
- # Look for all callout numbers on this line
158
- callout_matches = list(self.CALLOUT_IN_CODE.finditer(line))
159
- if callout_matches:
160
- # Remove all callouts from the line to get the actual code
161
- line_without_callouts = self.CALLOUT_IN_CODE.sub('', line).strip()
162
-
163
- # Find all angle-bracket enclosed values
164
- user_values = self.USER_VALUE_PATTERN.findall(line_without_callouts)
165
-
166
- # Determine what to use as the code line term
167
- if user_values:
168
- # Use the rightmost (closest to the callout) user value
169
- code_line = user_values[-1]
170
- else:
171
- # No angle-bracket value found - use the actual code line
172
- code_line = line_without_callouts
173
-
174
- # Collect all callout numbers on this line
175
- callout_nums = [int(m.group(1)) for m in callout_matches]
176
-
177
- groups.append(CalloutGroup(
178
- code_line=code_line,
179
- callout_numbers=callout_nums
180
- ))
181
-
182
- return groups
183
-
184
- def extract_callout_explanations(self, lines: List[str], start_line: int) -> Tuple[Dict[int, Callout], int]:
185
- """
186
- Extract callout explanations following a code block.
187
- Returns dict of callouts and the line number where explanations end.
188
- """
189
- explanations = {}
190
- i = start_line + 1 # Start after the closing delimiter
191
-
192
- # Skip blank lines and continuation markers (+)
193
- while i < len(lines) and (not lines[i].strip() or lines[i].strip() == '+'):
194
- i += 1
195
-
196
- # Collect consecutive callout explanation lines
197
- while i < len(lines):
198
- match = self.CALLOUT_EXPLANATION.match(lines[i])
199
- if match:
200
- num = int(match.group(1))
201
- first_line = match.group(2).strip()
202
- explanation_lines = [first_line]
203
- i += 1
204
-
205
- # Collect continuation lines (lines that don't start with a new callout)
206
- # Continue until we hit a blank line, a new callout, or certain patterns
207
- while i < len(lines):
208
- line = lines[i]
209
- # Stop if we hit a blank line, new callout, or list start marker
210
- if not line.strip() or self.CALLOUT_EXPLANATION.match(line) or line.startswith('[start='):
211
- break
212
- # Add continuation line preserving original formatting
213
- explanation_lines.append(line)
214
- i += 1
215
-
216
- # Check if marked as optional (only in first line)
217
- is_optional = False
218
- if first_line.lower().startswith('optional.') or first_line.lower().startswith('optional:'):
219
- is_optional = True
220
- # Remove "Optional." or "Optional:" from first line
221
- explanation_lines[0] = first_line[9:].strip()
222
- elif '(Optional)' in first_line or '(optional)' in first_line:
223
- is_optional = True
224
- explanation_lines[0] = re.sub(r'\s*\(optional\)\s*', ' ', first_line, flags=re.IGNORECASE).strip()
225
-
226
- explanations[num] = Callout(num, explanation_lines, is_optional)
227
- else:
228
- break
229
-
230
- return explanations, i - 1
231
-
232
- def validate_callouts(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout],
233
- input_file: Path = None, block_start: int = None, block_end: int = None) -> bool:
234
- """
235
- Validate that callout numbers in code match explanation numbers.
236
- Returns True if valid, False otherwise.
237
- """
238
- # Extract all callout numbers from groups
239
- code_nums = set()
240
- for group in callout_groups:
241
- code_nums.update(group.callout_numbers)
242
-
243
- explanation_nums = set(explanations.keys())
244
-
245
- if code_nums != explanation_nums:
246
- # Format warning message with file and line numbers
247
- if input_file and block_start is not None and block_end is not None:
248
- # Line numbers are 1-indexed for display
249
- line_range = f"{block_start + 1}-{block_end + 1}"
250
- warning_msg = (
251
- f"WARNING: {input_file.name} lines {line_range}: Callout mismatch: "
252
- f"code has {sorted(code_nums)}, explanations have {sorted(explanation_nums)}"
253
- )
254
- print_colored(warning_msg, Colors.YELLOW)
255
- # Store warning for summary
256
- self.warnings.append(warning_msg)
257
- else:
258
- self.log(f"Callout mismatch: code has {code_nums}, explanations have {explanation_nums}")
259
- return False
260
-
261
- return True
262
-
263
- def remove_callouts_from_code(self, content: List[str]) -> List[str]:
264
- """Remove callout numbers from code block content (handles multiple callouts per line)."""
265
- cleaned = []
266
- for line in content:
267
- # Remove all callout numbers and trailing whitespace
268
- cleaned.append(self.CALLOUT_IN_CODE.sub('', line).rstrip())
269
- return cleaned
270
-
271
- def create_definition_list(self, callout_groups: List[CalloutGroup], explanations: Dict[int, Callout]) -> List[str]:
272
- """
273
- Create definition list from callout groups and explanations.
274
-
275
- For callouts with user-replaceable values in angle brackets, uses those.
276
- For callouts without values, uses the actual code line as the term.
277
-
278
- When multiple callouts share the same code line (same group), their
279
- explanations are merged using AsciiDoc list continuation (+).
280
- """
281
- lines = ['\nwhere:']
282
-
283
- # Process each group (which may contain one or more callouts)
284
- for group in callout_groups:
285
- code_line = group.code_line
286
- callout_nums = group.callout_numbers
287
-
288
- # Check if this is a user-replaceable value (contains angle brackets but not heredoc)
289
- # User values are single words/phrases in angle brackets like <my-value>
290
- user_values = self.USER_VALUE_PATTERN.findall(code_line)
291
-
292
- if user_values and len(user_values) == 1 and len(code_line) < 100:
293
- # This looks like a user-replaceable value placeholder
294
- # Format the value (ensure it has angle brackets)
295
- user_value = user_values[0]
296
- if not user_value.startswith('<'):
297
- user_value = f'<{user_value}>'
298
- if not user_value.endswith('>'):
299
- user_value = f'{user_value}>'
300
- term = f'`{user_value}`'
301
- else:
302
- # This is a code line - use it as-is in backticks
303
- term = f'`{code_line}`'
304
-
305
- # Add blank line before each term
306
- lines.append('')
307
- lines.append(f'{term}::')
308
-
309
- # Add explanations for all callouts in this group
310
- for idx, callout_num in enumerate(callout_nums):
311
- explanation = explanations[callout_num]
312
-
313
- # If this is not the first explanation in the group, add continuation marker
314
- if idx > 0:
315
- lines.append('+')
316
-
317
- # Add explanation lines, prepending "Optional. " to first line if needed
318
- for line_idx, line in enumerate(explanation.lines):
319
- if line_idx == 0 and explanation.is_optional:
320
- lines.append(f'Optional. {line}')
321
- else:
322
- lines.append(line)
323
-
324
- return lines
325
-
326
60
  def convert_file(self, input_file: Path) -> Tuple[int, bool]:
327
61
  """
328
- Convert callouts in a file to definition list format.
62
+ Convert callouts in a file to the specified output format.
329
63
  Returns tuple of (number of conversions, whether file was modified).
330
64
  """
331
65
  # Read input file
@@ -339,7 +73,7 @@ class CalloutConverter:
339
73
  self.log(f"Processing {input_file} ({len(lines)} lines)")
340
74
 
341
75
  # Find all code blocks
342
- blocks = self.find_code_blocks(lines)
76
+ blocks = self.detector.find_code_blocks(lines)
343
77
  self.log(f"Found {len(blocks)} code blocks")
344
78
 
345
79
  if not blocks:
@@ -351,7 +85,7 @@ class CalloutConverter:
351
85
 
352
86
  for block in reversed(blocks):
353
87
  # Extract callouts from code (returns list of CalloutGroups)
354
- callout_groups = self.extract_callouts_from_code(block.content)
88
+ callout_groups = self.detector.extract_callouts_from_code(block.content)
355
89
 
356
90
  if not callout_groups:
357
91
  self.log(f"No callouts in block at line {block.start_line + 1}")
@@ -365,47 +99,96 @@ class CalloutConverter:
365
99
  self.log(f"Block at line {block.start_line + 1} has callouts: {all_callout_nums}")
366
100
 
367
101
  # Extract explanations
368
- explanations, explanation_end = self.extract_callout_explanations(new_lines, block.end_line)
102
+ explanations, explanation_end = self.detector.extract_callout_explanations(new_lines, block.end_line)
369
103
 
370
104
  if not explanations:
371
105
  self.log(f"No explanations found after block at line {block.start_line + 1}")
372
106
  continue
373
107
 
374
108
  # Validate callouts match
375
- if not self.validate_callouts(callout_groups, explanations, input_file, block.start_line, block.end_line):
109
+ is_valid, code_nums, explanation_nums = self.detector.validate_callouts(callout_groups, explanations)
110
+ if not is_valid:
111
+ # Format warning message with file and line numbers
112
+ line_range = f"{block.start_line + 1}-{block.end_line + 1}"
113
+ warning_msg = (
114
+ f"WARNING: {input_file.name} lines {line_range}: Callout mismatch: "
115
+ f"code has {sorted(code_nums)}, explanations have {sorted(explanation_nums)}"
116
+ )
117
+ print_colored(warning_msg, Colors.YELLOW)
118
+ self.warnings.append(warning_msg)
376
119
  continue
377
120
 
378
121
  self.log(f"Converting block at line {block.start_line + 1}")
379
122
 
380
- # Remove callouts from code
381
- cleaned_content = self.remove_callouts_from_code(block.content)
123
+ # Convert based on format option
124
+ use_deflist_fallback = False
125
+ if self.output_format == 'comments':
126
+ # For comments format, replace callouts inline in the code
127
+ converted_content, long_warnings = CommentConverter.convert(
128
+ block.content, callout_groups, explanations, block.language,
129
+ max_length=self.max_comment_length, shorten_long=False
130
+ )
382
131
 
383
- # Create definition list
384
- def_list = self.create_definition_list(callout_groups, explanations)
132
+ # If there are long comment warnings, fall back to definition list
133
+ if long_warnings:
134
+ for lw in long_warnings:
135
+ warning_msg = (
136
+ f"WARNING: {input_file.name} lines {block.start_line + 1}-{block.end_line + 1}: "
137
+ f"Callout <{lw.callout_num}> explanation too long ({lw.length} chars) "
138
+ f"for inline comment (max: {self.max_comment_length}). Falling back to definition list format."
139
+ )
140
+ print_colored(warning_msg, Colors.YELLOW)
141
+ self.warnings.append(warning_msg)
142
+ self.long_comment_warnings.append((input_file.name, block.start_line + 1, lw))
143
+
144
+ # Fall back to definition list
145
+ self.log(f"Falling back to definition list for block at line {block.start_line + 1}")
146
+ converted_content = self.detector.remove_callouts_from_code(block.content)
147
+ output_list = DefListConverter.convert(callout_groups, explanations)
148
+ use_deflist_fallback = True
149
+ else:
150
+ output_list = [] # No separate list after code block for comments
151
+ else:
152
+ # For deflist and bullets, remove callouts from code and create separate list
153
+ converted_content = self.detector.remove_callouts_from_code(block.content)
154
+
155
+ if self.output_format == 'bullets':
156
+ output_list = BulletListConverter.convert(callout_groups, explanations)
157
+ else: # default to 'deflist'
158
+ output_list = DefListConverter.convert(callout_groups, explanations)
385
159
 
386
160
  # Replace in document
387
- # 1. Update code block content
388
- # Check if block has [source] prefix by checking if start_line contains [source]
389
- has_source_prefix = self.CODE_BLOCK_START.match(new_lines[block.start_line])
161
+ # Check if block has [source] prefix
162
+ has_source_prefix = self.detector.CODE_BLOCK_START.match(new_lines[block.start_line])
390
163
  if has_source_prefix:
391
164
  content_start = block.start_line + 2 # After [source] and ----
392
165
  else:
393
166
  content_start = block.start_line + 1 # After ---- only
394
167
  content_end = block.end_line
395
168
 
396
- # 2. Remove old callout explanations
397
- explanation_start = block.end_line + 1
398
- while explanation_start < len(new_lines) and not new_lines[explanation_start].strip():
399
- explanation_start += 1
400
-
401
- # Build the new section
402
- new_section = (
403
- new_lines[:content_start] +
404
- cleaned_content +
405
- [new_lines[content_end]] + # Keep closing delimiter
406
- def_list +
407
- new_lines[explanation_end + 1:]
408
- )
169
+ # For comments format (without fallback), we keep the explanations section
170
+ # For deflist/bullets format, we remove old explanations and add new list
171
+ if self.output_format == 'comments' and not use_deflist_fallback:
172
+ # Keep everything as-is, just replace code content
173
+ new_section = (
174
+ new_lines[:content_start] +
175
+ converted_content +
176
+ new_lines[content_end:]
177
+ )
178
+ else:
179
+ # Remove old callout explanations and add new list
180
+ explanation_start = block.end_line + 1
181
+ while explanation_start < len(new_lines) and not new_lines[explanation_start].strip():
182
+ explanation_start += 1
183
+
184
+ # Build the new section
185
+ new_section = (
186
+ new_lines[:content_start] +
187
+ converted_content +
188
+ [new_lines[content_end]] + # Keep closing delimiter
189
+ output_list +
190
+ new_lines[explanation_end + 1:]
191
+ )
409
192
 
410
193
  new_lines = new_section
411
194
  conversions += 1
@@ -497,23 +280,29 @@ def load_exclusion_list(exclusion_file: Path) -> Tuple[List[str], List[str]]:
497
280
  def main():
498
281
  """Main entry point"""
499
282
  parser = argparse.ArgumentParser(
500
- description='Convert AsciiDoc callouts to definition list format',
283
+ description='Convert AsciiDoc callouts to various formats',
501
284
  formatter_class=argparse.RawDescriptionHelpFormatter,
502
285
  epilog="""
503
- Convert AsciiDoc callout-style documentation to definition list format.
286
+ Convert AsciiDoc callout-style documentation to various formats.
504
287
 
505
288
  This script identifies code blocks with callout numbers (<1>, <2>, etc.) and their
506
- corresponding explanation lines, then converts them to a cleaner definition list format
507
- with "where:" prefix.
289
+ corresponding explanation lines, then converts them to your chosen format.
290
+
291
+ Formats:
292
+ deflist - Definition list with "where:" prefix (default)
293
+ bullets - Bulleted list format
294
+ comments - Inline comments within code (removes separate explanations)
508
295
 
509
296
  Examples:
510
297
  %(prog)s # Process all .adoc files in current directory
511
298
  %(prog)s modules/ # Process all .adoc files in modules/
512
299
  %(prog)s assemblies/my-guide.adoc # Process single file
513
300
  %(prog)s --dry-run modules/ # Preview changes without modifying
301
+ %(prog)s --format bullets modules/ # Convert to bulleted list format
302
+ %(prog)s --format comments src/ # Convert to inline comments
514
303
  %(prog)s --exclude-dir .vale modules/ # Exclude .vale directory
515
304
 
516
- Example transformation:
305
+ Example transformation (deflist format):
517
306
  FROM:
518
307
  [source,yaml]
519
308
  ----
@@ -556,6 +345,18 @@ Example transformation:
556
345
  action='store_true',
557
346
  help='Enable verbose output'
558
347
  )
348
+ parser.add_argument(
349
+ '-f', '--format',
350
+ choices=['deflist', 'bullets', 'comments'],
351
+ default='deflist',
352
+ help='Output format: "deflist" for definition list (default), "bullets" for bulleted list, "comments" for inline comments'
353
+ )
354
+ parser.add_argument(
355
+ '--max-comment-length',
356
+ type=int,
357
+ default=120,
358
+ help='Maximum length for inline comments before falling back to definition list (default: 120 characters)'
359
+ )
559
360
  parser.add_argument(
560
361
  '--exclude-dir',
561
362
  action='append',
@@ -613,7 +414,8 @@ Example transformation:
613
414
  print(f"Found {len(adoc_files)} AsciiDoc file(s) to process")
614
415
 
615
416
  # Create converter
616
- converter = CalloutConverter(dry_run=args.dry_run, verbose=args.verbose)
417
+ converter = CalloutConverter(dry_run=args.dry_run, verbose=args.verbose, output_format=args.format,
418
+ max_comment_length=args.max_comment_length)
617
419
 
618
420
  # Process each file
619
421
  files_processed = 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rolfedh-doc-utils
3
- Version: 0.1.23
3
+ Version: 0.1.25
4
4
  Summary: CLI tools for AsciiDoc documentation projects
5
5
  Author: Rolfe Dlugy-Hegwer
6
6
  License: MIT License
@@ -1,13 +1,19 @@
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_to_deflist.py,sha256=Rd5jaX2c9qsj4fj0JftohBDXurJTLLXxDSzkUSH2-lE,25115
4
+ convert_callouts_interactive.py,sha256=hoDKff3jqyJiGZ3IqjcWF7AXM4XUQE-vVg2NpJYECs4,21066
5
+ convert_callouts_to_deflist.py,sha256=WRpHmD3DWs7G7qEcL6c9WLYpX4uaPzlMKrWXnPlHQ_s,17720
5
6
  doc_utils_cli.py,sha256=dsMYrkAriYdZUF0_cSPh5DAPrJMPiecuY26xN-p0UJ0,4911
6
7
  extract_link_attributes.py,sha256=wR2SmR2la-jR6DzDbas2PoNONgRZ4dZ6aqwzkwEv8Gs,3516
7
8
  find_unused_attributes.py,sha256=77CxFdm72wj6SO81w-auMdDjnvF83jWy_qaM7DsAtBw,4263
8
9
  format_asciidoc_spacing.py,sha256=nmWpw2dgwhd81LXyznq0rT8w6Z7cNRyGtPJGRyKFRdc,4212
9
10
  replace_link_attributes.py,sha256=Cpc4E-j9j-4_y0LOstAKYOPl02Ln_2bGNIeqp3ZVCdA,7624
10
11
  validate_links.py,sha256=lWuK8sgfiFdfcUdSVAt_5U9JHVde_oa6peSUlBQtsac,6145
12
+ callout_lib/__init__.py,sha256=8B82N_z4D1LaZVYgd5jZR53QAabtgPzADOyGlnvihj0,665
13
+ callout_lib/converter_bullets.py,sha256=8P92QZ0PylrKRE7V-D3TVZCDH0ct3GRIonc7W5AK5uU,3898
14
+ callout_lib/converter_comments.py,sha256=do0dH8uOyNFpn5CDEzR0jYYCMIPP3oPFM8cEB-Fp22c,9767
15
+ callout_lib/converter_deflist.py,sha256=mQ17Y8gJLv0MzzJscpUL7ujuDRyEVcrb9lcPdUNkIX4,3117
16
+ callout_lib/detector.py,sha256=douBVXaTM_VWzI5mN8R7QyYzqxD1sVTFPuAbU-blPNo,8806
11
17
  doc_utils/__init__.py,sha256=qqZR3lohzkP63soymrEZPBGzzk6-nFzi4_tSffjmu_0,74
12
18
  doc_utils/extract_link_attributes.py,sha256=U0EvPZReJQigNfbT-icBsVT6Li64hYki5W7MQz6qqbc,22743
13
19
  doc_utils/file_utils.py,sha256=fpTh3xx759sF8sNocdn_arsP3KAv8XA6cTQTAVIZiZg,4247
@@ -22,9 +28,9 @@ doc_utils/unused_images.py,sha256=nqn36Bbrmon2KlGlcaruNjJJvTQ8_9H0WU9GvCW7rW8,14
22
28
  doc_utils/validate_links.py,sha256=iBGXnwdeLlgIT3fo3v01ApT5k0X2FtctsvkrE6E3VMk,19610
23
29
  doc_utils/version.py,sha256=5Uc0sAUOkXA6R_PvDGjw2MBYptEKdav5XmeRqukMTo0,203
24
30
  doc_utils/version_check.py,sha256=eHJnZmBTbdhhY2fJQW9KnnyD0rWEvCZpMg6oSr0fOmI,7090
25
- rolfedh_doc_utils-0.1.23.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
26
- rolfedh_doc_utils-0.1.23.dist-info/METADATA,sha256=ajW7JUW_CmM2tgioJPBzoWne7bcbLdoO-pYErq-NBP8,8325
27
- rolfedh_doc_utils-0.1.23.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
- rolfedh_doc_utils-0.1.23.dist-info/entry_points.txt,sha256=uoZFRyvDmJfz-0M6cKyB2WjxH0WCmeRrDq0Os1R1wd8,512
29
- rolfedh_doc_utils-0.1.23.dist-info/top_level.txt,sha256=O13H7Ibk6HKNC32hpcqK8Cq13jiIqRP6A_bB66Zib1Q,224
30
- rolfedh_doc_utils-0.1.23.dist-info/RECORD,,
31
+ rolfedh_doc_utils-0.1.25.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
32
+ rolfedh_doc_utils-0.1.25.dist-info/METADATA,sha256=MxNbC8OYyyEGXZE_iEipQJHSvpsxzbcyA3e32nD_hsA,8325
33
+ rolfedh_doc_utils-0.1.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
+ rolfedh_doc_utils-0.1.25.dist-info/entry_points.txt,sha256=vL_LlLKOiurRzchrq8iRUQG19Xi9lSAFVZGjO-xyErk,577
35
+ rolfedh_doc_utils-0.1.25.dist-info/top_level.txt,sha256=J4xtr3zoyCip27b3GnticFVZoyz5HHtgGqHQ-SZONCA,265
36
+ rolfedh_doc_utils-0.1.25.dist-info/RECORD,,
@@ -2,6 +2,7 @@
2
2
  archive-unused-files = archive_unused_files:main
3
3
  archive-unused-images = archive_unused_images:main
4
4
  check-scannability = check_scannability:main
5
+ convert-callouts-interactive = convert_callouts_interactive:main
5
6
  convert-callouts-to-deflist = convert_callouts_to_deflist:main
6
7
  doc-utils = doc_utils_cli:main
7
8
  extract-link-attributes = extract_link_attributes:main
@@ -1,6 +1,8 @@
1
1
  archive_unused_files
2
2
  archive_unused_images
3
+ callout_lib
3
4
  check_scannability
5
+ convert_callouts_interactive
4
6
  convert_callouts_to_deflist
5
7
  doc_utils
6
8
  doc_utils_cli