rolfedh-doc-utils 0.1.6__py3-none-any.whl → 0.1.7__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.
@@ -0,0 +1,318 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """Format AsciiDoc spacing - ensures blank lines after headings and around include directives"""
4
+
5
+ import argparse
6
+ import os
7
+ import re
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import List, Tuple
11
+
12
+
13
+ # Colors for output
14
+ class Colors:
15
+ RED = '\033[0;31m'
16
+ GREEN = '\033[0;32m'
17
+ YELLOW = '\033[1;33m'
18
+ NC = '\033[0m' # No Color
19
+
20
+
21
+ def print_colored(message: str, color: str = Colors.NC) -> None:
22
+ """Print message with color"""
23
+ print(f"{color}{message}{Colors.NC}")
24
+
25
+
26
+ def process_file(file_path: Path, dry_run: bool = False, verbose: bool = False) -> bool:
27
+ """
28
+ Process a single AsciiDoc file to fix spacing issues.
29
+
30
+ Args:
31
+ file_path: Path to the file to process
32
+ dry_run: If True, show what would be changed without modifying
33
+ verbose: If True, show detailed output
34
+
35
+ Returns:
36
+ True if changes were made (or would be made in dry-run), False otherwise
37
+ """
38
+ if verbose:
39
+ print(f"Processing: {file_path}")
40
+
41
+ try:
42
+ with open(file_path, 'r', encoding='utf-8') as f:
43
+ lines = f.readlines()
44
+ except (IOError, UnicodeDecodeError) as e:
45
+ print_colored(f"Error reading {file_path}: {e}", Colors.RED)
46
+ return False
47
+
48
+ # Remove trailing newlines from lines for processing
49
+ lines = [line.rstrip('\n\r') for line in lines]
50
+
51
+ new_lines = []
52
+ changes_made = False
53
+ in_block = False # Track if we're inside a block (admonition, listing, etc.)
54
+ in_conditional = False # Track if we're inside a conditional block
55
+
56
+ for i, current_line in enumerate(lines):
57
+ prev_line = lines[i-1] if i > 0 else ""
58
+ next_line = lines[i+1] if i + 1 < len(lines) else ""
59
+
60
+ # Check for conditional start (ifdef:: or ifndef::)
61
+ if re.match(r'^(ifdef::|ifndef::)', current_line):
62
+ in_conditional = True
63
+ # Add blank line before conditional if needed
64
+ if (prev_line and
65
+ not re.match(r'^\s*$', prev_line) and
66
+ not re.match(r'^(ifdef::|ifndef::|endif::)', prev_line)):
67
+ new_lines.append("")
68
+ changes_made = True
69
+ if verbose:
70
+ print(f" Added blank line before conditional block")
71
+ new_lines.append(current_line)
72
+
73
+ # Check for conditional end (endif::)
74
+ elif re.match(r'^endif::', current_line):
75
+ new_lines.append(current_line)
76
+ in_conditional = False
77
+ # Add blank line after conditional if needed
78
+ if (next_line and
79
+ not re.match(r'^\s*$', next_line) and
80
+ not re.match(r'^(ifdef::|ifndef::|endif::)', next_line)):
81
+ new_lines.append("")
82
+ changes_made = True
83
+ if verbose:
84
+ print(f" Added blank line after conditional block")
85
+
86
+ # Check for block delimiters (====, ----, ...., ____)
87
+ # These are used for admonitions, listing blocks, literal blocks, etc.
88
+ elif re.match(r'^(====+|----+|\.\.\.\.+|____+)$', current_line):
89
+ in_block = not in_block # Toggle block state
90
+ new_lines.append(current_line)
91
+ # Check if current line is a heading (but not if we're in a block)
92
+ elif not in_block and re.match(r'^=+\s+', current_line):
93
+ new_lines.append(current_line)
94
+
95
+ # Check if next line is not empty and not another heading
96
+ if (next_line and
97
+ not re.match(r'^=+\s+', next_line) and
98
+ not re.match(r'^\s*$', next_line)):
99
+ new_lines.append("")
100
+ changes_made = True
101
+ if verbose:
102
+ truncated = current_line[:50] + "..." if len(current_line) > 50 else current_line
103
+ print(f" Added blank line after heading: {truncated}")
104
+
105
+ # Check if current line is a comment (AsciiDoc comments start with //)
106
+ elif re.match(r'^//', current_line):
107
+ # Skip special handling if we're inside a conditional block
108
+ if in_conditional:
109
+ new_lines.append(current_line)
110
+ else:
111
+ # Check if next line is an include directive
112
+ if next_line and re.match(r'^include::', next_line):
113
+ # This comment belongs to the include, add blank line before comment if needed
114
+ if (prev_line and
115
+ not re.match(r'^\s*$', prev_line) and
116
+ not re.match(r'^//', prev_line) and
117
+ not re.match(r'^:', prev_line)): # Don't add if previous is attribute
118
+ new_lines.append("")
119
+ changes_made = True
120
+ if verbose:
121
+ print(f" Added blank line before comment above include")
122
+ new_lines.append(current_line)
123
+
124
+ # Check if current line is an attribute (starts with :)
125
+ elif re.match(r'^:', current_line):
126
+ # Skip special handling if we're inside a conditional block
127
+ if in_conditional:
128
+ new_lines.append(current_line)
129
+ else:
130
+ # Check if next line is an include directive
131
+ if next_line and re.match(r'^include::', next_line):
132
+ # This attribute belongs to the include, add blank line before attribute if needed
133
+ if (prev_line and
134
+ not re.match(r'^\s*$', prev_line) and
135
+ not re.match(r'^//', prev_line) and
136
+ not re.match(r'^:', prev_line)): # Don't add if previous is comment or attribute
137
+ new_lines.append("")
138
+ changes_made = True
139
+ if verbose:
140
+ print(f" Added blank line before attribute above include")
141
+ new_lines.append(current_line)
142
+
143
+ # Check if current line is an include directive
144
+ elif re.match(r'^include::', current_line):
145
+ # Skip special handling if we're inside a conditional block
146
+ if in_conditional:
147
+ new_lines.append(current_line)
148
+ else:
149
+ # Check if this is an attribute include (contains "attribute" in the path)
150
+ is_attribute_include = 'attribute' in current_line.lower()
151
+
152
+ # Check if this appears near the top of the file (within first 10 lines after H1)
153
+ # Find the H1 heading position
154
+ h1_position = -1
155
+ for j in range(min(i, 10)): # Look back up to 10 lines or to current position
156
+ if re.match(r'^=\s+', lines[j]): # H1 heading starts with single =
157
+ h1_position = j
158
+ break
159
+
160
+ # If this is an attribute include near the H1 heading, don't add surrounding blank lines
161
+ is_near_h1 = h1_position >= 0 and (i - h1_position) <= 2
162
+
163
+ # Check if previous line is a comment or attribute (which belongs to this include)
164
+ has_comment_above = prev_line and re.match(r'^//', prev_line)
165
+ has_attribute_above = prev_line and re.match(r'^:', prev_line)
166
+
167
+ # If it's an attribute include near H1, only the heading's blank line is needed
168
+ if not (is_attribute_include and is_near_h1):
169
+ # Don't add blank line if there's a comment or attribute above (it was handled by the comment/attribute logic)
170
+ if not has_comment_above and not has_attribute_above:
171
+ # Add blank line before include if previous line is not empty and not an include
172
+ if (prev_line and
173
+ not re.match(r'^\s*$', prev_line) and
174
+ not re.match(r'^include::', prev_line)):
175
+ new_lines.append("")
176
+ changes_made = True
177
+ if verbose:
178
+ truncated = current_line[:50] + "..." if len(current_line) > 50 else current_line
179
+ print(f" Added blank line before include: {truncated}")
180
+
181
+ new_lines.append(current_line)
182
+
183
+ # If it's an attribute include near H1, don't add blank line after
184
+ if not (is_attribute_include and is_near_h1):
185
+ # Add blank line after include if next line exists and is not empty and not an include
186
+ if (next_line and
187
+ not re.match(r'^\s*$', next_line) and
188
+ not re.match(r'^include::', next_line)):
189
+ new_lines.append("")
190
+ changes_made = True
191
+ if verbose:
192
+ truncated = current_line[:50] + "..." if len(current_line) > 50 else current_line
193
+ print(f" Added blank line after include: {truncated}")
194
+
195
+ else:
196
+ new_lines.append(current_line)
197
+
198
+ # Apply changes if any were made
199
+ if changes_made:
200
+ # Clean up any consecutive blank lines we may have added
201
+ cleaned_lines = []
202
+ for i, line in enumerate(new_lines):
203
+ # Check if this is a blank line we're about to add
204
+ if line == "":
205
+ # Check if the previous line is also a blank line
206
+ if i > 0 and cleaned_lines and cleaned_lines[-1] == "":
207
+ # Skip this blank line as we already have one
208
+ continue
209
+ cleaned_lines.append(line)
210
+
211
+ if dry_run:
212
+ print_colored(f"Would modify: {file_path}", Colors.YELLOW)
213
+ else:
214
+ try:
215
+ with open(file_path, 'w', encoding='utf-8') as f:
216
+ for line in cleaned_lines:
217
+ f.write(line + '\n')
218
+ print_colored(f"Modified: {file_path}", Colors.GREEN)
219
+ except IOError as e:
220
+ print_colored(f"Error writing {file_path}: {e}", Colors.RED)
221
+ return False
222
+ else:
223
+ if verbose:
224
+ print(" No changes needed")
225
+
226
+ return changes_made
227
+
228
+
229
+ def find_adoc_files(path: Path) -> List[Path]:
230
+ """Find all .adoc files in the given path"""
231
+ adoc_files = []
232
+
233
+ if path.is_file():
234
+ if path.suffix == '.adoc':
235
+ adoc_files.append(path)
236
+ else:
237
+ print_colored(f"Warning: {path} is not an AsciiDoc file (.adoc)", Colors.YELLOW)
238
+ elif path.is_dir():
239
+ adoc_files = list(path.rglob('*.adoc'))
240
+
241
+ return adoc_files
242
+
243
+
244
+ def main():
245
+ """Main entry point"""
246
+ parser = argparse.ArgumentParser(
247
+ description="Format AsciiDoc files to ensure proper spacing",
248
+ formatter_class=argparse.RawDescriptionHelpFormatter,
249
+ epilog="""
250
+ Format AsciiDoc files to ensure proper spacing:
251
+ - Blank line after headings (=, ==, ===, etc.)
252
+ - Blank lines around include:: directives
253
+
254
+ Examples:
255
+ %(prog)s # Process all .adoc files in current directory
256
+ %(prog)s modules/ # Process all .adoc files in modules/
257
+ %(prog)s assemblies/my-guide.adoc # Process single file
258
+ %(prog)s --dry-run modules/ # Preview changes without modifying
259
+ """
260
+ )
261
+
262
+ parser.add_argument(
263
+ 'path',
264
+ nargs='?',
265
+ default='.',
266
+ help='File or directory to process (default: current directory)'
267
+ )
268
+ parser.add_argument(
269
+ '-n', '--dry-run',
270
+ action='store_true',
271
+ help='Show what would be changed without modifying files'
272
+ )
273
+ parser.add_argument(
274
+ '-v', '--verbose',
275
+ action='store_true',
276
+ help='Show detailed output'
277
+ )
278
+
279
+ args = parser.parse_args()
280
+
281
+ # Convert path to Path object
282
+ target_path = Path(args.path)
283
+
284
+ # Check if path exists
285
+ if not target_path.exists():
286
+ print_colored(f"Error: Path does not exist: {target_path}", Colors.RED)
287
+ sys.exit(1)
288
+
289
+ # Display dry-run mode message
290
+ if args.dry_run:
291
+ print_colored("DRY RUN MODE - No files will be modified", Colors.YELLOW)
292
+
293
+ # Find all AsciiDoc files
294
+ adoc_files = find_adoc_files(target_path)
295
+
296
+ if not adoc_files:
297
+ print(f"Processed 0 AsciiDoc file(s)")
298
+ print("AsciiDoc spacing formatting complete!")
299
+ return
300
+
301
+ # Process each file
302
+ files_processed = 0
303
+ for file_path in adoc_files:
304
+ try:
305
+ process_file(file_path, args.dry_run, args.verbose)
306
+ files_processed += 1
307
+ except KeyboardInterrupt:
308
+ print_colored("\nOperation cancelled by user", Colors.YELLOW)
309
+ sys.exit(1)
310
+ except Exception as e:
311
+ print_colored(f"Unexpected error processing {file_path}: {e}", Colors.RED)
312
+
313
+ print(f"Processed {files_processed} AsciiDoc file(s)")
314
+ print("AsciiDoc spacing formatting complete!")
315
+
316
+
317
+ if __name__ == "__main__":
318
+ main()
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: rolfedh-doc-utils
3
+ Version: 0.1.7
4
+ Summary: CLI tools for AsciiDoc documentation projects
5
+ Author: Rolfe Dlugy-Hegwer
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Rolfe Dlugy-Hegwer
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Requires-Python: >=3.8
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: PyYAML>=6.0
32
+ Dynamic: license-file
33
+
34
+ # doc-utils
35
+
36
+ [![PyPI version](https://badge.fury.io/py/rolfedh-doc-utils.svg)](https://pypi.org/project/rolfedh-doc-utils/)
37
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
38
+ [![License](https://img.shields.io/github/license/rolfedh/doc-utils)](https://github.com/rolfedh/doc-utils/blob/main/LICENSE)
39
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-brightgreen)](https://rolfedh.github.io/doc-utils/)
40
+
41
+ Python CLI tools for maintaining clean, consistent AsciiDoc documentation repositories.
42
+
43
+ 📚 **[View Full Documentation](https://rolfedh.github.io/doc-utils/)** | 📦 **[PyPI Package](https://pypi.org/project/rolfedh-doc-utils/)** | 🐙 **[GitHub](https://github.com/rolfedh/doc-utils)**
44
+
45
+ ## ⚠️ Safety First
46
+
47
+ These tools can modify or delete files. **Always:**
48
+ - Work in a git branch (never main/master)
49
+ - Review changes with `git diff`
50
+ - Test documentation builds after changes
51
+
52
+ ## 🚀 Quick Start
53
+
54
+ ### Install with pipx (Recommended)
55
+
56
+ ```bash
57
+ pipx install rolfedh-doc-utils
58
+ ```
59
+
60
+ ### Alternative Installation
61
+
62
+ ```bash
63
+ # With pip user flag
64
+ pip install --user rolfedh-doc-utils
65
+
66
+ # For development
67
+ git clone https://github.com/rolfedh/doc-utils.git
68
+ cd doc-utils
69
+ pip install -e .
70
+ ```
71
+
72
+ ## 🛠️ Available Tools
73
+
74
+ | Tool | Description | Usage |
75
+ |------|-------------|-------|
76
+ | **`format-asciidoc-spacing`** | Standardizes spacing after headings and around includes | `format-asciidoc-spacing --dry-run .` |
77
+ | **`check-scannability`** | Analyzes readability (sentence/paragraph length) | `check-scannability --max-words 25` |
78
+ | **`archive-unused-files`** | Finds and archives unreferenced .adoc files | `archive-unused-files --archive` |
79
+ | **`archive-unused-images`** | Finds and archives unreferenced images | `archive-unused-images --archive` |
80
+ | **`find-unused-attributes`** | Identifies unused attribute definitions | `find-unused-attributes attributes.adoc` |
81
+
82
+ ## 📖 Documentation
83
+
84
+ Comprehensive documentation is available at **[rolfedh.github.io/doc-utils](https://rolfedh.github.io/doc-utils/)**
85
+
86
+ - [Getting Started Guide](https://rolfedh.github.io/doc-utils/getting-started)
87
+ - [Tools Reference](https://rolfedh.github.io/doc-utils/tools/)
88
+ - [Best Practices](https://rolfedh.github.io/doc-utils/best-practices)
89
+ - [Contributing](https://rolfedh.github.io/doc-utils/contributing)
90
+
91
+ ## 💡 Common Workflows
92
+
93
+ ### Clean Up Documentation
94
+
95
+ ```bash
96
+ # 1. Create a branch
97
+ git checkout -b doc-cleanup
98
+
99
+ # 2. Preview what would change
100
+ format-asciidoc-spacing --dry-run .
101
+ archive-unused-files
102
+ archive-unused-images
103
+
104
+ # 3. Apply changes
105
+ format-asciidoc-spacing .
106
+ archive-unused-files --archive
107
+ archive-unused-images --archive
108
+
109
+ # 4. Review and commit
110
+ git diff
111
+ git add -A && git commit -m "Clean up documentation"
112
+ ```
113
+
114
+ ### Check Documentation Quality
115
+
116
+ ```bash
117
+ # Check readability
118
+ check-scannability --max-words 30 --max-sentences 5
119
+
120
+ # Find unused attributes
121
+ find-unused-attributes attributes.adoc
122
+
123
+ # Save results
124
+ find-unused-attributes attributes.adoc --output unused.txt
125
+ ```
126
+
127
+ ## 🔧 Exclusions
128
+
129
+ All tools support excluding files and directories:
130
+
131
+ ```bash
132
+ # Exclude specific directories
133
+ archive-unused-files --exclude-dir ./temp --exclude-dir ./drafts
134
+
135
+ # Exclude specific files
136
+ check-scannability --exclude-file ./README.adoc
137
+
138
+ # Use exclusion list file
139
+ echo "./deprecated/" > .docutils-ignore
140
+ archive-unused-images --exclude-list .docutils-ignore
141
+ ```
142
+
143
+ ## 🧪 Development
144
+
145
+ ```bash
146
+ # Install dev dependencies
147
+ pip install -r requirements-dev.txt
148
+
149
+ # Run tests
150
+ python -m pytest tests/ -v
151
+
152
+ # Run specific test
153
+ python -m pytest tests/test_file_utils.py
154
+ ```
155
+
156
+ ## 🤝 Contributing
157
+
158
+ We welcome contributions! See our [Contributing Guide](https://rolfedh.github.io/doc-utils/contributing) for details.
159
+
160
+ Before submitting PRs:
161
+ - ✅ All tests pass
162
+ - ✅ Code follows PEP 8
163
+ - ✅ Documentation updated
164
+ - ✅ Changelog entry added
165
+
166
+ ## 📊 Project Status
167
+
168
+ - **Latest Version**: 0.1.6
169
+ - **Python Support**: 3.8+
170
+ - **Test Coverage**: 66+ tests (100% passing)
171
+ - **Dependencies**: Minimal (PyYAML for OpenShift-docs support)
172
+
173
+ ## 🔗 Resources
174
+
175
+ - [Documentation](https://rolfedh.github.io/doc-utils/)
176
+ - [PyPI Package](https://pypi.org/project/rolfedh-doc-utils/)
177
+ - [Issue Tracker](https://github.com/rolfedh/doc-utils/issues)
178
+ - [Changelog](https://github.com/rolfedh/doc-utils/blob/main/CHANGELOG.md)
179
+ - [License](https://github.com/rolfedh/doc-utils/blob/main/LICENSE)
180
+
181
+ ## 📝 License
182
+
183
+ This project is licensed under the terms specified in the [LICENSE](https://github.com/rolfedh/doc-utils/blob/main/LICENSE) file.
184
+
185
+ ---
186
+
187
+ Created by [Rolfe Dlugy-Hegwer](https://github.com/rolfedh) for technical writers everywhere.
@@ -2,6 +2,7 @@ archive_unused_files.py,sha256=KMC5a1WL3rZ5owoVnncvfpT1YeMKbVXq9giHvadDgbM,1936
2
2
  archive_unused_images.py,sha256=PG2o3haovYckgfhoPhl6KRG_a9czyZuqlLkzkupKTCY,1526
3
3
  check_scannability.py,sha256=gcM-vFXKHGP_yFBz7-V5xbXWhIMmtMzBYIGwP9CFbzI,5140
4
4
  find_unused_attributes.py,sha256=fk-K32eoCVHxoj7RiBNgSmX1arBLuwYfdSAOMc-wIx0,1677
5
+ format_asciidoc_spacing.py,sha256=Jy_V8c03KGRPJxu4uPdDuMsFg-Q-4AGD9BdkGnApUu8,13241
5
6
  doc_utils/__init__.py,sha256=qqZR3lohzkP63soymrEZPBGzzk6-nFzi4_tSffjmu_0,74
6
7
  doc_utils/file_utils.py,sha256=fpTh3xx759sF8sNocdn_arsP3KAv8XA6cTQTAVIZiZg,4247
7
8
  doc_utils/scannability.py,sha256=XwlmHqDs69p_V36X7DLjPTy0DUoLszSGqYjJ9wE-3hg,982
@@ -9,9 +10,9 @@ doc_utils/topic_map_parser.py,sha256=tKcIO1m9r2K6dvPRGue58zqMr0O2zKU1gnZMzEE3U6o
9
10
  doc_utils/unused_adoc.py,sha256=2cbqcYr1os2EhETUU928BlPRlsZVSdI00qaMhqjSIqQ,5263
10
11
  doc_utils/unused_attributes.py,sha256=HBgmHelqearfWl3TTC2bZGiJytjLADIgiGQUNKqXXPg,1847
11
12
  doc_utils/unused_images.py,sha256=nqn36Bbrmon2KlGlcaruNjJJvTQ8_9H0WU9GvCW7rW8,1456
12
- rolfedh_doc_utils-0.1.6.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
13
- rolfedh_doc_utils-0.1.6.dist-info/METADATA,sha256=JoFOMLPMcQiGaSXBwqXLVZP5jLahLSP0s8_go98X4N8,8787
14
- rolfedh_doc_utils-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- rolfedh_doc_utils-0.1.6.dist-info/entry_points.txt,sha256=dA-u4qlxKcewUAOFgaeW1NUIrkhsVknuwFuGTn1-84w,271
16
- rolfedh_doc_utils-0.1.6.dist-info/top_level.txt,sha256=WrYqTa4wbjRPMUl2hgJBfP734XsXLkhbnzUublx8S0s,119
17
- rolfedh_doc_utils-0.1.6.dist-info/RECORD,,
13
+ rolfedh_doc_utils-0.1.7.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
14
+ rolfedh_doc_utils-0.1.7.dist-info/METADATA,sha256=KZ9pa1ZFWS_rj4iVRW9TTbL6RPWvVFfL2twZseuk9Ko,6200
15
+ rolfedh_doc_utils-0.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ rolfedh_doc_utils-0.1.7.dist-info/entry_points.txt,sha256=dA-u4qlxKcewUAOFgaeW1NUIrkhsVknuwFuGTn1-84w,271
17
+ rolfedh_doc_utils-0.1.7.dist-info/top_level.txt,sha256=WrYqTa4wbjRPMUl2hgJBfP734XsXLkhbnzUublx8S0s,119
18
+ rolfedh_doc_utils-0.1.7.dist-info/RECORD,,
@@ -1,303 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: rolfedh-doc-utils
3
- Version: 0.1.6
4
- Summary: CLI tools for AsciiDoc documentation projects
5
- Author: Rolfe Dlugy-Hegwer
6
- License: MIT License
7
-
8
- Copyright (c) 2025 Rolfe Dlugy-Hegwer
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- copies of the Software, and to permit persons to whom the Software is
15
- furnished to do so, subject to the following conditions:
16
-
17
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
27
-
28
- Requires-Python: >=3.8
29
- Description-Content-Type: text/markdown
30
- License-File: LICENSE
31
- Requires-Dist: PyYAML>=6.0
32
- Dynamic: license-file
33
-
34
- # doc-utils
35
-
36
- A set of Python utilities and CLI tools to help technical writers maintain AsciiDoc documentation repositories.
37
-
38
- > ⚠️ **IMPORTANT: Safety First**
39
- >
40
- > These tools can modify or delete files in your documentation repository. Always:
41
- > - **Work in a git branch** - Never run these tools on the main/master branch
42
- > - **Review all changes carefully** - Use `git diff` or a pull request to verify modifications
43
- > - **Check your preview builds** - Ensure no documentation errors were introduced
44
-
45
- ## Resources
46
-
47
- - [PyPI: rolfedh-doc-utils](https://pypi.org/project/rolfedh-doc-utils/)
48
- - [GitHub repository](https://github.com/rolfedh/doc-utils)
49
-
50
- ## Installation
51
-
52
- ### From PyPI
53
-
54
- On modern Linux distributions, you may encounter an "externally-managed-environment" error. Use one of these methods:
55
-
56
- **Option 1: pipx (Recommended for CLI tools)**
57
- ```sh
58
- pipx install rolfedh-doc-utils
59
- ```
60
-
61
- **Option 2: pip with --user flag**
62
- ```sh
63
- pip install --user rolfedh-doc-utils
64
- ```
65
-
66
- **Option 3: Traditional pip (may require virtual environment)**
67
- ```sh
68
- pip install rolfedh-doc-utils
69
- ```
70
-
71
- ### Upgrading
72
-
73
- To upgrade to the latest version:
74
-
75
- ```sh
76
- # If installed with pipx:
77
- pipx upgrade rolfedh-doc-utils
78
-
79
- # If installed with pip:
80
- pip install --upgrade rolfedh-doc-utils # or --user flag if needed
81
- ```
82
-
83
- ### For Development
84
-
85
- If you're developing or testing locally, install the package in editable mode:
86
-
87
- ```sh
88
- # Clone the repository
89
- git clone https://github.com/rolfedh/doc-utils.git
90
- cd doc-utils
91
-
92
- # Install in editable mode
93
- pip install -e .
94
- ```
95
-
96
- The following CLI tools are installed:
97
-
98
- * `check-scannability`
99
- * `archive-unused-files`
100
- * `archive-unused-images`
101
- * `find-unused-attributes`
102
- * `format-asciidoc-spacing`
103
-
104
- These tools can be run from any directory.
105
-
106
- ### Add to PATH (if needed)
107
-
108
- By default, CLI tools install to:
109
-
110
- ```sh
111
- $HOME/.local/bin
112
- ```
113
-
114
- If this directory isn’t in your `PATH`, commands may not run. Append it to your shell configuration:
115
-
116
- ```sh
117
- echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc # or ~/.zshrc
118
- ```
119
-
120
- Then reload your shell:
121
-
122
- ```sh
123
- source ~/.bashrc # or ~/.zshrc
124
- ```
125
-
126
- ## CLI Tools Overview
127
-
128
- ### `check-scannability`
129
-
130
- Scans `.adoc` files in the current directory to report:
131
-
132
- * Sentences that exceed a length limit (default: 22 words)
133
- * Paragraphs with too many sentences (default: 3 sentences)
134
- * Supports exclusion of files and directories
135
-
136
- ➡️ See [Scannability Checker for AsciiDoc Files](https://github.com/rolfedh/doc-utils/blob/main/check_scannability.md) for details.
137
-
138
- ---
139
-
140
- ### `archive-unused-files`
141
-
142
- Scans the `./modules` and `./assemblies` directories for `.adoc` files that are not referenced. Optionally archives and deletes them.
143
-
144
- Works with both:
145
- - **OpenShift-docs style** repositories (uses `_topic_maps/*.yml` files)
146
- - **Traditional AsciiDoc** repositories (uses `master.adoc` files)
147
-
148
- ➡️ See [Archive Unused AsciiDoc Files](https://github.com/rolfedh/doc-utils/blob/main/archive_unused_files.md).
149
-
150
- ---
151
-
152
- ### `archive-unused-images`
153
-
154
- Finds unused image files (e.g., `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`) in the current directory and optionally archives and deletes them.
155
-
156
- ➡️ See [Archive Unused Images](https://github.com/rolfedh/doc-utils/blob/main/archive_unused_images.md).
157
-
158
- ---
159
-
160
- ### `find-unused-attributes`
161
-
162
- Scans an attributes file (e.g., `attributes.adoc`) for unused attribute definitions across all `.adoc` files in the current directory.
163
-
164
- ➡️ See [Find Unused AsciiDoc Attributes](https://github.com/rolfedh/doc-utils/blob/main/find_unused_attributes.md).
165
-
166
- ---
167
-
168
- ### `format-asciidoc-spacing`
169
-
170
- Ensures proper spacing in AsciiDoc files by adding blank lines after headings and around `include::` directives.
171
-
172
- Formatting rules:
173
- - Adds blank line after headings (`=`, `==`, `===`, etc.)
174
- - Adds blank lines before and after `include::` directives
175
- - Preserves existing spacing where appropriate
176
-
177
- Implemented as a Python script (`format-asciidoc-spacing.py`).
178
-
179
- ➡️ See [AsciiDoc Spacing Formatter](https://github.com/rolfedh/doc-utils/blob/main/format_asciidoc_spacing.md).
180
-
181
- ## Best Practices for Safe Usage
182
-
183
- ### Before Running Any Tool:
184
-
185
- - **Create a feature branch:**
186
- ```sh
187
- git checkout -b doc-cleanup-$(date +%Y%m%d)
188
- ```
189
-
190
- - **Commit any pending changes:**
191
- ```sh
192
- git add -A && git commit -m "Save work before cleanup"
193
- ```
194
-
195
- - **Run tools in preview mode first:**
196
- - For archive tools: Run without `--archive` to see what would be affected
197
-
198
- - **Review all changes and preview builds**
199
-
200
- - **Only merge after verification:**
201
-
202
- ## Usage
203
-
204
- To run the tools after installation:
205
-
206
- ```sh
207
- check-scannability --help
208
- archive-unused-files --help
209
- find-unused-attributes attributes.adoc
210
- format-asciidoc-spacing --help
211
- ```
212
-
213
- Or run them directly from source:
214
-
215
- ```sh
216
- python3 check_scannability.py
217
- python3 archive_unused_files.py
218
- python3 find_unused_attributes.py attributes.adoc
219
- python3 format-asciidoc-spacing.py
220
- ```
221
-
222
- ### Directory/File Exclusion
223
-
224
- All tools support excluding specific directories and files from scanning. You can use these options:
225
-
226
- 1. **`--exclude-dir`** - Exclude specific directories (can be used multiple times):
227
- ```sh
228
- archive-unused-files --exclude-dir ./modules/temp --exclude-dir ./modules/old
229
- ```
230
-
231
- 2. **`--exclude-file`** - Exclude specific files (can be used multiple times):
232
- ```sh
233
- check-scannability --exclude-file ./README.adoc --exclude-file ./test.adoc
234
- ```
235
-
236
- 3. **`--exclude-list`** - Point to a text file containing exclusions:
237
- ```sh
238
- archive-unused-images --exclude-list .docutils-ignore
239
- ```
240
-
241
- The exclusion file format:
242
- ```
243
- # Comments are supported
244
- ./modules/deprecated/
245
- ./assemblies/archive/
246
- ./images/temp/
247
- specific-file.adoc
248
- ```
249
-
250
- **Note:** When you exclude a parent directory, all its subdirectories are automatically excluded. Symbolic links are never followed during scanning.
251
-
252
- ## Troubleshooting
253
-
254
- ### ModuleNotFoundError
255
-
256
- If you see an error like `ModuleNotFoundError: No module named 'find_unused_attributes'`, this typically means:
257
-
258
- 1. The package isn't installed. Run:
259
- ```sh
260
- pipx install rolfedh-doc-utils # or pip install --user rolfedh-doc-utils
261
- ```
262
-
263
- 2. You're trying to run the script directly without installation. Either:
264
- - Install the package first (see Installation section)
265
- - Run the script using Python directly:
266
- ```sh
267
- python3 find_unused_attributes.py attributes.adoc
268
- ```
269
-
270
- ### Command not found
271
-
272
- If the command isn't found after installation, ensure `$HOME/.local/bin` is in your PATH (see "Add to PATH" section above).
273
-
274
- ## Development
275
-
276
- ### Running Tests
277
-
278
- The project includes a comprehensive test suite. To run tests:
279
-
280
- ```sh
281
- # Install development dependencies
282
- pip install -r requirements-dev.txt
283
-
284
- # Run all tests
285
- python -m pytest tests/
286
-
287
- # Run with verbose output
288
- python -m pytest tests/ -v
289
- ```
290
-
291
- ### Contributing
292
-
293
- Contributions are welcome! Please ensure:
294
- - All tests pass before submitting a PR
295
- - New features include appropriate tests
296
- - Code follows PEP 8 style guidelines
297
- - Documentation is updated as needed
298
-
299
- See [Contributing Guidelines](https://github.com/rolfedh/doc-utils/blob/main/CONTRIBUTING.md) for more details.
300
-
301
- ## License
302
-
303
- This project is licensed under the terms of the [LICENSE](https://github.com/rolfedh/doc-utils/blob/main/LICENSE).