refcheck 0.3.0__tar.gz → 0.4.2__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.
- refcheck-0.4.2/PKG-INFO +152 -0
- refcheck-0.4.2/README.md +132 -0
- refcheck-0.4.2/pyproject.toml +112 -0
- refcheck-0.4.2/refcheck/cli.py +75 -0
- {refcheck-0.3.0 → refcheck-0.4.2}/refcheck/log_conf.py +1 -1
- {refcheck-0.3.0 → refcheck-0.4.2}/refcheck/main.py +34 -21
- refcheck-0.4.2/refcheck/parsers.py +230 -0
- {refcheck-0.3.0 → refcheck-0.4.2}/refcheck/settings.py +20 -10
- {refcheck-0.3.0 → refcheck-0.4.2}/refcheck/utils.py +8 -4
- {refcheck-0.3.0 → refcheck-0.4.2}/refcheck/validators.py +30 -9
- refcheck-0.3.0/PKG-INFO +0 -167
- refcheck-0.3.0/README.md +0 -150
- refcheck-0.3.0/pyproject.toml +0 -33
- refcheck-0.3.0/refcheck/parsers.py +0 -233
- {refcheck-0.3.0 → refcheck-0.4.2}/LICENSE +0 -0
- {refcheck-0.3.0 → refcheck-0.4.2}/refcheck/__init__.py +0 -0
refcheck-0.4.2/PKG-INFO
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: refcheck
|
|
3
|
+
Version: 0.4.2
|
|
4
|
+
Summary: Tool for finding broken references and links in Markdown files.
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Keywords: markdown,links,references,validator,cli
|
|
7
|
+
Author: Sebastian Flum
|
|
8
|
+
Author-email: sebastian.flum.dev@gmail.com
|
|
9
|
+
Requires-Python: >=3.10,<4.0
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
17
|
+
Project-URL: Repository, https://github.com/flumi3/markdown-refcheck
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# RefCheck
|
|
21
|
+
|
|
22
|
+
[](https://pepy.tech/projects/refcheck)
|
|
23
|
+

|
|
24
|
+
[](https://opensource.org/licenses/MIT)
|
|
25
|
+
[](https://github.com/flumi3/markdown-refcheck/actions/workflows/ci-cd.yml)
|
|
26
|
+
|
|
27
|
+
RefCheck is a simple tool for finding broken references and links in Markdown files.
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
usage: refcheck [OPTIONS] [PATH ...]
|
|
31
|
+
|
|
32
|
+
positional arguments:
|
|
33
|
+
PATH Markdown files or directories to check
|
|
34
|
+
|
|
35
|
+
options:
|
|
36
|
+
-h, --help show this help message and exit
|
|
37
|
+
-e, --exclude [ ...] Files or directories to exclude
|
|
38
|
+
-cm, --check-remote Check remote references (HTTP/HTTPS links)
|
|
39
|
+
-nc, --no-color Turn off colored output
|
|
40
|
+
-v, --verbose Enable verbose output
|
|
41
|
+
--allow-absolute Allow absolute path references like [ref](/path/to/file.md)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
<!-- [](https://codecov.io/gh/flumi3/markdown-refcheck) -->
|
|
45
|
+
|
|
46
|
+
## Features
|
|
47
|
+
|
|
48
|
+
- 🔍 **Comprehensive Reference Detection** - Find and validate various reference patterns in Markdown files
|
|
49
|
+
- ❌ **Broken Link Highlighting** - Quickly identify broken references with clear error messages
|
|
50
|
+
- 📁 **File Path Validation** - Support for both absolute and relative file paths to any file type
|
|
51
|
+
- 🌐 **Remote URL Checking** - Validate external HTTP/HTTPS links (optional with `--check-remote`)
|
|
52
|
+
- 🎯 **Header Reference Validation** - Verify links to specific sections within Markdown files
|
|
53
|
+
- 🛠️ **User-Friendly CLI** - Simple and intuitive command-line interface
|
|
54
|
+
- ⚙️ **CI/CD Ready** - Perfect for automated quality checks in your documentation workflows
|
|
55
|
+
- 🎨 **Colored Output** - Clear, color-coded results for easy scanning (disable with `--no-color`)
|
|
56
|
+
- 📊 **Detailed Reporting** - Summary statistics and line-by-line reference validation
|
|
57
|
+
- 🚀 **Pre-commit Integration** - Available as a pre-commit hook for automated validation
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
RefCheck is available on PyPI:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install refcheck
|
|
65
|
+
|
|
66
|
+
# or using pipx
|
|
67
|
+
pipx install refcheck
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Examples
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
$ refcheck README.md
|
|
74
|
+
|
|
75
|
+
[+] 1 Markdown files to check.
|
|
76
|
+
- README.md
|
|
77
|
+
|
|
78
|
+
[+] FILE: README.md...
|
|
79
|
+
README.md:3: #introduction - OK
|
|
80
|
+
README.md:5: #installation - OK
|
|
81
|
+
README.md:6: #getting-started - OK
|
|
82
|
+
|
|
83
|
+
Reference check complete.
|
|
84
|
+
|
|
85
|
+
============================| Summary |=============================
|
|
86
|
+
🎉 No broken references!
|
|
87
|
+
====================================================================
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
$ refcheck . --check-remote
|
|
92
|
+
|
|
93
|
+
[+] Searching for markdown files in C:\Users\flumi3\github\refcheck ...
|
|
94
|
+
|
|
95
|
+
[+] 2 Markdown files to check.
|
|
96
|
+
- tests\sample_markdown.md
|
|
97
|
+
- docs\Understanding-Markdown-References.md
|
|
98
|
+
|
|
99
|
+
[+] FILE: tests\sample_markdown.md...
|
|
100
|
+
tests\sample_markdown.md:39: /img/image.png - BROKEN
|
|
101
|
+
tests\sample_markdown.md:52: https://www.openai.com/logo.png - BROKEN
|
|
102
|
+
|
|
103
|
+
[+] FILE: docs\Understanding-Markdown-References.md...
|
|
104
|
+
docs\Understanding-Markdown-References.md:42: #local-file-references - OK
|
|
105
|
+
|
|
106
|
+
Reference check complete.
|
|
107
|
+
|
|
108
|
+
============================| Summary |=============================
|
|
109
|
+
[!] 2 broken references found:
|
|
110
|
+
tests\sample_markdown.md:39: /img/image.png
|
|
111
|
+
tests\sample_markdown.md:52: https://www.openai.com/logo.png
|
|
112
|
+
====================================================================
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Pre-commit Hook
|
|
116
|
+
|
|
117
|
+
RefCheck is also available as pre-commit hook!
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
- repo: https://github.com/flumi3/refcheck
|
|
121
|
+
rev: v0.4.2
|
|
122
|
+
hooks:
|
|
123
|
+
- id: refcheck
|
|
124
|
+
args: ["docs/", "-e", "docs/filetoexclude.md"] # e.g. scan the docs/ folder and exclude a file
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
For more advanced configuration options, see the [Integration Guide](docs/Integration-Guide.md).
|
|
128
|
+
|
|
129
|
+
## Contributing
|
|
130
|
+
|
|
131
|
+
Contributions are welcome!
|
|
132
|
+
|
|
133
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for:
|
|
134
|
+
|
|
135
|
+
- Development setup instructions
|
|
136
|
+
- Commit message conventions
|
|
137
|
+
- Code quality standards
|
|
138
|
+
- Testing requirements
|
|
139
|
+
- Pull request guidelines
|
|
140
|
+
|
|
141
|
+
## Documentation
|
|
142
|
+
|
|
143
|
+
For more detailed information, check out the documentation:
|
|
144
|
+
|
|
145
|
+
- [CLI Reference](docs/CLI-Reference.md) - Complete command-line options and usage
|
|
146
|
+
- [Integration Guide](docs/Integration-Guide.md) - CI/CD and workflow integration
|
|
147
|
+
- [Examples](docs/Examples.md) - Real-world usage examples
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
152
|
+
|
refcheck-0.4.2/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# RefCheck
|
|
2
|
+
|
|
3
|
+
[](https://pepy.tech/projects/refcheck)
|
|
4
|
+

|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://github.com/flumi3/markdown-refcheck/actions/workflows/ci-cd.yml)
|
|
7
|
+
|
|
8
|
+
RefCheck is a simple tool for finding broken references and links in Markdown files.
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
usage: refcheck [OPTIONS] [PATH ...]
|
|
12
|
+
|
|
13
|
+
positional arguments:
|
|
14
|
+
PATH Markdown files or directories to check
|
|
15
|
+
|
|
16
|
+
options:
|
|
17
|
+
-h, --help show this help message and exit
|
|
18
|
+
-e, --exclude [ ...] Files or directories to exclude
|
|
19
|
+
-cm, --check-remote Check remote references (HTTP/HTTPS links)
|
|
20
|
+
-nc, --no-color Turn off colored output
|
|
21
|
+
-v, --verbose Enable verbose output
|
|
22
|
+
--allow-absolute Allow absolute path references like [ref](/path/to/file.md)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
<!-- [](https://codecov.io/gh/flumi3/markdown-refcheck) -->
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- 🔍 **Comprehensive Reference Detection** - Find and validate various reference patterns in Markdown files
|
|
30
|
+
- ❌ **Broken Link Highlighting** - Quickly identify broken references with clear error messages
|
|
31
|
+
- 📁 **File Path Validation** - Support for both absolute and relative file paths to any file type
|
|
32
|
+
- 🌐 **Remote URL Checking** - Validate external HTTP/HTTPS links (optional with `--check-remote`)
|
|
33
|
+
- 🎯 **Header Reference Validation** - Verify links to specific sections within Markdown files
|
|
34
|
+
- 🛠️ **User-Friendly CLI** - Simple and intuitive command-line interface
|
|
35
|
+
- ⚙️ **CI/CD Ready** - Perfect for automated quality checks in your documentation workflows
|
|
36
|
+
- 🎨 **Colored Output** - Clear, color-coded results for easy scanning (disable with `--no-color`)
|
|
37
|
+
- 📊 **Detailed Reporting** - Summary statistics and line-by-line reference validation
|
|
38
|
+
- 🚀 **Pre-commit Integration** - Available as a pre-commit hook for automated validation
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
RefCheck is available on PyPI:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install refcheck
|
|
46
|
+
|
|
47
|
+
# or using pipx
|
|
48
|
+
pipx install refcheck
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Examples
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
$ refcheck README.md
|
|
55
|
+
|
|
56
|
+
[+] 1 Markdown files to check.
|
|
57
|
+
- README.md
|
|
58
|
+
|
|
59
|
+
[+] FILE: README.md...
|
|
60
|
+
README.md:3: #introduction - OK
|
|
61
|
+
README.md:5: #installation - OK
|
|
62
|
+
README.md:6: #getting-started - OK
|
|
63
|
+
|
|
64
|
+
Reference check complete.
|
|
65
|
+
|
|
66
|
+
============================| Summary |=============================
|
|
67
|
+
🎉 No broken references!
|
|
68
|
+
====================================================================
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
$ refcheck . --check-remote
|
|
73
|
+
|
|
74
|
+
[+] Searching for markdown files in C:\Users\flumi3\github\refcheck ...
|
|
75
|
+
|
|
76
|
+
[+] 2 Markdown files to check.
|
|
77
|
+
- tests\sample_markdown.md
|
|
78
|
+
- docs\Understanding-Markdown-References.md
|
|
79
|
+
|
|
80
|
+
[+] FILE: tests\sample_markdown.md...
|
|
81
|
+
tests\sample_markdown.md:39: /img/image.png - BROKEN
|
|
82
|
+
tests\sample_markdown.md:52: https://www.openai.com/logo.png - BROKEN
|
|
83
|
+
|
|
84
|
+
[+] FILE: docs\Understanding-Markdown-References.md...
|
|
85
|
+
docs\Understanding-Markdown-References.md:42: #local-file-references - OK
|
|
86
|
+
|
|
87
|
+
Reference check complete.
|
|
88
|
+
|
|
89
|
+
============================| Summary |=============================
|
|
90
|
+
[!] 2 broken references found:
|
|
91
|
+
tests\sample_markdown.md:39: /img/image.png
|
|
92
|
+
tests\sample_markdown.md:52: https://www.openai.com/logo.png
|
|
93
|
+
====================================================================
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Pre-commit Hook
|
|
97
|
+
|
|
98
|
+
RefCheck is also available as pre-commit hook!
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
- repo: https://github.com/flumi3/refcheck
|
|
102
|
+
rev: v0.4.2
|
|
103
|
+
hooks:
|
|
104
|
+
- id: refcheck
|
|
105
|
+
args: ["docs/", "-e", "docs/filetoexclude.md"] # e.g. scan the docs/ folder and exclude a file
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For more advanced configuration options, see the [Integration Guide](docs/Integration-Guide.md).
|
|
109
|
+
|
|
110
|
+
## Contributing
|
|
111
|
+
|
|
112
|
+
Contributions are welcome!
|
|
113
|
+
|
|
114
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for:
|
|
115
|
+
|
|
116
|
+
- Development setup instructions
|
|
117
|
+
- Commit message conventions
|
|
118
|
+
- Code quality standards
|
|
119
|
+
- Testing requirements
|
|
120
|
+
- Pull request guidelines
|
|
121
|
+
|
|
122
|
+
## Documentation
|
|
123
|
+
|
|
124
|
+
For more detailed information, check out the documentation:
|
|
125
|
+
|
|
126
|
+
- [CLI Reference](docs/CLI-Reference.md) - Complete command-line options and usage
|
|
127
|
+
- [Integration Guide](docs/Integration-Guide.md) - CI/CD and workflow integration
|
|
128
|
+
- [Examples](docs/Examples.md) - Real-world usage examples
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "refcheck"
|
|
3
|
+
version = "0.4.2"
|
|
4
|
+
description = "Tool for finding broken references and links in Markdown files."
|
|
5
|
+
authors = ["Sebastian Flum <sebastian.flum.dev@gmail.com>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
repository = "https://github.com/flumi3/markdown-refcheck"
|
|
8
|
+
keywords = ["markdown", "links", "references", "validator", "cli"]
|
|
9
|
+
|
|
10
|
+
[tool.poetry.dependencies]
|
|
11
|
+
python = "^3.10"
|
|
12
|
+
requests = "^2.32.3"
|
|
13
|
+
|
|
14
|
+
[tool.poetry.group.dev.dependencies]
|
|
15
|
+
pytest = "^8.3.4"
|
|
16
|
+
pytest-cov = "^6.0.0"
|
|
17
|
+
commitizen = "^4.2.2"
|
|
18
|
+
python-semantic-release = ">=9.20,<11.0"
|
|
19
|
+
ruff = ">=0.9.7,<0.12.0"
|
|
20
|
+
mypy = "^1.13.0"
|
|
21
|
+
types-requests = "^2.32.0"
|
|
22
|
+
vulture = "^2.13"
|
|
23
|
+
deptry = "^0.22.0"
|
|
24
|
+
pre-commit = "^4.0.0"
|
|
25
|
+
|
|
26
|
+
[tool.poetry.scripts]
|
|
27
|
+
refcheck = "refcheck.main:main"
|
|
28
|
+
|
|
29
|
+
[tool.ruff]
|
|
30
|
+
line-length = 100
|
|
31
|
+
|
|
32
|
+
[tool.semantic_release]
|
|
33
|
+
commit_parser = "angular"
|
|
34
|
+
branch = "main"
|
|
35
|
+
major_on_zero = true
|
|
36
|
+
build_command = "pip install poetry && python -m poetry build"
|
|
37
|
+
version_toml = ["pyproject.toml:tool.poetry.version"]
|
|
38
|
+
version_variables = [
|
|
39
|
+
"pyproject.toml:tool.poetry.version",
|
|
40
|
+
"README.md:rev:tf",
|
|
41
|
+
"docs/CLI-Reference.md:rev:tf",
|
|
42
|
+
"docs/Development-Guide.md:rev:tf",
|
|
43
|
+
"docs/Examples.md:rev:tf",
|
|
44
|
+
"docs/Integration-Guide.md:rev:tf",
|
|
45
|
+
"CONTRIBUTING.md:rev:tf",
|
|
46
|
+
]
|
|
47
|
+
tag_format = "v{version}"
|
|
48
|
+
|
|
49
|
+
[tool.commitizen]
|
|
50
|
+
name = "cz_conventional_commits"
|
|
51
|
+
version = "0.3.0"
|
|
52
|
+
tag_format = "v$version"
|
|
53
|
+
update_changelog_on_bump = true
|
|
54
|
+
version_files = [
|
|
55
|
+
"pyproject.toml:tool.poetry.version",
|
|
56
|
+
"pyproject.toml:tool.commitizen.version"
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[tool.vulture]
|
|
60
|
+
min_confidence = 80
|
|
61
|
+
exclude = ["*/__pycache__/*"]
|
|
62
|
+
ignore_names = [
|
|
63
|
+
"_format_action_invocation",
|
|
64
|
+
"RAW_LINK_PATTERN",
|
|
65
|
+
"HTML_LINK_PATTERN",
|
|
66
|
+
"HTML_IMAGE_PATTERN",
|
|
67
|
+
"_process_inline_links",
|
|
68
|
+
"print_green_background",
|
|
69
|
+
"print_red_background",
|
|
70
|
+
"is_valid_remote_reference"
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[tool.deptry.per_rule_ignores]
|
|
74
|
+
DEP002 = ["mypy", "vulture", "deptry"]
|
|
75
|
+
|
|
76
|
+
[tool.mypy]
|
|
77
|
+
python_version = "3.10"
|
|
78
|
+
warn_return_any = true
|
|
79
|
+
warn_unused_configs = true
|
|
80
|
+
disallow_untyped_defs = false
|
|
81
|
+
|
|
82
|
+
[tool.coverage.run]
|
|
83
|
+
source = ["refcheck"]
|
|
84
|
+
omit = [
|
|
85
|
+
"*/tests/*",
|
|
86
|
+
"*/__pycache__/*",
|
|
87
|
+
"*/test_*",
|
|
88
|
+
"*/__init__.py",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
[tool.coverage.report]
|
|
92
|
+
fail_under = 80
|
|
93
|
+
precision = 2
|
|
94
|
+
show_missing = true
|
|
95
|
+
skip_covered = false
|
|
96
|
+
exclude_lines = [
|
|
97
|
+
"pragma: no cover",
|
|
98
|
+
"def __repr__",
|
|
99
|
+
"raise AssertionError",
|
|
100
|
+
"raise NotImplementedError",
|
|
101
|
+
"if __name__ == .__main__.:",
|
|
102
|
+
"if TYPE_CHECKING:",
|
|
103
|
+
"class .*\\bProtocol\\):",
|
|
104
|
+
"@(abc\\.)?abstractmethod",
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
[tool.coverage.html]
|
|
108
|
+
directory = "htmlcov"
|
|
109
|
+
|
|
110
|
+
[build-system]
|
|
111
|
+
requires = ["poetry-core"]
|
|
112
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
from argparse import Namespace
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CustomFormatter(argparse.HelpFormatter):
|
|
7
|
+
def _format_action_invocation(self, action):
|
|
8
|
+
if not action.option_strings:
|
|
9
|
+
(metavar,) = self._metavar_formatter(action, action.dest)(1)
|
|
10
|
+
return metavar
|
|
11
|
+
else:
|
|
12
|
+
parts = []
|
|
13
|
+
# if the Optional doesn't take a value, format is:
|
|
14
|
+
# -s, --long
|
|
15
|
+
if action.nargs == 0:
|
|
16
|
+
parts.extend(action.option_strings)
|
|
17
|
+
|
|
18
|
+
# if the Optional takes a value, format is:
|
|
19
|
+
# -s ARGS, --long ARGS
|
|
20
|
+
# change to
|
|
21
|
+
# -s, --long ARGS
|
|
22
|
+
else:
|
|
23
|
+
default = action.dest.upper()
|
|
24
|
+
args_string = self._format_args(action, default)
|
|
25
|
+
for option_string in action.option_strings:
|
|
26
|
+
# parts.append('%s %s' % (option_string, args_string))
|
|
27
|
+
parts.append("%s" % option_string)
|
|
28
|
+
parts[-1] += " %s" % args_string
|
|
29
|
+
return ", ".join(parts)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_command_line_arguments() -> Namespace:
|
|
33
|
+
"""Setup command line argument parser."""
|
|
34
|
+
parser = argparse.ArgumentParser(
|
|
35
|
+
prog="refcheck",
|
|
36
|
+
usage="refcheck [OPTIONS] [PATH ...]",
|
|
37
|
+
formatter_class=CustomFormatter,
|
|
38
|
+
) # type: ignore
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"paths",
|
|
41
|
+
metavar="PATH",
|
|
42
|
+
type=str,
|
|
43
|
+
nargs="*",
|
|
44
|
+
help="Markdown files or directories to check",
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"-e",
|
|
48
|
+
"--exclude",
|
|
49
|
+
metavar="",
|
|
50
|
+
type=str,
|
|
51
|
+
nargs="*",
|
|
52
|
+
default=[],
|
|
53
|
+
help="Files or directories to exclude",
|
|
54
|
+
) # type: ignore
|
|
55
|
+
parser.add_argument(
|
|
56
|
+
"-cm",
|
|
57
|
+
"--check-remote",
|
|
58
|
+
action="store_true",
|
|
59
|
+
help="Check remote references (HTTP/HTTPS links)",
|
|
60
|
+
) # type: ignore
|
|
61
|
+
parser.add_argument("-nc", "--no-color", action="store_true", help="Turn off colored output") # type: ignore
|
|
62
|
+
parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose output") # type: ignore
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--allow-absolute",
|
|
65
|
+
action="store_true",
|
|
66
|
+
help="Allow absolute path references like [ref](/path/to/file.md)",
|
|
67
|
+
) # type: ignore
|
|
68
|
+
|
|
69
|
+
# Check if the user has provided any files or directories
|
|
70
|
+
args = parser.parse_args()
|
|
71
|
+
if not args.paths:
|
|
72
|
+
parser.print_help()
|
|
73
|
+
sys.exit(0)
|
|
74
|
+
|
|
75
|
+
return args
|
|
@@ -18,7 +18,7 @@ def setup_logging(verbose=False):
|
|
|
18
18
|
console_handler.setLevel(logging.INFO)
|
|
19
19
|
console_formatter = logging.Formatter("[%(levelname)s] %(message)s")
|
|
20
20
|
else:
|
|
21
|
-
console_handler.setLevel(logging.
|
|
21
|
+
console_handler.setLevel(logging.WARNING)
|
|
22
22
|
console_formatter = logging.Formatter("%(asctime)s - %(message)s")
|
|
23
23
|
|
|
24
24
|
console_handler.setFormatter(console_formatter)
|
|
@@ -32,7 +32,7 @@ class ReferenceChecker:
|
|
|
32
32
|
logger.info(ref)
|
|
33
33
|
|
|
34
34
|
if ref.is_remote and not settings.check_remote:
|
|
35
|
-
logger.
|
|
35
|
+
logger.info("Skipping remote reference check.")
|
|
36
36
|
status = print_yellow("SKIPPED")
|
|
37
37
|
elif ref.is_remote and settings.check_remote:
|
|
38
38
|
# Check if remote reference is reachable
|
|
@@ -41,9 +41,13 @@ class ReferenceChecker:
|
|
|
41
41
|
if response.status_code < 400:
|
|
42
42
|
status = print_green("OK")
|
|
43
43
|
else:
|
|
44
|
-
logger.info(
|
|
44
|
+
logger.info(
|
|
45
|
+
f"Status code: {response.status_code}, Reason: {response.reason}"
|
|
46
|
+
)
|
|
45
47
|
status = print_red("BROKEN")
|
|
46
|
-
self.broken_references.append(
|
|
48
|
+
self.broken_references.append(
|
|
49
|
+
BrokenReference(**ref.__dict__, status=status)
|
|
50
|
+
)
|
|
47
51
|
except requests.exceptions.RequestException as e:
|
|
48
52
|
logger.error(f"Error: Could not reach remote reference '{ref.link}': {e}")
|
|
49
53
|
status = print_red("BROKEN")
|
|
@@ -54,13 +58,17 @@ class ReferenceChecker:
|
|
|
54
58
|
status = print_green("OK")
|
|
55
59
|
else:
|
|
56
60
|
status = print_red("BROKEN")
|
|
57
|
-
self.broken_references.append(
|
|
61
|
+
self.broken_references.append(
|
|
62
|
+
BrokenReference(**ref.__dict__, status=status)
|
|
63
|
+
)
|
|
58
64
|
else:
|
|
59
65
|
if file_exists(ref.file_path, ref.link):
|
|
60
66
|
status = print_green("OK")
|
|
61
67
|
else:
|
|
62
68
|
status = print_red("BROKEN")
|
|
63
|
-
self.broken_references.append(
|
|
69
|
+
self.broken_references.append(
|
|
70
|
+
BrokenReference(**ref.__dict__, status=status)
|
|
71
|
+
)
|
|
64
72
|
print(f"{ref.file_path}:{ref.line_number}: {ref.syntax} - {status}")
|
|
65
73
|
|
|
66
74
|
def print_summary(self):
|
|
@@ -69,7 +77,9 @@ class ReferenceChecker:
|
|
|
69
77
|
|
|
70
78
|
if self.broken_references:
|
|
71
79
|
print(print_red(f"[!] {len(self.broken_references)} broken references found:"))
|
|
72
|
-
self.broken_references = sorted(
|
|
80
|
+
self.broken_references = sorted(
|
|
81
|
+
self.broken_references, key=lambda ref: (ref.file_path, ref.line_number)
|
|
82
|
+
)
|
|
73
83
|
|
|
74
84
|
for broken_ref in self.broken_references:
|
|
75
85
|
print(f"{broken_ref.file_path}:{broken_ref.line_number}: {broken_ref.syntax}")
|
|
@@ -77,12 +87,12 @@ class ReferenceChecker:
|
|
|
77
87
|
if settings.no_color:
|
|
78
88
|
print("No broken references!")
|
|
79
89
|
else:
|
|
80
|
-
print(print_green("\
|
|
90
|
+
print(print_green("\U0001f389 No broken references!"))
|
|
81
91
|
|
|
82
92
|
print("====================================================================")
|
|
83
93
|
|
|
84
94
|
|
|
85
|
-
def main() ->
|
|
95
|
+
def main() -> None:
|
|
86
96
|
# Check if settings configuration is valid
|
|
87
97
|
if not settings.is_valid():
|
|
88
98
|
sys.exit(1)
|
|
@@ -92,13 +102,17 @@ def main() -> bool:
|
|
|
92
102
|
|
|
93
103
|
check_remote: bool = settings.check_remote
|
|
94
104
|
if not check_remote:
|
|
95
|
-
print(
|
|
105
|
+
print(
|
|
106
|
+
print_yellow(
|
|
107
|
+
"[!] WARNING: Skipping remote reference check. Enable with arg --check-remote."
|
|
108
|
+
)
|
|
109
|
+
)
|
|
96
110
|
|
|
97
111
|
# Retrieve all markdown files specified by the user
|
|
98
112
|
markdown_files = get_markdown_files_from_args(settings.paths, settings.exclude)
|
|
99
113
|
if not markdown_files:
|
|
100
114
|
print(print_red("[!] No Markdown files specified or found."))
|
|
101
|
-
|
|
115
|
+
sys.exit(1)
|
|
102
116
|
|
|
103
117
|
print(f"\n[+] {len(markdown_files)} Markdown files to check.")
|
|
104
118
|
for file in markdown_files:
|
|
@@ -119,20 +133,19 @@ def main() -> bool:
|
|
|
119
133
|
logging.info(f"Checking {len(image_refs)} image references ...")
|
|
120
134
|
checker.check_references(image_refs)
|
|
121
135
|
|
|
122
|
-
|
|
123
|
-
|
|
136
|
+
inline_links = references["inline_links"]
|
|
137
|
+
logging.info(f"Checking {len(inline_links)} inline links ...")
|
|
138
|
+
checker.check_references(inline_links)
|
|
124
139
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
# logging.info(f"Checking {len(inline_links)} inline links ...")
|
|
128
|
-
# checker.check_references(inline_links, check_remote)
|
|
140
|
+
if len(basic_refs) == 0 and len(image_refs) == 0 and len(inline_links) == 0:
|
|
141
|
+
print("No references found.")
|
|
129
142
|
|
|
130
143
|
checker.print_summary()
|
|
131
|
-
|
|
144
|
+
if checker.broken_references:
|
|
145
|
+
sys.exit(1) # Exit with failure if broken references found
|
|
146
|
+
else:
|
|
147
|
+
sys.exit(0) # Exit with success if no broken references
|
|
132
148
|
|
|
133
149
|
|
|
134
150
|
if __name__ == "__main__":
|
|
135
|
-
|
|
136
|
-
sys.exit(0)
|
|
137
|
-
else:
|
|
138
|
-
sys.exit(1)
|
|
151
|
+
main()
|