topmark 0.1.0__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.
- topmark-0.1.0/LICENSE +21 -0
- topmark-0.1.0/PKG-INFO +308 -0
- topmark-0.1.0/README.md +262 -0
- topmark-0.1.0/pyproject.toml +247 -0
- topmark-0.1.0/setup.cfg +4 -0
- topmark-0.1.0/src/topmark/__init__.py +14 -0
- topmark-0.1.0/src/topmark/cli/__init__.py +23 -0
- topmark-0.1.0/src/topmark/cli/cli_types.py +299 -0
- topmark-0.1.0/src/topmark/cli/commands/__init__.py +11 -0
- topmark-0.1.0/src/topmark/cli/commands/default.py +295 -0
- topmark-0.1.0/src/topmark/cli/commands/dump_config.py +108 -0
- topmark-0.1.0/src/topmark/cli/commands/filetypes.py +39 -0
- topmark-0.1.0/src/topmark/cli/commands/init_config.py +60 -0
- topmark-0.1.0/src/topmark/cli/commands/show_defaults.py +54 -0
- topmark-0.1.0/src/topmark/cli/commands/version.py +32 -0
- topmark-0.1.0/src/topmark/cli/config_resolver.py +82 -0
- topmark-0.1.0/src/topmark/cli/main.py +464 -0
- topmark-0.1.0/src/topmark/cli/options.py +276 -0
- topmark-0.1.0/src/topmark/cli/utils.py +245 -0
- topmark-0.1.0/src/topmark/config/__init__.py +520 -0
- topmark-0.1.0/src/topmark/config/logging.py +148 -0
- topmark-0.1.0/src/topmark/constants.py +24 -0
- topmark-0.1.0/src/topmark/file_resolver.py +228 -0
- topmark-0.1.0/src/topmark/filetypes/__init__.py +16 -0
- topmark-0.1.0/src/topmark/filetypes/base.py +81 -0
- topmark-0.1.0/src/topmark/filetypes/instances.py +327 -0
- topmark-0.1.0/src/topmark/filetypes/policy.py +44 -0
- topmark-0.1.0/src/topmark/filetypes/registry.py +79 -0
- topmark-0.1.0/src/topmark/pipeline/__init__.py +25 -0
- topmark-0.1.0/src/topmark/pipeline/context.py +363 -0
- topmark-0.1.0/src/topmark/pipeline/contracts.py +22 -0
- topmark-0.1.0/src/topmark/pipeline/pipelines.py +93 -0
- topmark-0.1.0/src/topmark/pipeline/processors/__init__.py +96 -0
- topmark-0.1.0/src/topmark/pipeline/processors/base.py +754 -0
- topmark-0.1.0/src/topmark/pipeline/processors/pound.py +154 -0
- topmark-0.1.0/src/topmark/pipeline/processors/xml.py +278 -0
- topmark-0.1.0/src/topmark/pipeline/runner.py +49 -0
- topmark-0.1.0/src/topmark/pipeline/steps/__init__.py +11 -0
- topmark-0.1.0/src/topmark/pipeline/steps/builder.py +135 -0
- topmark-0.1.0/src/topmark/pipeline/steps/comparer.py +73 -0
- topmark-0.1.0/src/topmark/pipeline/steps/patcher.py +171 -0
- topmark-0.1.0/src/topmark/pipeline/steps/reader.py +173 -0
- topmark-0.1.0/src/topmark/pipeline/steps/renderer.py +64 -0
- topmark-0.1.0/src/topmark/pipeline/steps/resolver.py +103 -0
- topmark-0.1.0/src/topmark/pipeline/steps/scanner.py +146 -0
- topmark-0.1.0/src/topmark/pipeline/steps/updater.py +128 -0
- topmark-0.1.0/src/topmark/py.typed +1 -0
- topmark-0.1.0/src/topmark/rendering/api.py +80 -0
- topmark-0.1.0/src/topmark/rendering/formats.py +26 -0
- topmark-0.1.0/src/topmark/utils/__init__.py +11 -0
- topmark-0.1.0/src/topmark/utils/file.py +42 -0
- topmark-0.1.0/src/topmark.egg-info/PKG-INFO +308 -0
- topmark-0.1.0/src/topmark.egg-info/SOURCES.txt +55 -0
- topmark-0.1.0/src/topmark.egg-info/dependency_links.txt +1 -0
- topmark-0.1.0/src/topmark.egg-info/entry_points.txt +2 -0
- topmark-0.1.0/src/topmark.egg-info/requires.txt +33 -0
- topmark-0.1.0/src/topmark.egg-info/top_level.txt +1 -0
topmark-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Olivier Biot
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
topmark-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: topmark
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A tool to inspect, validate, and manage file headers in diverse codebases
|
|
5
|
+
Author-email: Olivier Biot <olivier.biot@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/shutterfreak/topmark
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: <3.14,>=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: pathspec
|
|
17
|
+
Requires-Dist: tomlkit
|
|
18
|
+
Requires-Dist: toml
|
|
19
|
+
Requires-Dist: yachalk
|
|
20
|
+
Requires-Dist: click
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: ruff; extra == "dev"
|
|
23
|
+
Requires-Dist: pylint; extra == "dev"
|
|
24
|
+
Requires-Dist: mypy; extra == "dev"
|
|
25
|
+
Requires-Dist: pyright; extra == "dev"
|
|
26
|
+
Requires-Dist: mdformat; extra == "dev"
|
|
27
|
+
Requires-Dist: mdformat-tables; extra == "dev"
|
|
28
|
+
Requires-Dist: taplo; extra == "dev"
|
|
29
|
+
Requires-Dist: pip-tools>=7.4; extra == "dev"
|
|
30
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
31
|
+
Requires-Dist: tox>=4.0; extra == "dev"
|
|
32
|
+
Requires-Dist: build; extra == "dev"
|
|
33
|
+
Requires-Dist: twine; extra == "dev"
|
|
34
|
+
Provides-Extra: docs
|
|
35
|
+
Requires-Dist: mkdocs>=1.6; extra == "docs"
|
|
36
|
+
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
|
|
37
|
+
Requires-Dist: mkdocstrings[python]>=0.25; extra == "docs"
|
|
38
|
+
Requires-Dist: pymdown-extensions>=10.8; extra == "docs"
|
|
39
|
+
Provides-Extra: test
|
|
40
|
+
Requires-Dist: pytest; extra == "test"
|
|
41
|
+
Requires-Dist: pytest-xdist; extra == "test"
|
|
42
|
+
Provides-Extra: typing
|
|
43
|
+
Requires-Dist: mypy; extra == "typing"
|
|
44
|
+
Requires-Dist: types-toml; extra == "typing"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
<!--
|
|
48
|
+
topmark:header:start
|
|
49
|
+
|
|
50
|
+
file : README.md
|
|
51
|
+
file_relpath : README.md
|
|
52
|
+
project : TopMark
|
|
53
|
+
license : MIT
|
|
54
|
+
copyright : (c) 2025 Olivier Biot
|
|
55
|
+
|
|
56
|
+
topmark:header:end
|
|
57
|
+
-->
|
|
58
|
+
|
|
59
|
+
# TopMark
|
|
60
|
+
|
|
61
|
+
**TopMark** is a command-line tool to inspect, validate, and manage file headers in diverse
|
|
62
|
+
codebases. It helps maintain consistent header metadata across projects by supporting per-file-type
|
|
63
|
+
header formats, customizable fields, inclusion/exclusion rules, and dry-run safety.
|
|
64
|
+
|
|
65
|
+
## ✨ Features
|
|
66
|
+
|
|
67
|
+
- File header detection, insertion, and replacement
|
|
68
|
+
- Supports multiple file types (Python, Makefile, Markdown, `.env`, ...)
|
|
69
|
+
- Configurable comment styles and header fields
|
|
70
|
+
- Inclusion and exclusion logic (via CLI, globs, stdin, or config)
|
|
71
|
+
- Dry-run by default; safe for CI/CD integration
|
|
72
|
+
- Configuration via `pyproject.toml` or `topmark.toml`
|
|
73
|
+
- Shell completion for enum-based options
|
|
74
|
+
- Colorized CLI output (via `yachalk`)
|
|
75
|
+
- Python ≥3.10
|
|
76
|
+
- Integrated pre-commit hooks for automated checks
|
|
77
|
+
- Formatting and linting support via Makefile targets
|
|
78
|
+
- CI-friendly design for safe automated use
|
|
79
|
+
- Strict static typing with mypy and Pyright, using PEP 604 union syntax
|
|
80
|
+
- Google-style docstrings without redundant type declarations
|
|
81
|
+
- Selective removal
|
|
82
|
+
- Preserves original newline style (LF/CRLF/CR) and BOM
|
|
83
|
+
- Idempotent updates (re-running does not change already-correct files)
|
|
84
|
+
|
|
85
|
+
## 🚀 Installation
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
git clone https://github.com/shutterfreak/topmark.git
|
|
89
|
+
cd topmark
|
|
90
|
+
make setup # creates virtualenv, installs dependencies and tools
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Or install into an existing virtualenv:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install -e .
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Or install the latest release from PyPI:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pip install topmark
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## ⚙️ Usage
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
topmark [OPTIONS] [PATHS]...
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
TopMark uses Click 8.2 and supports shell completions. The base command performs a dry‑run *check*
|
|
112
|
+
by default and applies changes when `--apply` is provided.
|
|
113
|
+
|
|
114
|
+
Logging verbosity is controlled globally:
|
|
115
|
+
|
|
116
|
+
- `-v`, `--verbose`: Increase verbosity (can be repeated)
|
|
117
|
+
- `-q`, `--quiet`: Suppress most output (overrides verbosity)
|
|
118
|
+
|
|
119
|
+
All other options, such as `--stdin`, `--file-type`, and path filters, are specific to individual
|
|
120
|
+
subcommands like `check` or `apply`.
|
|
121
|
+
|
|
122
|
+
### Examples
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Check Python files in the src/ directory
|
|
126
|
+
topmark --file-type python src/
|
|
127
|
+
|
|
128
|
+
# Use exclusion patterns, and compute relative paths from src
|
|
129
|
+
topmark --file-type python --exclude .venv --relative-to src src/
|
|
130
|
+
|
|
131
|
+
# Add one verbosity level to topmark, use exclusion patterns from .gitignore
|
|
132
|
+
topmark -v --file-type python --exclude-from .gitignore src/
|
|
133
|
+
|
|
134
|
+
# Read files from stdin, generate summary
|
|
135
|
+
find . -name "*.py" | topmark --file-type python --summary --stdin
|
|
136
|
+
|
|
137
|
+
# Process all files in a Git repo
|
|
138
|
+
git ls-files -c -o --exclude-standard | sort -u | topmark --stdin --apply
|
|
139
|
+
|
|
140
|
+
# Dump the merged configuration (after loading all applicable config layers)
|
|
141
|
+
topmark dump-config --file-type python --exclude .venv --exclude-from .gitignore
|
|
142
|
+
|
|
143
|
+
# Display the default configuration without any merging
|
|
144
|
+
topmark show-defaults
|
|
145
|
+
|
|
146
|
+
# Output a starter configuration to stdout
|
|
147
|
+
topmark init-config
|
|
148
|
+
|
|
149
|
+
# Show TopMark version
|
|
150
|
+
topmark version
|
|
151
|
+
|
|
152
|
+
# Apply changes to files in-place
|
|
153
|
+
topmark --apply src/
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 📐 Header placement rules
|
|
157
|
+
|
|
158
|
+
TopMark is comment-aware and places the header block according to the file type and its policy.
|
|
159
|
+
|
|
160
|
+
### Pound-style files (e.g., Python, Shell, Ruby, Makefile, YAML, TOML, Dockerfile)
|
|
161
|
+
|
|
162
|
+
Rules:
|
|
163
|
+
|
|
164
|
+
- If a **shebang** is present (e.g., `#!/usr/bin/env python3`), place the header **after** the
|
|
165
|
+
shebang and ensure **exactly one** blank line in-between.
|
|
166
|
+
- If a **coding/encoding line** follows the shebang (PEP 263 style), place the header **after**
|
|
167
|
+
shebang **and** encoding line.
|
|
168
|
+
- Otherwise, place the header **at the top of the file**.
|
|
169
|
+
- Ensure **one trailing blank line** after the header block when the next line is not already blank.
|
|
170
|
+
|
|
171
|
+
Example (Python):
|
|
172
|
+
|
|
173
|
+
```py
|
|
174
|
+
#!/usr/bin/env python3
|
|
175
|
+
|
|
176
|
+
# topmark:header:start
|
|
177
|
+
#
|
|
178
|
+
# file :
|
|
179
|
+
# file_relpath :
|
|
180
|
+
#
|
|
181
|
+
# topmark:header:end
|
|
182
|
+
|
|
183
|
+
print("hello")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### XML-style files (XML, HTML/XHTML, SVG, Vue/Svelte/Markdown via HTML comments)
|
|
187
|
+
|
|
188
|
+
Rules:
|
|
189
|
+
|
|
190
|
+
- If present, place the header **after the XML declaration** and **DOCTYPE**, with **one blank
|
|
191
|
+
line** before the header block.
|
|
192
|
+
- Otherwise, place the header **at the top of the file**.
|
|
193
|
+
- The header uses the file’s native comment syntax; for XML/HTML it’s a comment block wrapper:
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<!--
|
|
197
|
+
topmark:header:start
|
|
198
|
+
|
|
199
|
+
file :
|
|
200
|
+
file_relpath :
|
|
201
|
+
|
|
202
|
+
topmark:header:end
|
|
203
|
+
-->
|
|
204
|
+
|
|
205
|
+
<html>...</html>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### General guarantees
|
|
209
|
+
|
|
210
|
+
- **Newline preservation:** The inserted header uses the same newline style as the file
|
|
211
|
+
(LF/CRLF/CR).
|
|
212
|
+
- **BOM preservation:** If a UTF‑8 BOM is present, it is preserved.
|
|
213
|
+
- **Idempotency:** Re-running TopMark on a file with a correct header makes **no changes**.
|
|
214
|
+
|
|
215
|
+
### Common Options
|
|
216
|
+
|
|
217
|
+
The following options can be used with most commands.
|
|
218
|
+
|
|
219
|
+
| Option | Description |
|
|
220
|
+
| ---------------- | ---------------------------------------- |
|
|
221
|
+
| `--file-type` | Specify file type (python, markdown, …) |
|
|
222
|
+
| `--relative-to` | Set base path for relative header fields |
|
|
223
|
+
| `--include` | Include paths or glob patterns |
|
|
224
|
+
| `--include-from` | Read inclusion patterns from file |
|
|
225
|
+
| `--exclude` | Exclude paths or glob patterns |
|
|
226
|
+
| `--exclude-from` | Read exclusion patterns from file |
|
|
227
|
+
| `--stdin` | Read file paths from stdin |
|
|
228
|
+
| `--apply` | Actually modify files instead of dry-run |
|
|
229
|
+
| `-v, --verbose` | Increase verbosity (can be repeated) |
|
|
230
|
+
| `-q, --quiet` | Suppress most output |
|
|
231
|
+
|
|
232
|
+
### Subcommands
|
|
233
|
+
|
|
234
|
+
| Command | Description |
|
|
235
|
+
| --------------- | -------------------------------------------------- |
|
|
236
|
+
| `dump-config` | Show the resolved configuration in TOML format |
|
|
237
|
+
| `filetypes` | List supported file types and their comment styles |
|
|
238
|
+
| `version` | Print TopMark version |
|
|
239
|
+
| `show-defaults` | Show default config (without merging) |
|
|
240
|
+
| `init-config` | Output a starter configuration file |
|
|
241
|
+
|
|
242
|
+
## 🧩 Supported file types
|
|
243
|
+
|
|
244
|
+
| Processor | File types (examples) |
|
|
245
|
+
| -------------------- | -------------------------------------------------------------------------- |
|
|
246
|
+
| PoundHeaderProcessor | python, shell, ruby, r, julia, perl, makefile, dockerfile, yaml, toml, env |
|
|
247
|
+
| XmlHeaderProcessor | xml, xhtml, html, svg, xsl/xslt, vue, svelte, markdown |
|
|
248
|
+
|
|
249
|
+
## 🛠 Configuration
|
|
250
|
+
|
|
251
|
+
You can specify one or more `--config` files, or rely on local fallback resolution:
|
|
252
|
+
|
|
253
|
+
- `topmark.toml` in the working directory
|
|
254
|
+
- `pyproject.toml` using the `[tool.topmark]` table
|
|
255
|
+
|
|
256
|
+
TopMark reads configuration from one or more TOML files. Configuration is merged from:
|
|
257
|
+
|
|
258
|
+
1. Built-in defaults
|
|
259
|
+
2. Local project config (if not disabled via `--no-config`)
|
|
260
|
+
3. Additional files via `--config`
|
|
261
|
+
4. CLI overrides
|
|
262
|
+
|
|
263
|
+
Example configuration snippet (`topmark.toml`):
|
|
264
|
+
|
|
265
|
+
```toml
|
|
266
|
+
[fields]
|
|
267
|
+
project = "TopMark"
|
|
268
|
+
license = "MIT"
|
|
269
|
+
copyright = "(c) 2025 Olivier Biot"
|
|
270
|
+
|
|
271
|
+
[header]
|
|
272
|
+
fields = [ "file", "file_relpath", "project", "license", "copyright",]
|
|
273
|
+
|
|
274
|
+
[formatting]
|
|
275
|
+
align_fields = true
|
|
276
|
+
raw_header = false
|
|
277
|
+
|
|
278
|
+
[files]
|
|
279
|
+
file_types = [ "python", "markdown", "env" ]
|
|
280
|
+
include = []
|
|
281
|
+
include_from = []
|
|
282
|
+
exclude = []
|
|
283
|
+
exclude_from = [ ".gitignore" ]
|
|
284
|
+
relative_to = "."
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Notes
|
|
288
|
+
|
|
289
|
+
- `formatting.align_fields = true` vertically aligns the field names within the rendered header
|
|
290
|
+
lines for readability.
|
|
291
|
+
- File-type specific behavior (shebang handling, XML prolog, blank line policies) is driven by
|
|
292
|
+
internal **FileTypeHeaderPolicy** defaults and can be extended to new types.
|
|
293
|
+
|
|
294
|
+
The `EnumParam` class enables shell completion for enum-based CLI options.
|
|
295
|
+
|
|
296
|
+
## 🧪 Development Setup
|
|
297
|
+
|
|
298
|
+
For development setup and contribution guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
299
|
+
|
|
300
|
+
To verify compatibility across supported Python versions (3.10–3.13), use `tox` to run tests and
|
|
301
|
+
type checks in each environment.
|
|
302
|
+
|
|
303
|
+
## 📄 License
|
|
304
|
+
|
|
305
|
+
MIT License © 2025 Olivier Biot
|
|
306
|
+
|
|
307
|
+
Markdown formatting is handled by `mdformat` with the `mdformat-tables` plugin, and configuration is
|
|
308
|
+
read from `pyproject.toml`.
|
topmark-0.1.0/README.md
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
topmark:header:start
|
|
3
|
+
|
|
4
|
+
file : README.md
|
|
5
|
+
file_relpath : README.md
|
|
6
|
+
project : TopMark
|
|
7
|
+
license : MIT
|
|
8
|
+
copyright : (c) 2025 Olivier Biot
|
|
9
|
+
|
|
10
|
+
topmark:header:end
|
|
11
|
+
-->
|
|
12
|
+
|
|
13
|
+
# TopMark
|
|
14
|
+
|
|
15
|
+
**TopMark** is a command-line tool to inspect, validate, and manage file headers in diverse
|
|
16
|
+
codebases. It helps maintain consistent header metadata across projects by supporting per-file-type
|
|
17
|
+
header formats, customizable fields, inclusion/exclusion rules, and dry-run safety.
|
|
18
|
+
|
|
19
|
+
## ✨ Features
|
|
20
|
+
|
|
21
|
+
- File header detection, insertion, and replacement
|
|
22
|
+
- Supports multiple file types (Python, Makefile, Markdown, `.env`, ...)
|
|
23
|
+
- Configurable comment styles and header fields
|
|
24
|
+
- Inclusion and exclusion logic (via CLI, globs, stdin, or config)
|
|
25
|
+
- Dry-run by default; safe for CI/CD integration
|
|
26
|
+
- Configuration via `pyproject.toml` or `topmark.toml`
|
|
27
|
+
- Shell completion for enum-based options
|
|
28
|
+
- Colorized CLI output (via `yachalk`)
|
|
29
|
+
- Python ≥3.10
|
|
30
|
+
- Integrated pre-commit hooks for automated checks
|
|
31
|
+
- Formatting and linting support via Makefile targets
|
|
32
|
+
- CI-friendly design for safe automated use
|
|
33
|
+
- Strict static typing with mypy and Pyright, using PEP 604 union syntax
|
|
34
|
+
- Google-style docstrings without redundant type declarations
|
|
35
|
+
- Selective removal
|
|
36
|
+
- Preserves original newline style (LF/CRLF/CR) and BOM
|
|
37
|
+
- Idempotent updates (re-running does not change already-correct files)
|
|
38
|
+
|
|
39
|
+
## 🚀 Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/shutterfreak/topmark.git
|
|
43
|
+
cd topmark
|
|
44
|
+
make setup # creates virtualenv, installs dependencies and tools
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or install into an existing virtualenv:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install -e .
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or install the latest release from PyPI:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install topmark
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## ⚙️ Usage
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
topmark [OPTIONS] [PATHS]...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
TopMark uses Click 8.2 and supports shell completions. The base command performs a dry‑run *check*
|
|
66
|
+
by default and applies changes when `--apply` is provided.
|
|
67
|
+
|
|
68
|
+
Logging verbosity is controlled globally:
|
|
69
|
+
|
|
70
|
+
- `-v`, `--verbose`: Increase verbosity (can be repeated)
|
|
71
|
+
- `-q`, `--quiet`: Suppress most output (overrides verbosity)
|
|
72
|
+
|
|
73
|
+
All other options, such as `--stdin`, `--file-type`, and path filters, are specific to individual
|
|
74
|
+
subcommands like `check` or `apply`.
|
|
75
|
+
|
|
76
|
+
### Examples
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Check Python files in the src/ directory
|
|
80
|
+
topmark --file-type python src/
|
|
81
|
+
|
|
82
|
+
# Use exclusion patterns, and compute relative paths from src
|
|
83
|
+
topmark --file-type python --exclude .venv --relative-to src src/
|
|
84
|
+
|
|
85
|
+
# Add one verbosity level to topmark, use exclusion patterns from .gitignore
|
|
86
|
+
topmark -v --file-type python --exclude-from .gitignore src/
|
|
87
|
+
|
|
88
|
+
# Read files from stdin, generate summary
|
|
89
|
+
find . -name "*.py" | topmark --file-type python --summary --stdin
|
|
90
|
+
|
|
91
|
+
# Process all files in a Git repo
|
|
92
|
+
git ls-files -c -o --exclude-standard | sort -u | topmark --stdin --apply
|
|
93
|
+
|
|
94
|
+
# Dump the merged configuration (after loading all applicable config layers)
|
|
95
|
+
topmark dump-config --file-type python --exclude .venv --exclude-from .gitignore
|
|
96
|
+
|
|
97
|
+
# Display the default configuration without any merging
|
|
98
|
+
topmark show-defaults
|
|
99
|
+
|
|
100
|
+
# Output a starter configuration to stdout
|
|
101
|
+
topmark init-config
|
|
102
|
+
|
|
103
|
+
# Show TopMark version
|
|
104
|
+
topmark version
|
|
105
|
+
|
|
106
|
+
# Apply changes to files in-place
|
|
107
|
+
topmark --apply src/
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 📐 Header placement rules
|
|
111
|
+
|
|
112
|
+
TopMark is comment-aware and places the header block according to the file type and its policy.
|
|
113
|
+
|
|
114
|
+
### Pound-style files (e.g., Python, Shell, Ruby, Makefile, YAML, TOML, Dockerfile)
|
|
115
|
+
|
|
116
|
+
Rules:
|
|
117
|
+
|
|
118
|
+
- If a **shebang** is present (e.g., `#!/usr/bin/env python3`), place the header **after** the
|
|
119
|
+
shebang and ensure **exactly one** blank line in-between.
|
|
120
|
+
- If a **coding/encoding line** follows the shebang (PEP 263 style), place the header **after**
|
|
121
|
+
shebang **and** encoding line.
|
|
122
|
+
- Otherwise, place the header **at the top of the file**.
|
|
123
|
+
- Ensure **one trailing blank line** after the header block when the next line is not already blank.
|
|
124
|
+
|
|
125
|
+
Example (Python):
|
|
126
|
+
|
|
127
|
+
```py
|
|
128
|
+
#!/usr/bin/env python3
|
|
129
|
+
|
|
130
|
+
# topmark:header:start
|
|
131
|
+
#
|
|
132
|
+
# file :
|
|
133
|
+
# file_relpath :
|
|
134
|
+
#
|
|
135
|
+
# topmark:header:end
|
|
136
|
+
|
|
137
|
+
print("hello")
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### XML-style files (XML, HTML/XHTML, SVG, Vue/Svelte/Markdown via HTML comments)
|
|
141
|
+
|
|
142
|
+
Rules:
|
|
143
|
+
|
|
144
|
+
- If present, place the header **after the XML declaration** and **DOCTYPE**, with **one blank
|
|
145
|
+
line** before the header block.
|
|
146
|
+
- Otherwise, place the header **at the top of the file**.
|
|
147
|
+
- The header uses the file’s native comment syntax; for XML/HTML it’s a comment block wrapper:
|
|
148
|
+
|
|
149
|
+
```html
|
|
150
|
+
<!--
|
|
151
|
+
topmark:header:start
|
|
152
|
+
|
|
153
|
+
file :
|
|
154
|
+
file_relpath :
|
|
155
|
+
|
|
156
|
+
topmark:header:end
|
|
157
|
+
-->
|
|
158
|
+
|
|
159
|
+
<html>...</html>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### General guarantees
|
|
163
|
+
|
|
164
|
+
- **Newline preservation:** The inserted header uses the same newline style as the file
|
|
165
|
+
(LF/CRLF/CR).
|
|
166
|
+
- **BOM preservation:** If a UTF‑8 BOM is present, it is preserved.
|
|
167
|
+
- **Idempotency:** Re-running TopMark on a file with a correct header makes **no changes**.
|
|
168
|
+
|
|
169
|
+
### Common Options
|
|
170
|
+
|
|
171
|
+
The following options can be used with most commands.
|
|
172
|
+
|
|
173
|
+
| Option | Description |
|
|
174
|
+
| ---------------- | ---------------------------------------- |
|
|
175
|
+
| `--file-type` | Specify file type (python, markdown, …) |
|
|
176
|
+
| `--relative-to` | Set base path for relative header fields |
|
|
177
|
+
| `--include` | Include paths or glob patterns |
|
|
178
|
+
| `--include-from` | Read inclusion patterns from file |
|
|
179
|
+
| `--exclude` | Exclude paths or glob patterns |
|
|
180
|
+
| `--exclude-from` | Read exclusion patterns from file |
|
|
181
|
+
| `--stdin` | Read file paths from stdin |
|
|
182
|
+
| `--apply` | Actually modify files instead of dry-run |
|
|
183
|
+
| `-v, --verbose` | Increase verbosity (can be repeated) |
|
|
184
|
+
| `-q, --quiet` | Suppress most output |
|
|
185
|
+
|
|
186
|
+
### Subcommands
|
|
187
|
+
|
|
188
|
+
| Command | Description |
|
|
189
|
+
| --------------- | -------------------------------------------------- |
|
|
190
|
+
| `dump-config` | Show the resolved configuration in TOML format |
|
|
191
|
+
| `filetypes` | List supported file types and their comment styles |
|
|
192
|
+
| `version` | Print TopMark version |
|
|
193
|
+
| `show-defaults` | Show default config (without merging) |
|
|
194
|
+
| `init-config` | Output a starter configuration file |
|
|
195
|
+
|
|
196
|
+
## 🧩 Supported file types
|
|
197
|
+
|
|
198
|
+
| Processor | File types (examples) |
|
|
199
|
+
| -------------------- | -------------------------------------------------------------------------- |
|
|
200
|
+
| PoundHeaderProcessor | python, shell, ruby, r, julia, perl, makefile, dockerfile, yaml, toml, env |
|
|
201
|
+
| XmlHeaderProcessor | xml, xhtml, html, svg, xsl/xslt, vue, svelte, markdown |
|
|
202
|
+
|
|
203
|
+
## 🛠 Configuration
|
|
204
|
+
|
|
205
|
+
You can specify one or more `--config` files, or rely on local fallback resolution:
|
|
206
|
+
|
|
207
|
+
- `topmark.toml` in the working directory
|
|
208
|
+
- `pyproject.toml` using the `[tool.topmark]` table
|
|
209
|
+
|
|
210
|
+
TopMark reads configuration from one or more TOML files. Configuration is merged from:
|
|
211
|
+
|
|
212
|
+
1. Built-in defaults
|
|
213
|
+
2. Local project config (if not disabled via `--no-config`)
|
|
214
|
+
3. Additional files via `--config`
|
|
215
|
+
4. CLI overrides
|
|
216
|
+
|
|
217
|
+
Example configuration snippet (`topmark.toml`):
|
|
218
|
+
|
|
219
|
+
```toml
|
|
220
|
+
[fields]
|
|
221
|
+
project = "TopMark"
|
|
222
|
+
license = "MIT"
|
|
223
|
+
copyright = "(c) 2025 Olivier Biot"
|
|
224
|
+
|
|
225
|
+
[header]
|
|
226
|
+
fields = [ "file", "file_relpath", "project", "license", "copyright",]
|
|
227
|
+
|
|
228
|
+
[formatting]
|
|
229
|
+
align_fields = true
|
|
230
|
+
raw_header = false
|
|
231
|
+
|
|
232
|
+
[files]
|
|
233
|
+
file_types = [ "python", "markdown", "env" ]
|
|
234
|
+
include = []
|
|
235
|
+
include_from = []
|
|
236
|
+
exclude = []
|
|
237
|
+
exclude_from = [ ".gitignore" ]
|
|
238
|
+
relative_to = "."
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Notes
|
|
242
|
+
|
|
243
|
+
- `formatting.align_fields = true` vertically aligns the field names within the rendered header
|
|
244
|
+
lines for readability.
|
|
245
|
+
- File-type specific behavior (shebang handling, XML prolog, blank line policies) is driven by
|
|
246
|
+
internal **FileTypeHeaderPolicy** defaults and can be extended to new types.
|
|
247
|
+
|
|
248
|
+
The `EnumParam` class enables shell completion for enum-based CLI options.
|
|
249
|
+
|
|
250
|
+
## 🧪 Development Setup
|
|
251
|
+
|
|
252
|
+
For development setup and contribution guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
253
|
+
|
|
254
|
+
To verify compatibility across supported Python versions (3.10–3.13), use `tox` to run tests and
|
|
255
|
+
type checks in each environment.
|
|
256
|
+
|
|
257
|
+
## 📄 License
|
|
258
|
+
|
|
259
|
+
MIT License © 2025 Olivier Biot
|
|
260
|
+
|
|
261
|
+
Markdown formatting is handled by `mdformat` with the `mdformat-tables` plugin, and configuration is
|
|
262
|
+
read from `pyproject.toml`.
|