mkdocs-easylinks-plugin 0.1.1__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.
@@ -0,0 +1,33 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ env:
9
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.12"
22
+
23
+ - name: Install build tools
24
+ run: pip install build twine
25
+
26
+ - name: Build package
27
+ run: python -m build
28
+
29
+ - name: Publish to PyPI
30
+ env:
31
+ TWINE_USERNAME: __token__
32
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
33
+ run: twine upload dist/*
@@ -0,0 +1,31 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ env:
10
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Set up Python ${{ matrix.python-version }}
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+
27
+ - name: Install dependencies
28
+ run: pip install -e ".[dev]"
29
+
30
+ - name: Run tests
31
+ run: pytest
@@ -0,0 +1,44 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ .Python
8
+ build/
9
+ develop-eggs/
10
+ dist/
11
+ downloads/
12
+ eggs/
13
+ .eggs/
14
+ lib/
15
+ lib64/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ wheels/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+
24
+ # Testing
25
+ .pytest_cache/
26
+ .coverage
27
+ htmlcov/
28
+ .tox/
29
+
30
+ # Virtual environments
31
+ venv/
32
+ env/
33
+ ENV/
34
+
35
+ # IDEs
36
+ .vscode/
37
+ .idea/
38
+ *.swp
39
+ *.swo
40
+ *~
41
+
42
+ # OS
43
+ .DS_Store
44
+ Thumbs.db
@@ -0,0 +1,34 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.1.1] - 2026-03-26
6
+
7
+ ### Fixed
8
+ - Relative path calculation replaced with `os.path.relpath` — the previous custom algorithm could miscalculate paths for certain directory structures, producing silently broken links
9
+ - `exclude_dirs` no longer incorrectly excludes directories whose names contain the excluded name as a substring (e.g. excluding `"api"` no longer excluded `"apidocs/"`)
10
+ - Unresolved images now increment `images_unresolved` instead of `links_unresolved`, preventing misleading statistics
11
+ - Duplicate filenames are now correctly counted in `files_indexed` statistics
12
+ - `stats` and `link_counts` now reset on each build, preventing accumulation across rebuilds during `mkdocs serve` live reload
13
+ - Restored `files` parameter to `on_page_markdown` signature for compatibility with MkDocs versions that pass all keyword arguments directly
14
+
15
+ ### Added
16
+ - Per-page warning when a link resolves to an ambiguous filename, including the referring page path and all candidate locations
17
+ - All plugin warnings now prefixed with `easylinks:` for easier identification in build output
18
+ - `images_unresolved` statistic counter
19
+
20
+ ### Changed
21
+ - Migrated plugin configuration from deprecated `config_scheme` tuple to typed `PluginConfig` class (MkDocs 1.5+ style)
22
+ - Regex pattern for link matching compiled once at class level rather than per page
23
+ - Removed unused `page` parameter from `_resolve_filename`
24
+ - Merged duplicate closures in `_extract_protected_blocks` into a single function
25
+
26
+ ## [0.1.0] - Initial release
27
+
28
+ - Simple filename-based link and image resolution
29
+ - Automatic relative path calculation
30
+ - Glob pattern support for `ignore_files`
31
+ - Directory exclusion via `exclude_dirs`
32
+ - Ambiguity detection and warnings
33
+ - Code fence and HTML comment protection
34
+ - Post-build link statistics via `show_stats`
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Ferguson
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,292 @@
1
+ Metadata-Version: 2.4
2
+ Name: mkdocs-easylinks-plugin
3
+ Version: 0.1.1
4
+ Summary: An MkDocs plugin that allows linking to files by filename only
5
+ Author: Daniel Ferguson
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/dsferg/mkdocs-easylinks-plugin
8
+ Project-URL: Documentation, https://github.com/dsferg/mkdocs-easylinks-plugin
9
+ Project-URL: Repository, https://github.com/dsferg/mkdocs-easylinks-plugin
10
+ Keywords: mkdocs,plugin,links,cross-references
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: mkdocs>=1.4.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0; extra == "dev"
27
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # MkDocs EasyLinks Plugin
31
+
32
+ An MkDocs plugin that allows you to create cross-references and embed images by specifying only the filename, without needing to know the full path.
33
+
34
+ ## Features
35
+
36
+ - **Simple linking**: Reference any file in your docs with just its filename
37
+ - **Image support**: Embed images using simple filenames like `![alt](image.png)`
38
+ - **Automatic resolution**: The plugin finds the file and generates the correct relative path
39
+ - **Glob patterns**: Use wildcards to ignore multiple files (e.g., `draft-*.md`, `*.tmp`)
40
+ - **Directory exclusion**: Exclude entire directories from being indexed
41
+ - **Link statistics**: See which files are most linked and find orphaned content
42
+ - **Ambiguity warnings**: Get notified if multiple files share the same name
43
+ - **Material for MkDocs compatible**: Works seamlessly with Material theme
44
+ - **Smart protection**: Code fences and HTML comments are preserved unchanged
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ pip install mkdocs-easylinks-plugin
50
+ ```
51
+
52
+ Or install directly from source:
53
+
54
+ ```bash
55
+ pip install -e .
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ Add the plugin to your `mkdocs.yml`:
61
+
62
+ ```yaml
63
+ plugins:
64
+ - search
65
+ - easylinks
66
+ ```
67
+
68
+ ### Configuration Options
69
+
70
+ ```yaml
71
+ plugins:
72
+ - easylinks:
73
+ warn_on_missing: true # Warn when a file can't be found (default: true)
74
+ warn_on_ambiguous: true # Warn when multiple files have the same name (default: true)
75
+ ignore_files: [] # List of filenames/patterns to ignore (default: [])
76
+ exclude_dirs: [] # List of directories to exclude (default: [])
77
+ show_stats: false # Show link statistics after build (default: false)
78
+ ```
79
+
80
+ #### Available Options
81
+
82
+ - **`warn_on_missing`** (bool, default: `true`): Show warnings when a linked file cannot be found
83
+ - **`warn_on_ambiguous`** (bool, default: `true`): Show warnings when multiple files share the same name
84
+ - **`ignore_files`** (list, default: `[]`): List of filenames/patterns to exclude from link resolution (supports glob patterns)
85
+ - **`exclude_dirs`** (list, default: `[]`): List of directories to exclude completely
86
+ - **`show_stats`** (bool, default: `false`): Display link statistics after the build completes
87
+
88
+ #### Ignoring Specific Files
89
+
90
+ Use `ignore_files` to exclude certain files. Supports both exact matches and glob patterns:
91
+
92
+ ```yaml
93
+ plugins:
94
+ - easylinks:
95
+ ignore_files:
96
+ - draft.md # Exact match
97
+ - template.md # Exact match
98
+ - "draft-*.md" # Glob pattern - all files starting with "draft-"
99
+ - "*.tmp" # Glob pattern - all .tmp files
100
+ - "test_*" # Glob pattern - all files starting with "test_"
101
+ ```
102
+
103
+ #### Excluding Directories
104
+
105
+ Use `exclude_dirs` to exclude entire directories:
106
+
107
+ ```yaml
108
+ plugins:
109
+ - easylinks:
110
+ exclude_dirs:
111
+ - drafts/
112
+ - templates/
113
+ - .archive/
114
+ ```
115
+
116
+ All files in these directories (and subdirectories) will be excluded from indexing.
117
+
118
+ > **Note:** Directory paths are matched as prefixes against each file's path within the docs directory. This means `exclude_dirs: ["api"]` excludes `api/page.md` but **not** `docs/api/page.md`. To exclude a nested directory, specify the full path from the docs root: `exclude_dirs: ["docs/api"]`.
119
+
120
+ #### Link Statistics
121
+
122
+ Enable `show_stats` to see detailed statistics after your build:
123
+
124
+ ```yaml
125
+ plugins:
126
+ - easylinks:
127
+ show_stats: true
128
+ ```
129
+
130
+ This will display:
131
+ - Files scanned and indexed
132
+ - Links processed, resolved, and unresolved
133
+ - Images processed, resolved, and unresolved
134
+ - Most frequently linked files
135
+ - Orphaned files (indexed but never linked)
136
+
137
+ ## Examples
138
+
139
+ ### Documentation Links
140
+
141
+ Instead of writing:
142
+
143
+ ```markdown
144
+ [See the guide](../../advanced/guides/configuration.md)
145
+ ```
146
+
147
+ You can now write:
148
+
149
+ ```markdown
150
+ [See the guide](configuration.md)
151
+ ```
152
+
153
+ The plugin will automatically resolve `configuration.md` to its full path and generate the correct relative link.
154
+
155
+ ### Images
156
+
157
+ Works with images too! Instead of:
158
+
159
+ ```markdown
160
+ ![Diagram](../../assets/images/architecture.png)
161
+ ```
162
+
163
+ Just write:
164
+
165
+ ```markdown
166
+ ![Diagram](architecture.png)
167
+ ```
168
+
169
+ ### With Anchors
170
+
171
+ Anchors work for document links:
172
+
173
+ ```markdown
174
+ [See section](somefile.md#advanced-features)
175
+ ```
176
+
177
+ ### What Links Are Processed
178
+
179
+ **Processed** (converted to full paths):
180
+ - `[text](filename.md)` - Simple document filenames
181
+ - `[text](file.md#anchor)` - Document filenames with anchors
182
+ - `![alt](image.png)` - Simple image filenames (png, jpg, svg, gif, etc.)
183
+
184
+ **Not processed** (left as-is):
185
+ - `[text](https://example.com)` - External URLs
186
+ - `![alt](https://example.com/image.png)` - External images
187
+ - `[text](/absolute/path.md)` - Absolute paths
188
+ - `[text](../relative/path.md)` - Explicit relative paths with directories
189
+ - `[text](#anchor)` - Fragment-only links
190
+ - Links/images inside code fences (` ``` ` or `~~~`)
191
+ - Links/images inside HTML comments (`<!-- -->`)
192
+
193
+ ### Protected Content
194
+
195
+ The plugin intelligently ignores links in:
196
+
197
+ **Code fences:**
198
+ ````markdown
199
+ ```python
200
+ # This [link](example.md) won't be processed
201
+ ```
202
+ ````
203
+
204
+ **HTML comments:**
205
+ ```markdown
206
+ <!-- This [link](example.md) won't be processed -->
207
+ ```
208
+
209
+ This ensures that example code and commented-out content remain unchanged.
210
+
211
+ **Important: Indented Content**
212
+
213
+ Only explicit code fences (``` or ~~~) are protected. Indented content, such as in MkDocs admonitions, **is processed normally**:
214
+
215
+ ```markdown
216
+ !!! note
217
+ This [link](guide.md) WILL be processed.
218
+ The plugin works inside admonitions!
219
+ ```
220
+
221
+ This design choice ensures the plugin works seamlessly with MkDocs features like admonitions, which rely heavily on indentation.
222
+
223
+ ## How It Works
224
+
225
+ 1. During the build, the plugin scans all files (documentation, images, assets, etc.)
226
+ 2. It creates a mapping of filenames to their full paths
227
+ 3. When processing each page, it finds markdown links and images with simple filenames
228
+ 4. It replaces them with the correct relative path from the current page to the target
229
+
230
+ **Files that are excluded from mapping:**
231
+ - Files starting with `.` (dotfiles) - always ignored
232
+ - Files listed in `ignore_files` configuration - useful for drafts and templates
233
+
234
+ ## Using with mkdocs-macros-plugin (Snippets)
235
+
236
+ If you use [mkdocs-macros-plugin](https://mkdocs-macros-plugin.readthedocs.io/) to include snippet files via `{% include '...' %}`, easylinks works correctly with no extra configuration — as long as the plugin order in `mkdocs.yml` is correct:
237
+
238
+ ```yaml
239
+ plugins:
240
+ - macros:
241
+ include_dir: docs/.snippets
242
+ - easylinks # must come after macros
243
+ ```
244
+
245
+ Because macros runs first, snippet content is inlined into the page before easylinks processes it. Links in snippets are resolved relative to the **including page**, not the snippet file itself — which is exactly the right behaviour when a snippet may be included from pages at different directory levels.
246
+
247
+ **Best practices:**
248
+
249
+ - Always list `easylinks` after `macros` in your `plugins` configuration.
250
+ - Use simple filename links (e.g. `[text](target.md)`) in your snippets rather than relative paths, since relative paths would break when the same snippet is included from different locations.
251
+ - If your snippets directory could contain files whose names clash with published docs files, add it to `exclude_dirs` to prevent false ambiguity warnings:
252
+
253
+ ```yaml
254
+ plugins:
255
+ - easylinks:
256
+ exclude_dirs: ['.snippets']
257
+ ```
258
+
259
+ ## Handling Ambiguous Filenames
260
+
261
+ If you have multiple files with the same name (e.g., `index.md` in different folders), the plugin will:
262
+
263
+ 1. Warn you about the ambiguity
264
+ 2. Use the first occurrence found
265
+ 3. Recommend using full paths for those specific files
266
+
267
+ ## Development
268
+
269
+ ### Setup
270
+
271
+ ```bash
272
+ # Clone the repository
273
+ git clone https://github.com/dsferg/mkdocs-easylinks-plugin.git
274
+ cd mkdocs-easylinks-plugin
275
+
276
+ # Install in development mode
277
+ pip install -e ".[dev]"
278
+ ```
279
+
280
+ ### Running Tests
281
+
282
+ ```bash
283
+ pytest
284
+ ```
285
+
286
+ ## License
287
+
288
+ MIT License - See LICENSE file for details
289
+
290
+ ## Contributing
291
+
292
+ Contributions are welcome! Please feel free to submit a Pull Request.