pax_global_header00006660000000000000000000000064147663654450014536gustar00rootroot0000000000000052 comment=7423f00fe2c26c879310f76631b8180cb2bb6ace mkdocs-literate-nav-0.6.2/000077500000000000000000000000001476636544500154145ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/.github/000077500000000000000000000000001476636544500167545ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/.github/FUNDING.yml000066400000000000000000000000201476636544500205610ustar00rootroot00000000000000github: oprypin mkdocs-literate-nav-0.6.2/.github/workflows/000077500000000000000000000000001476636544500210115ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/.github/workflows/autofix.yml000066400000000000000000000014761476636544500232230ustar00rootroot00000000000000name: Auto-fix on: push: pull_request: jobs: style: runs-on: ubuntu-latest steps: - name: Download source uses: actions/checkout@v4 - name: Install Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install Hatch run: | pip install hatch - name: Install dependencies run: | hatch run style:pip freeze - name: Fix code style run: | hatch run style:fix --fix-only - name: Check if any edits are necessary run: | git diff --color --exit-code - name: Apply automatic fixes using pre-commit-ci-lite if: failure() && github.event_name == 'pull_request' uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0 mkdocs-literate-nav-0.6.2/.github/workflows/ci.yml000066400000000000000000000034621476636544500221340ustar00rootroot00000000000000name: CI on: push: pull_request: schedule: - cron: '0 6 * * 6' defaults: run: shell: bash jobs: test: strategy: fail-fast: false matrix: include: - python: '^3.13' os: ubuntu-latest - python: '3.13' os: macos-latest - python: '3.12' os: windows-latest - python: '3.11' os: ubuntu-latest - python: '3.10' os: macos-latest - python: '3.9' os: windows-latest - python: '3.9' os: ubuntu-latest versions: minimal runs-on: ${{matrix.os}} steps: - name: Download source uses: actions/checkout@v4 - name: Install Python uses: actions/setup-python@v5 with: python-version: ${{matrix.python}} - name: Pin to lowest versions if: matrix.versions == 'minimal' run: | sed -i -E 's/#min //; s/\b >=([0-9])/ ==\1/' pyproject.toml - name: Install Hatch run: | pip install hatch - name: Install dependencies run: | hatch run test:pip freeze - name: Run tests run: | hatch run test:test style: runs-on: ubuntu-latest steps: - name: Download source uses: actions/checkout@v4 - name: Install Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install Hatch run: | pip install hatch - name: Install dependencies run: | hatch run style:pip freeze hatch run types:pip freeze - name: Check style if: always() run: | hatch run style:check - name: Check types if: always() run: | hatch run types:check mkdocs-literate-nav-0.6.2/.github/workflows/deploy-docs.yml000066400000000000000000000017641476636544500237660ustar00rootroot00000000000000name: Deploy docs on: push: pull_request: schedule: - cron: '0 6 * * 6' jobs: build: runs-on: ubuntu-latest steps: - name: Download source uses: actions/checkout@v4 - name: Install Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install dependencies run: pip install --no-deps -r requirements/requirements-docs.txt - name: Build site run: mkdocs build --strict - name: Upload to GitHub Pages uses: actions/upload-pages-artifact@v3 with: path: site deploy: if: github.event_name == 'push' && github.ref_name == github.event.repository.default_branch needs: build permissions: pages: write id-token: write runs-on: ubuntu-latest steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} mkdocs-literate-nav-0.6.2/.github/workflows/deploy-release.yml000066400000000000000000000007651476636544500244560ustar00rootroot00000000000000name: Deploy release on: push: tags: - '*' jobs: pypi: permissions: id-token: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install dependencies run: pip install -U build - name: Build package run: python -m build - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 mkdocs-literate-nav-0.6.2/.gitignore000066400000000000000000000001371476636544500174050ustar00rootroot00000000000000/dist/ site*/ .mypy_cache/ .pytest_cache/ __pycache__/ *.egg-info/ .venv/ poetry.lock .vscode/ mkdocs-literate-nav-0.6.2/.tools/000077500000000000000000000000001476636544500166325ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/.tools/copier-answers.yml000066400000000000000000000006331476636544500223200ustar00rootroot00000000000000_commit: 1c7686408 _src_path: gh:oprypin/py-project-template copyright_date: '2020' mkdocs: true mkdocs_install_self: false project_description: MkDocs plugin to specify the navigation in Markdown instead of YAML project_name: mkdocs-literate-nav pytest: true python_distribution_name: mkdocs-literate-nav python_source_path: mkdocs_literate_nav repository_name: oprypin/mkdocs-literate-nav script_test: false mkdocs-literate-nav-0.6.2/.tools/release.sh000077500000000000000000000004161476636544500206120ustar00rootroot00000000000000#!/bin/bash set -e -u -x cd "$(dirname "$0")/.." git diff --staged --quiet git diff --quiet HEAD pyproject.toml rm -rf dist hatch version "$1" hatch build git add mkdocs_literate_nav/__init__.py git commit -m "v$1" git tag -a -m "" "v$1" git push origin master --tags mkdocs-literate-nav-0.6.2/LICENSE.md000066400000000000000000000020731476636544500170220ustar00rootroot00000000000000MIT License Copyright (c) 2020 Oleh Prypin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mkdocs-literate-nav-0.6.2/README.md000066400000000000000000000332651476636544500167040ustar00rootroot00000000000000# mkdocs-literate-nav **[Plugin][] for [MkDocs][] to specify the navigation in Markdown instead of YAML** [![PyPI](https://img.shields.io/pypi/v/mkdocs-literate-nav)](https://pypi.org/project/mkdocs-literate-nav/) [![License](https://img.shields.io/github/license/oprypin/mkdocs-literate-nav)](https://github.com/oprypin/mkdocs-literate-nav/blob/master/LICENSE.md) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/oprypin/mkdocs-literate-nav/ci.yml.svg)](https://github.com/oprypin/mkdocs-literate-nav/actions?query=event%3Apush+branch%3Amaster) ```shell pip install mkdocs-literate-nav ``` Works well with **[section-index][]** and **[gen-files][]**. Supplants **[awesome-pages][]**. [mkdocs]: https://www.mkdocs.org/ [plugin]: https://www.mkdocs.org/user-guide/plugins/ [section-index]: https://oprypin.github.io/mkdocs-section-index/ [gen-files]: https://oprypin.github.io/mkdocs-gen-files/ [awesome-pages]: https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin ## Usage Activate the plugin in **mkdocs.yml**: ```yaml plugins: - search - literate-nav: nav_file: SUMMARY.md ``` and **drop** the `nav` section if it's present there; it will be ignored now. ([Unless you want to keep it?](#hybrid-nav))
To get this navigation, create the file SUMMARY.md: (old YAML equivalent:)
* [Frob](#index.md) * [Baz](#baz.md) * [Borgs](#borgs/index.md) * [Bar](#borgs/bar.md) * [Foo](#borgs/foo.md) ```markdown * [Frob](index.md) * [Baz](baz.md) * [Borgs](borgs/index.md) * [Bar](borgs/bar.md) * [Foo](borgs/foo.md) ``` ```yaml nav: - Frob: index.md - Baz: baz.md - Borgs: - borgs/index.md - Bar: borgs/bar.md - Foo: borgs/foo.md ```
IMPORTANT: The nav file must be put inside the [`docs` directory][docs_dir] -- at the root of it. So, the plugin lets you specify your site's navigation with lists of links that are parsed according to normal Markdown rules. Note that, the way we wrote the Markdown, a section seems to also have a page associated with it. MkDocs doesn't actually support that, and neither is it representable in YAML directly, so the plugin tries to do the next best thing: include the link as the first page of the section. However, this structure is perfectly suited for the *[section-index][]* plugin, which actually makes that work. Or you could just *not* associate a link with sections:
To get this navigation, create the file SUMMARY.md: (old YAML equivalent:)
* [Frob](#index.md) * [Baz](#baz.md) * Borgs * [Bar](#borgs/bar.md) * [Foo](#borgs/foo.md) ```markdown * [Frob](index.md) * [Baz](baz.md) * Borgs * [Bar](borgs/bar.md) * [Foo](borgs/foo.md) ``` ```yaml nav: - Frob: index.md - Baz: baz.md - Borgs: - Bar: borgs/bar.md - Foo: borgs/foo.md ```
**[See syntax details about literate nav files.](https://oprypin.github.io/mkdocs-literate-nav/reference.html)** You can find more examples of the "literate nav" syntax [in the testcases directory](https://github.com/oprypin/mkdocs-literate-nav/tree/master/tests/nav). ### Nav cross-link But why stop there? Each directory can have its own decoupled navigation list (see how the trailing slash initiates a nav cross-link):
To get this navigation, create the file SUMMARY.md: (old YAML equivalent:)
* [Frob](#index.md) * [Baz](#baz.md) * Borgs * [Bar](#borgs/bar.md) * [Foo](#borgs/foo.md) ```markdown * [Frob](index.md) * [Baz](baz.md) * [Borgs](borgs/) ``` ```yaml nav: - Frob: index.md - Baz: baz.md - Borgs: - Bar: borgs/bar.md - Foo: borgs/foo.md ```
and the file borgs/SUMMARY.md:
```markdown * [Bar](bar.md) * [Foo](foo.md) ```
> NOTE: The nav file in the subdirectory is picked up *only* because its directory is explicitly mentioned in a parent nav file. **SUMMARY.md** (generally [`nav-file`](#customizing-nav_file)) files are **not** picked up implicitly (only the root nav file is "implicit"). > > So you might say that the nav construction approach is exactly the opposite from the *[awesome-pages][]* plugin. > > That said, an [inferred cross-linked directory](#inferred-sub-directory) (whether directly or through [wildcards](#wildcards)) gets resolved recursively, so that way you actually go back to implicit resolution. #### Inferred sub-directory Or perhaps you don't care about the order of the pages under the **borgs/** directory? Just drop the file __borgs/SUMMARY.md__ and let it be inferred (recursively, if applicable). For our particular example, the final result would be the same. The fallback behavior follows the [default behavior of MkDocs when nav isn't specified][mkdocs-nav], except that you can leave out only some directory trees, rather than an all-or-nothing choice. ### Wildcards Between the two extremes of entirely specifying a nav and entirely inferring it, there's the option of applying wildcards. Instead of putting links like `[Foo 1](foo_1.md)`, `[Foo 2](foo_2.md)` into the nav list, you can write a wildcard item: `foo_*.md` (bare, not as a link). The asterisk indicates that any number of characters can go there, and the file name has to match the rest of the pattern. A wildcard item is always required to have at least one `*` asterisk in it, because if it doesn't, then it's *just* a bare item, which are disallowed. **[See details about wildcards.](https://oprypin.github.io/mkdocs-literate-nav/reference.html#wildcards)** So this can be used to fully specify order for items that matter and apply wildcards for all other cases. Example:
By writing this literate nav file, you may get a nav like this: (assuming the files exist:)
```markdown - [Welcome](index.md) - Usage - [Foo](usage/foo.md) - usage/*.md - */ - *.md - [API docs](api/) - [License](license.md) ``` ```yaml - Welcome: index.md - Usage: - Foo: usage/foo.md - usage/bar.md - usage/baz.md - Tips: - tips/other-stuff.md - tips/stuff.md - changelog.md - credits.md - API docs: - api/Foo.md - Bar: - api/Bar/index.md - api/Bar/Baz.md - License: license.md ``` * index.md * changelog.md * credits.md * usage / bar.md * usage / baz.md * usage / foo.md * tips / stuff.md * tips / other-stuff.md * api / Foo.md * api / Bar / index.md * api / Bar / Baz.md
TIP: Speaking of API docs... Want to fine-tune file ordering in a large directory tree? Check out [integrations with other plugins](#extras). The paths are relative to the directory that the nav file is in. Matching files in subdirectories also works, in both ways: `*/foo.md` and `foo/*.md`. As it's impossible for a user to specify the titles of items produced by a wildcard, they have to be inferred, based on [normal rules of MkDocs][mkdocs-nav]. > TIP: The ordering of items matches MkDocs' default, so first go all files, alphabetically (but with the index file first), then all directories. But, as an example, you could actually swap that, by writing: > > ```markdown > - */ > - * > ``` You can find more examples of the wildcard syntax [in the testcases directory](https://github.com/oprypin/mkdocs-literate-nav/tree/master/tests/nav/wildcard). ### Customizing `nav_file` We've been using **SUMMARY.md** as the name of the file that specifies the nav (actually that is also the default value of `nav_file`), but naturally, you can use any other file name. **[See details about the `nav_file` config.](https://oprypin.github.io/mkdocs-literate-nav/reference.html#nav_file)** The plugin takes care to not let MkDocs complain if you don't end up using the nav document as an actual page of your doc site. #### Show off your nav on the front page Or maybe you want the opposite -- make the nav page very prominent? You can actually use the index page, **README.md**, for the nav! Why would one do this? Well, GitHub (or another source hosting) also displays the Markdown files, and it's quite a nice perk to show off your navigation right in the index page of a directory. Of course, then you'd probably refrain from using [wildcards](#wildcards). [Directory cross linking](#nav-cross-link) still looks great, though. What's that, you ask? If the index page is taken up by navigation, we can't put any other content there, can we? Actually, we can! The nav list can just be put at the bottom of the page that also has whatever other content before that. [See an example of all this in action](https://github.com/oprypin/crsfml/tree/master/docs/tutorials) #### Explicit nav mark If the plugin is confused where in the document the nav is, or if you want to explicitly put it in a particular location, please precede the Markdown list with this HTML comment (verbatim) on a line of its own: ```html ``` ### Hybrid nav Do the features of this plugin interest you but you're not on board with the idea of migrating your whole nav? You can actually keep using [MkDocs' own nav specification][mkdocs-nav] at the root, *but* defer only some subdirectories to the *literate-nav* plugin. In that case make sure to *not* put a nav file at the [`docs` root][docs_dir], otherwise the native nav will be ignored.
To get this navigation, put this into mkdocs.yml: (old YAML equivalent:)
* [Frob](#index.md) * [Baz](#baz.md) * Borgs * [Bar](#borgs/bar.md) * [Foo](#borgs/foo.md) ```yaml nav: - Frob: index.md - Baz: baz.md - Borgs: borgs/ ``` ```yaml nav: - Frob: index.md - Baz: baz.md - Borgs: - Bar: borgs/bar.md - Foo: borgs/foo.md ```
& create the file borgs/SUMMARY.md:
```markdown * [Bar](bar.md) * [Foo](foo.md) ```
The syntax to defer to a subdirectory, just like [in a literate nav](#nav-cross-link), is to write an item that *ends* with a slash. NOTE: There is no way to use a YAML nav for a subdirectory, only a literate nav can be deferred. Wildcards also work very similarly. **[See details about syntax additions for MkDocs native nav.](https://oprypin.github.io/mkdocs-literate-nav/reference.html#mkdocs-native-nav)** You can find examples of the hybrid nav syntax [in the testcases directory](https://github.com/oprypin/mkdocs-literate-nav/tree/master/tests/nav/hybrid). #### MkDocs native nav with inferred subdirectories As before, whenever you have the option of using a literate nav file for a sub-directory, you can also *not* put any nav file there and infer the sub-directory instead. So, *not* creating the file **borgs/SUMMARY.md** would have yielded the same result in the above example. So basically, you can use the *literate-nav* plugin just for its ability to infer only sub-directories, without ever writing any actual "literate navs". #### Details about hybrid nav As a final example, note that there are two ways to include a subdirectory, with significant difference:
To get this navigation, put this into mkdocs.yml: To get this navigation, put this into mkdocs.yml:
* [Frob](#index.md) * [Baz](#baz.md) * Borgs * [Bar](#borgs/bar.md) * [Foo](#borgs/foo.md) ```yaml nav: - Frob: index.md - Baz: baz.md - Borgs: borgs/ ``` * [Frob](#index.md) * [Baz](#baz.md) * [Bar](#borgs/bar.md) * [Foo](#borgs/foo.md) ```yaml nav: - Frob: index.md - Baz: baz.md - borgs/* ```
So, a directory item with a title becomes a section titled as such. And a wildcard (which can't have a title specified) gets inlined into the existing section. This simple example has no sub-sub-directories, but the relative subdirectory structure would be preserved in both cases if it did. ### Extras #### Programmatic control over the nav Let's say you need the ability to infer nav for a sub-directory, but are unhappy with the default naming/layout behavior, and you don't want to write all that out manually either. Then, definitely check out the ***[gen-files][]* plugin**. Its normal usage is to programmatically add files to the site during the build, but that also includes literate nav files! Moreover, you don't even have to teach your program to write Markdown. There's a more direct integration: `mkdocs_gen_files.Nav.build_literate_nav`. [See an example that generates both the files and the navigation covering them](https://github.com/mkdocstrings/mkdocstrings/blob/5802b1ef5ad9bf6077974f777bd55f32ce2bc219/docs/gen_doc_stubs.py#L25). #### Indent lists by 2 spaces, not 4 Configure it through [tab_length](https://oprypin.github.io/mkdocs-literate-nav/reference.html#tab_length) or [markdown_extensions](https://oprypin.github.io/mkdocs-literate-nav/reference.html#markdown_extensions) #### Migrating from GitBook? It might be very easy! Just beware of the stricter Markdown parser; it will *not* accept 2-space indentation for sub-lists. And use this for **mkdocs.yml**:
```yaml use_directory_urls: false ``` ```yaml plugins: - search - same-dir - section-index - literate-nav: nav_file: SUMMARY.md ``` ```yaml theme: name: material ``` ```yaml markdown_extensions: - pymdownx.highlight - pymdownx.magiclink - pymdownx.superfences ```
[mkdocs-nav]: https://www.mkdocs.org/user-guide/writing-your-docs/#configure-pages-and-navigation [docs_dir]: https://www.mkdocs.org/user-guide/configuration/#docs_dir mkdocs-literate-nav-0.6.2/docs/000077500000000000000000000000001476636544500163445ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/docs/README.md000066400000000000000000000000231476636544500176160ustar00rootroot00000000000000--8<-- "README.md" mkdocs-literate-nav-0.6.2/docs/reference.md000066400000000000000000000201431476636544500206240ustar00rootroot00000000000000## Literate nav syntax The literate nav file must be a Markdown file, which can contain arbitrary content, but the **last-encountered Markdown list** in it will be used to determine the navigation. It must adhere to [specific rules](#nav-list-syntax), otherwise an error will be generated. ### Explicit nav mark If any line in the Markdown file has the exact content "``", that changes the choice of nav list for that file to instead be the first-encountered list after such a line. ### Nav list syntax !!! example "SUMMARY.md" ```markdown * [First list item](some-page.md) * Subsection title * [Something](subdirectory/something.md) * subdirectory/*.md * [Other directory](other/) ``` The navigation list must be a top-level [Markdown list](https://daringfireball.net/projects/markdown/syntax#list), regardless if it's an ordered list or not. It can contain other sub-lists, which are used as sub-directories for the nav. To include a page into the nav, write a [Markdown link](https://daringfireball.net/projects/markdown/syntax#link) such as `[Page title](path/to/some-page.md)`. Unlike with the [native nav](#mkdocs-native-nav), a title is mandatory; bare paths are an error (unless they contain an asterisk; see below). Links in the nav file directly under the root [`docs` dir][docs_dir] are relative to the `docs` dir, and for nav files that are in a subdirectory, links are relative to that subdirectory (generally referred to as "current" directory). Links can refer to files that are in other directories, both below (`sub/dir/foo.md`) and above (`../foo.md`) the current directory -- though the latter is not as well supported. The forward slash `/` must be used as the path separator. To add a sub-section into a nav, make a list item that is not a link (so its text becomes the section title) and start a nested list under it (so its content turns into the section nav). The rules apply recursively to that list. The parser makes some effort to allow *and strip* other inline Markdown markup (e.g. italics), but this is generally unsupported. ### Wildcards Bare paths that contain an `*` asterisk are recognized as [wildcards](#wildcards). Asterisks are special *only* in bare items; they don't do anything inside a Markdown link. A wildcard item, whenever encountered in a list, will be replaced with every file *and directory* that matches it and is not mentioned in the nav explicitly already *and* hasn't been matched by any preceding wildcard items. It is possible to select only directories by adding a trailing slash, like `*/`. And to distinguish files, you have to rely on them having a file extension, and write e.g. `*.md`. Wildcards can traverse to subdirectories and parent directories as well. However, the directly matching items will be included *flatly* into the current nav list -- though if a *directory* matches, its sub-items will not be flattened. Currently the only officially supported special character in a wildcard is an `*` asterisk. It indicates that there can be 0 or more arbitrary characters (excluding the path separator) in its place. Resolution of wildcards is done in a particular order, depth-first from the perspective of the final layout of the nav. The reason that the order is important is that *literate-nav* always tries to exclude items from a wildcard that was already mentioned elsewhere in the nav, so the items are not duplicated. If the two relevant occurrences are somewhere in the same directory tree (one nav section is a parent of the other), the detection will always just work. If they are in separate directory trees, order starts to matter: only items mentioned "earlier" (in top-to-bottom reading order) will be omitted from wildcards occurring "later". The same ordering applies if there are two wildcards competing for the same items: only the "earlier" one will contain those items. #### Subdirectory cross-link If a link's destination ends with a `/` slash, it is instead recognized as a [subdirectory cross-link](#subdirectory-cross-link). A link that leads to a path ending with `/` is understood to be a directory cross-link. If such a directory actually exists relative to the current directory, the nav for it is inserted into this place. If there is no such subdirectory, the link text is kept as is and is likely invalid in the end. If that subdirectory has no [nav file](#nav_file), then writing a directory cross-link means including that directory as a sub-section that recursively includes all the directory's items. I.e. the following two approaches are fully equivalent then: ```markdown * [Foo](foo/) ``` ```markdown * Foo * foo/* ``` But if that subdirectory *does* have a nav file, then that is resolved in the context of that subdirectory and put back into the nav under the subsection. ## MkDocs native nav If there is no literate nav file in the [`docs` dir][docs_dir], this plugin will fall back to using the [normal `nav:` defined in the file `mkdocs.yml`](https://www.mkdocs.org/user-guide/writing-your-docs/#configure-pages-and-navigation). But its items gain extended syntax. !!! example "mkdocs.yml" ```yaml nav: - Foo: foo.md - Usual: - usual/a.md - usual/b.md - '*.md' - Subdir: subdir/ ``` In this example only the last two items are special. Wildcards (items without a title that have an asterisk in them) get replaced by files that they match, relative to the root [`docs` dir][docs_dir]. The resolution rules are the same as [wildcards in a literate nav](#wildcards). [Subdirectory cross-link](#subdirectory-cross-link) items (items with a title and a link that ends with a slash) get replaced by the literate nav for the linked directory (if it exists), under a section with this title. ## MkDocs plugin !!! example "mkdocs.yml" ```yaml plugins: - literate-nav: nav_file: SUMMARY.md implicit_index: false tab_length: 4 ``` ### Config #### `nav_file` *string, default `'SUMMARY.md'`* The name of the file to read to determine the navigation for a particular directory under [`docs_dir`][docs_dir]. E.g. if the directory `docs/foo/bar/` is referenced, the file `docs/foo/bar/SUMMARY.md` will be read for it. This file must contain [a Markdown list](#literate-nav-syntax) that defines the navigation for that directory. If for a particular directory there is no such file, the navigation will be inferred automatically, following [normal MkDocs rules](https://www.mkdocs.org/user-guide/writing-your-docs/#configure-pages-and-navigation). If there is no such file for the [root `docs_dir`][], the nav can fall back to [MkDocs native nav](#mkdocs-native-nav). Although there can be several such files throughout the site, the choice of the file name is global and not modifiaable on a case-by-case basis. #### `implicit_index` *boolean, default `false`* If a directory has a file named [`index.md` or `README.md`](https://www.mkdocs.org/user-guide/writing-your-docs/#index-pages), but the literate nav for that directory that never includes it, it will be inserted as the first item of the nav. This is important when using directory cross-linking, which otherwise makes it impossible to specify a *[section-index][]* page for a subdirectory. #### `tab_length` *integer, default `4`* By default (like in MkDocs), lists need to be indented by 4 spaces. The more modern style is 2 spaces, though. You can change the indentation just for the extension, but that will not affect MkDocs' rendering. If you want to change both at once, install [mdx_truly_sane_lists](https://github.com/radude/mdx_truly_sane_lists) and use it through `markdown_extensions`, instead of this option. See example below. #### `markdown_extensions` *list of mappings, [same as MkDocs](https://www.mkdocs.org/user-guide/configuration/#markdown_extensions)* !!! example "mkdocs.yml" ```yaml plugins: - literate-nav: markdown_extensions: - mdx_truly_sane_lists markdown_extensions: - mdx_truly_sane_lists ``` [mkdocs-nav]: https://www.mkdocs.org/user-guide/writing-your-docs/#configure-pages-and-navigation [docs_dir]: https://www.mkdocs.org/user-guide/configuration/#docs_dir mkdocs-literate-nav-0.6.2/mkdocs.yml000066400000000000000000000022361476636544500174220ustar00rootroot00000000000000site_name: "mkdocs-literate-nav" site_description: "MkDocs plugin to specify the navigation in Markdown instead of YAML" site_url: "https://oprypin.github.io/mkdocs-literate-nav" repo_url: "https://github.com/oprypin/mkdocs-literate-nav" edit_uri: blob/master/docs/ use_directory_urls: false theme: name: material features: - content.action.edit - navigation.tabs - toc.integrate icon: repo: fontawesome/brands/github palette: primary: teal accent: purple markdown_extensions: - pymdownx.details - pymdownx.highlight - pymdownx.magiclink - pymdownx.saneheaders - pymdownx.superfences - pymdownx.snippets: check_paths: true base_path: - !relative $config_dir - callouts - admonition - md_in_html - toc: permalink: "#" validation: omitted_files: warn absolute_links: warn unrecognized_links: warn nav: absolute_links: ignore nav: - section-index: /mkdocs-section-index/ - literate-nav: - Overview: README.md - Reference: reference.md - gen-files: /mkdocs-gen-files/ - same-dir: /mkdocs-same-dir/ - code-validator: /mkdocs-code-validator/ - callouts: /markdown-callouts/ mkdocs-literate-nav-0.6.2/mkdocs_literate_nav/000077500000000000000000000000001476636544500214315ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/mkdocs_literate_nav/__init__.py000066400000000000000000000000261476636544500235400ustar00rootroot00000000000000__version__ = "0.6.2" mkdocs-literate-nav-0.6.2/mkdocs_literate_nav/exceptions.py000066400000000000000000000000541476636544500241630ustar00rootroot00000000000000class LiterateNavError(Exception): pass mkdocs-literate-nav-0.6.2/mkdocs_literate_nav/parser.py000066400000000000000000000273231476636544500233060ustar00rootroot00000000000000from __future__ import annotations import copy import functools import itertools import logging import posixpath import urllib.parse import xml.etree.ElementTree as etree from collections.abc import Iterator from typing import TYPE_CHECKING, Callable, Optional, Union, cast import markdown import markdown.extensions import markdown.postprocessors import markdown.preprocessors import markdown.treeprocessors import mkdocs.utils from mkdocs_literate_nav import exceptions if TYPE_CHECKING: from .plugin import MkDocsGlobber log = logging.getLogger(f"mkdocs.plugins.{__name__}") _unescape: Callable[[str], str] try: _unescape = markdown.treeprocessors.UnescapeTreeprocessor().unescape except AttributeError: _unescape = markdown.postprocessors.UnescapePostprocessor().run # type: ignore[attr-defined] class Wildcard: trim_slash = False def __init__(self, *path_parts: str, fallback: bool = True): norm = posixpath.normpath(posixpath.join(*path_parts).lstrip("/")) if path_parts[-1].endswith("/") and not self.trim_slash: norm += "/" self.value = norm self.fallback = path_parts[-1] if fallback else None def __repr__(self): return f"{type(self).__name__}({self.value!r})" if TYPE_CHECKING: NavWithWildcardsItem = Union[ Wildcard, str, "NavWithWildcards", dict[Optional[str], Union[Wildcard, str, "NavWithWildcards"]], ] NavWithWildcards = list[NavWithWildcardsItem] NavItem = Union[str, dict[Optional[str], Union[str, "Nav"]]] Nav = list[NavItem] RootStack = tuple[str, ...] class DirectoryWildcard(Wildcard): trim_slash = True class NavParser: def __init__( self, get_nav_for_dir: Callable[[str], tuple[str, str] | None], globber: MkDocsGlobber, *, implicit_index: bool = False, markdown_config: dict | None = None, ): self.get_nav_for_dir = get_nav_for_dir self.globber = globber self.implicit_index = implicit_index self._markdown_config = markdown_config or {} self.seen_items: set[str] = set() self._warn = functools.lru_cache()(log.warning) def markdown_to_nav(self, roots: tuple[str, ...] = (".",)) -> Nav: root = roots[0] if dir_nav := self.get_nav_for_dir(root): nav_file_name, markdown_content = dir_nav nav = _extract_nav_from_content(self._markdown_config, markdown_content) if nav is not None: self_path = posixpath.normpath(posixpath.join(root, nav_file_name)) if not (self.implicit_index and self_path == self.globber.find_index(root)): self.seen_items.add(self_path) first_item: Wildcard | None = None if self.implicit_index: if found_index := self.globber.find_index(root): first_item = Wildcard(root, "/" + found_index, fallback=False) return self._resolve_wildcards( self._list_element_to_nav(nav, root, first_item), roots ) log.debug(f"Navigation for {root!r} will be inferred.") return self._resolve_wildcards([Wildcard(root, "*", fallback=False)], roots) def _list_element_to_nav( self, section: etree.Element, root: str, first_item: Wildcard | str | None = None ) -> NavWithWildcards: assert section.tag in _LIST_TAGS result: NavWithWildcards = [] if first_item is not None: if isinstance(first_item, str): self.seen_items.add(first_item) result.append(first_item) for item in section: assert item.tag == "li" out_title = item.text out_item: Wildcard | str | list | None = None children = _iter_children_without_tail(item) try: child = next(children) if not out_title and child.tag == "a": if link := child.get("href"): out_item = self._resolve_string_item(root, link) out_title = _unescape("".join(child.itertext())) child = next(children) if child.tag in _LIST_TAGS: out_item = self._list_element_to_nav( child, root, cast("Union[Wildcard, str, None]", out_item) ) child = next(children) except StopIteration: error = "" else: error = f"Expected no more elements, but got {_to_short_string(child)}.\n" if out_title is None: error += "Did not find any title specified." + _EXAMPLES elif out_item is None: if "*" in out_title: out_item = Wildcard(root, out_title) out_title = None else: error += "Did not find any item/section content specified." + _EXAMPLES if error: raise LiterateNavParseError(error, item) assert out_item is not None if type(out_item) in (str, list, DirectoryWildcard) and out_title is not None: result.append({out_title: out_item}) else: result.append(out_item) return result def _resolve_string_item(self, root: str, link: str) -> Wildcard | str: parsed = urllib.parse.urlsplit(link) if parsed.scheme or parsed.netloc: return link abs_link = posixpath.normpath(posixpath.join(root, link)) self.seen_items.add(abs_link) if link.endswith("/") and self.globber.isdir(abs_link): return DirectoryWildcard(root, link) return abs_link def _resolve_wildcards(self, nav: NavWithWildcards, roots: RootStack = (".",)) -> Nav: def can_recurse(new_root: str) -> bool: if new_root in roots: rec = " -> ".join(repr(r) for r in reversed((new_root, *roots))) self._warn(f"Disallowing recursion {rec}") return False return True # Ensure depth-first processing, so separate loop for recursive calls first. for entry in nav: if isinstance(entry, dict) and len(entry) == 1: [(key, val)] = entry.items() if isinstance(val, str): entry = val if isinstance(entry, str): self.seen_items.add(entry) resolved: Nav = [] for entry in nav: if isinstance(entry, dict) and len(entry) == 1: [(key, val)] = entry.items() new_val: str | Nav | None = None if isinstance(val, list): new_val = self._resolve_wildcards(val, roots) elif isinstance(val, DirectoryWildcard): new_val = ( self.markdown_to_nav((val.value, *roots)) if can_recurse(val.value) else val.fallback ) elif isinstance(val, Wildcard): new_val = self._resolve_wildcards([val], roots) or val.fallback else: new_val = val if new_val: resolved.append({key: new_val}) continue assert not isinstance(entry, (DirectoryWildcard, list, dict)) if not isinstance(entry, Wildcard): resolved.append(entry) continue any_matches = False for item in self.globber.glob(entry.value.rstrip("/")): any_matches = True if item in self.seen_items: continue if self.globber.isdir(item): title = mkdocs.utils.dirname_to_title(posixpath.basename(item)) if subitems := self.markdown_to_nav((item, *roots)): resolved.append({title: subitems}) else: if entry.value.endswith("/"): continue resolved.append({None: item}) self.seen_items.add(item) if not any_matches and entry.fallback: resolved.append(entry.fallback) return resolved def resolve_yaml_nav(self, nav) -> Nav: if not isinstance(nav, list): return nav return self._resolve_wildcards([self._resolve_yaml_nav(x) for x in nav]) def _resolve_yaml_nav(self, item) -> NavWithWildcardsItem: if isinstance(item, str) and "*" in item: return Wildcard("", item) if isinstance(item, dict): assert len(item) == 1 [(key, val)] = item.items() if isinstance(val, list): return {key: [self._resolve_yaml_nav(x) for x in val]} if isinstance(val, str): if "*" in val: return {key: Wildcard("", val)} return {key: self._resolve_string_item("", val)} return {key: val} return item def _extract_nav_from_content(markdown_config: dict, markdown_content: str) -> etree.Element | None: md = markdown.Markdown(**markdown_config) md.inlinePatterns.deregister("html", strict=False) md.inlinePatterns.deregister("entity", strict=False) preprocessor = _Preprocessor(md) preprocessor._register() treeprocessor = _Treeprocessor(md) treeprocessor._register() md.convert(markdown_content) return treeprocessor.nav class _Preprocessor(markdown.preprocessors.Preprocessor): nav_placeholder: str | None = None def run(self, lines: list[str]) -> list[str]: for i, line in enumerate(lines): if line.strip() == "": self.nav_placeholder = self.md.htmlStash.store("") lines[i] = self.nav_placeholder + "\n" return lines def _register(self) -> None: self.md.preprocessors.register(self, "mkdocs_literate_nav", priority=25) class _Treeprocessor(markdown.treeprocessors.Treeprocessor): nav: etree.Element | None = None def run(self, root: etree.Element) -> None: preprocessor: _Preprocessor = self.md.preprocessors["mkdocs_literate_nav"] # type: ignore[assignment] nav_placeholder = preprocessor.nav_placeholder items: Iterator[etree.Element] if nav_placeholder is not None: # Will look for the first list after the last . items = itertools.dropwhile(lambda el: el.text != nav_placeholder, root) else: # Will look for the last list. items = reversed(root) for el in items: if el.tag in _LIST_TAGS: self.nav = copy.deepcopy(el) break def _register(self) -> None: self.md.treeprocessors.register(self, "mkdocs_literate_nav", priority=19) _LIST_TAGS = ("ul", "ol") _EXAMPLES = """ Examples: * [Item title](item_content.md) * Section title * [Sub content](sub/content.md) * *.md """ def _iter_children_without_tail(element: etree.Element) -> Iterator[etree.Element]: for child in element: yield child if child.tail: raise LiterateNavParseError( f"Expected no text after {_to_short_string(child)}, but got {child.tail!r}.", element, ) def _to_short_string(el: etree.Element) -> str: el = copy.deepcopy(el) for child in el: if len(child): del child[:] child.text = "[...]" el.tail = None return etree.tostring(el, encoding="unicode") class LiterateNavParseError(exceptions.LiterateNavError): def __init__(self, message, el): super().__init__(message + "\nThe problematic item:\n\n" + _to_short_string(el)) mkdocs-literate-nav-0.6.2/mkdocs_literate_nav/plugin.py000066400000000000000000000123771476636544500233130ustar00rootroot00000000000000from __future__ import annotations import fnmatch import logging import os.path import re from collections.abc import Iterator from pathlib import Path, PurePosixPath from typing import TYPE_CHECKING import mkdocs.structure.files from mkdocs.config import config_options as opt from mkdocs.config.base import Config from mkdocs.plugins import BasePlugin, event_priority from mkdocs.structure.pages import Page from mkdocs_literate_nav import parser if TYPE_CHECKING: from mkdocs.config.defaults import MkDocsConfig from mkdocs.structure.files import Files from mkdocs.structure.nav import Navigation log = logging.getLogger(f"mkdocs.plugins.{__name__}") class PluginConfig(Config): nav_file = opt.Type(str, default="SUMMARY.md") implicit_index = opt.Type(bool, default=False) markdown_extensions = opt.MarkdownExtensions() tab_length = opt.Type(int, default=4) class LiterateNavPlugin(BasePlugin[PluginConfig]): @event_priority(-100) # Run last def on_files(self, files: Files, config: MkDocsConfig) -> None: config.nav = resolve_directories_in_nav( config.nav, files, nav_file_name=self.config.nav_file, implicit_index=self.config.implicit_index, markdown_config=dict( extensions=self.config.markdown_extensions, extension_configs=self.config["mdx_configs"], tab_length=self.config.tab_length, ), ) self._files = files def on_nav(self, nav: Navigation, config: MkDocsConfig, files: Files) -> None: if files != getattr(self, "_files", None): log.warning( "The literate-nav plugin created the nav based on files that were subsequently modified by another MkDocs plugin! " "Re-order `plugins` in mkdocs.yml so that 'literate-nav' appears later." ) def resolve_directories_in_nav( nav_data, files: Files, nav_file_name: str, *, implicit_index: bool, markdown_config: dict | None = None, ): """Walk through a standard MkDocs nav config and replace `directory/` references. Directories, if found, are resolved by the rules of literate nav insertion: If it has a literate nav file, that is used. Otherwise an implicit nav is generated. """ def get_nav_for_dir(path: str) -> tuple[str, str] | None: file = files.get_file_from_path(os.path.join(path, nav_file_name)) if not file: return None log.debug(f"Navigation for {path!r} based on {file.src_path!r}.") # Prevent the warning in case the user doesn't also end up including this page in # the final nav, maybe they want it only for the purpose of feeding to this plugin. try: # MkDocs 1.5+ if file.inclusion.is_in_nav(): file.inclusion = mkdocs.structure.files.InclusionLevel.NOT_IN_NAV except AttributeError: # https://github.com/mkdocs/mkdocs/blob/ff0b726056/mkdocs/structure/nav.py#L113 Page(None, file, {}) # type: ignore[arg-type] try: # MkDocs 1.6+ content = file.content_string except AttributeError: # https://github.com/mkdocs/mkdocs/blob/fa5aa4a26e/mkdocs/structure/pages.py#L120 assert file.abs_src_path is not None content = Path(file.abs_src_path).read_text(encoding="utf-8-sig") return nav_file_name, content globber = MkDocsGlobber(files) nav_parser = parser.NavParser( get_nav_for_dir, globber, implicit_index=implicit_index, markdown_config=markdown_config ) result = None if not nav_data or get_nav_for_dir("."): result = nav_parser.markdown_to_nav() return result or nav_parser.resolve_yaml_nav(nav_data or []) class MkDocsGlobber: def __init__(self, files: Files): self.files = {} # Ordered set self.dirs = {} # Ordered set self.index_dirs = {} for f in files: if not f.is_documentation_page(): continue path = PurePosixPath("/", f.src_uri) self.files[path] = True tail, head = path.parent, path.name if f.name == "index": self.index_dirs[tail] = path while True: self.dirs[tail] = True if not head: break tail, head = tail.parent, tail.name def isdir(self, path: str) -> bool: return PurePosixPath("/", path) in self.dirs def glob(self, pattern: str) -> Iterator[str]: pat_parts = PurePosixPath("/" + pattern).parts re_parts = [re.compile(fnmatch.translate(part)) for part in pat_parts] for collection in self.files, self.dirs: for path in collection: if len(path.parts) == len(re_parts): zipped = zip(path.parts, re_parts) next(zipped) # Both the path and the pattern have a slash as their first part. if all(re_part.match(part) for part, re_part in zipped): yield str(path)[1:] def find_index(self, root: str) -> str | None: root_path = PurePosixPath("/", root) if root_path in self.index_dirs: return str(self.index_dirs[root_path])[1:] return None mkdocs-literate-nav-0.6.2/mkdocs_literate_nav/py.typed000066400000000000000000000000001476636544500231160ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/pyproject.toml000066400000000000000000000142121476636544500203300ustar00rootroot00000000000000[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "mkdocs-literate-nav" description = "MkDocs plugin to specify the navigation in Markdown instead of YAML" readme = "README.md" license = "MIT" keywords = ["mkdocs", "mkdocs-plugin"] authors = [ {name = "Oleh Prypin", email = "oleh@pryp.in"}, ] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Environment :: Web Environment", "Intended Audience :: Information Technology", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", # Begin Python versions "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", # End Python versions "Topic :: Documentation", "Topic :: Software Development :: Documentation", "Topic :: Text Processing :: Markup :: Markdown", "Typing :: Typed", ] dynamic = ["version"] requires-python = ">=3.9" dependencies = [ "mkdocs >=1.4.1", ] [project.urls] Documentation = "https://oprypin.github.io/mkdocs-literate-nav/" Source = "https://github.com/oprypin/mkdocs-literate-nav" Issues = "https://github.com/oprypin/mkdocs-literate-nav/issues" History = "https://github.com/oprypin/mkdocs-literate-nav/releases" [project.entry-points."mkdocs.plugins"] literate-nav = "mkdocs_literate_nav.plugin:LiterateNavPlugin" [tool.hatch.version] path = "mkdocs_literate_nav/__init__.py" [tool.hatch.build.targets.sdist] include = ["/mkdocs_literate_nav", "/tests"] [tool.hatch.env] requires = [ "hatch-mkdocs", "hatch-pip-compile >=1.7.0", ] [tool.hatch.envs.default.scripts] all = [ "hatch run style:fix", "hatch run types:check", "hatch run test:test", ] [tool.hatch.envs.test] dependencies = [ "pytest", "pytest-golden", ] [tool.hatch.envs.test.scripts] test = [ "pytest -q {args}", ] [tool.hatch.envs.types] dependencies = [ "mypy", "types-Markdown >=3.4.2", ] [tool.hatch.envs.types.scripts] check = "mypy {args} mkdocs_literate_nav" [tool.hatch.envs.style] type = "pip-compile" detached = true dependencies = [ "ruff", ] [tool.hatch.envs.style.scripts] check = "ruff check mkdocs_literate_nav tests {args}" format = "ruff format -q mkdocs_literate_nav tests" fix = [ "check --fix --unsafe-fixes", "format", ] [tool.hatch.env.collectors.mkdocs.docs] [tool.hatch.envs.docs] type = "pip-compile" [tool.ruff] line-length = 100 [tool.ruff.lint] preview = true select = [ "F", "E", "W", "I", "UP", "YTT", "ASYNC", "FBT", "C4", "DTZ", "T10", "FA", "ISC", "PIE", "T20", "RSE", "N803", "N804", "N805", "N806", "N807", "N815", "N816", "N999", "S201", "S202", "S303", "S304", "S305", "S306", "S506", "S602", "S604", "S605", "S612", "B002", "B003", "B004", "B005", "B007", "B008", "B009", "B010", "B011", "B012", "B013", "B014", "B015", "B016", "B017", "B018", "B019", "B020", "B021", "B022", "B023", "B025", "B026", "B029", "B030", "B031", "B032", "B033", "B034", "B035", "B039", "B905", "B909", "B911", "COM818", "LOG001", "LOG007", "LOG009", "LOG015", "G001", "G002", "G003", "G010", "G101", "G201", "G202", "PYI001", "PYI002", "PYI003", "PYI004", "PYI005", "PYI006", "PYI007", "PYI008", "PYI009", "PYI010", "PYI011", "PYI012", "PYI013", "PYI014", "PYI015", "PYI016", "PYI017", "PYI018", "PYI019", "PYI020", "PYI021", "PYI024", "PYI025", "PYI026", "PYI029", "PYI030", "PYI032", "PYI033", "PYI034", "PYI035", "PYI036", "PYI041", "PYI042", "PYI043", "PYI044", "PYI045", "PYI046", "PYI047", "PYI048", "PYI049", "PYI050", "PYI051", "PYI052", "PYI053", "PYI054", "PYI055", "PYI056", "PYI057", "PYI058", "PYI059", "PYI061", "PYI062", "PYI063", "PYI064", "PYI066", "PT001", "PT002", "PT003", "PT006", "PT007", "PT008", "PT009", "PT010", "PT013", "PT014", "PT015", "PT016", "PT018", "PT019", "PT020", "PT021", "PT022", "PT023", "PT024", "PT025", "PT026", "PT027", "Q004", "RET502", "RET503", "RET504", "SIM101", "SIM103", "SIM105", "SIM107", "SIM109", "SIM110", "SIM113", "SIM114", "SIM118", "SIM201", "SIM202", "SIM208", "SIM210", "SIM211", "SIM212", "SIM220", "SIM221", "SIM222", "SIM223", "SIM300", "SIM401", "SIM905", "SIM910", "SIM911", "TC001", "TC002", "TC003", "TC004", "TC005", "TC006", "TC007", "TC008", "TC010", "PTH201", "TD004", "TD005", "TD006", "TD007", "PGH003", "PGH004", "PGH005", "PLC0105", "PLC0131", "PLC0132", "PLC0205", "PLC0206", "PLC0208", "PLC0414", "PLC2401", "PLC2403", "PLC2701", "PLC2801", "PLC3002", "PLR0124", "PLR0133", "PLR0202", "PLR0203", "PLR0206", "PLR0402", "PLR1716", "PLR1722", "PLR1733", "PLR1736", "PLR2044", "PLR6301", "TRY201", "TRY203", "TRY401", "FLY002", "PERF101", "PERF102", "PERF402", "PERF403", "FURB105", "FURB110", "FURB116", "FURB118", "FURB129", "FURB131", "FURB132", "FURB136", "FURB142", "FURB145", "FURB148", "FURB154", "FURB156", "FURB157", "FURB161", "FURB163", "FURB164", "FURB166", "FURB167", "FURB168", "FURB169", "FURB171", "FURB177", "FURB180", "FURB181", "FURB188", "FURB192", "RUF001", "RUF002", "RUF003", "RUF005", "RUF006", "RUF007", "RUF008", "RUF009", "RUF010", "RUF012", "RUF013", "RUF015", "RUF016", "RUF017", "RUF018", "RUF019", "RUF020", "RUF021", "RUF022", "RUF023", "RUF024", "RUF026", "RUF028", "RUF029", "RUF030", "RUF031", "RUF032", "RUF033", "RUF034", "RUF035", "RUF036", "RUF037", "RUF038", "RUF039", "RUF040", "RUF041", "RUF043", "RUF046", "RUF047", "RUF048", "RUF049", "RUF051", "RUF052", "RUF055", "RUF056", "RUF057", "RUF058", "RUF100", "RUF101", "RUF200", ] ignore = ["E501", "E731", "UP038"] [tool.ruff.lint.per-file-ignores] "tests/**" = ["PLC2701", "PLR6301"] [tool.ruff.lint.flake8-comprehensions] allow-dict-calls-with-keyword-arguments = true [tool.ruff.lint.flake8-type-checking] exempt-modules = ["typing", "collections.abc"] [tool.mypy] warn_unreachable = true allow_redefinition = true [tool.pytest.ini_options] addopts = "--tb=native" enable_assertion_pass_hook = true filterwarnings = ["ignore::DeprecationWarning:.*:", "default::DeprecationWarning:mkdocs_literate_nav.*:"] testpaths = ["tests"] mkdocs-literate-nav-0.6.2/requirements/000077500000000000000000000000001476636544500201375ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/requirements/requirements-docs.txt000066400000000000000000000031731476636544500243550ustar00rootroot00000000000000# # This file is autogenerated by hatch-pip-compile with Python 3.12 # # - markdown-callouts # - mkdocs # - mkdocs-material # - pymdown-extensions # babel==2.16.0 # via mkdocs-material certifi==2024.8.30 # via requests charset-normalizer==3.4.0 # via requests click==8.1.7 # via mkdocs colorama==0.4.6 # via mkdocs-material ghp-import==2.1.0 # via mkdocs idna==3.10 # via requests jinja2==3.1.4 # via # mkdocs # mkdocs-material markdown==3.7 # via # markdown-callouts # mkdocs # mkdocs-material # pymdown-extensions markdown-callouts==0.4.0 # via hatch.envs.docs markupsafe==3.0.2 # via # jinja2 # mkdocs mergedeep==1.3.4 # via # mkdocs # mkdocs-get-deps mkdocs==1.6.1 # via # hatch.envs.docs # mkdocs-material mkdocs-get-deps==0.2.0 # via mkdocs mkdocs-material==9.5.47 # via hatch.envs.docs mkdocs-material-extensions==1.3.1 # via mkdocs-material packaging==24.2 # via mkdocs paginate==0.5.7 # via mkdocs-material pathspec==0.12.1 # via mkdocs platformdirs==4.3.6 # via mkdocs-get-deps pygments==2.18.0 # via mkdocs-material pymdown-extensions==10.12 # via # hatch.envs.docs # mkdocs-material python-dateutil==2.9.0.post0 # via ghp-import pyyaml==6.0.2 # via # mkdocs # mkdocs-get-deps # pymdown-extensions # pyyaml-env-tag pyyaml-env-tag==0.1 # via mkdocs regex==2024.11.6 # via mkdocs-material requests==2.32.3 # via mkdocs-material six==1.17.0 # via python-dateutil urllib3==2.2.3 # via requests watchdog==6.0.0 # via mkdocs mkdocs-literate-nav-0.6.2/requirements/requirements-style.txt000066400000000000000000000001721476636544500245610ustar00rootroot00000000000000# # This file is autogenerated by hatch-pip-compile with Python 3.13 # # - ruff # ruff==0.9.6 # via hatch.envs.style mkdocs-literate-nav-0.6.2/tests/000077500000000000000000000000001476636544500165565ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/tests/conftest.py000066400000000000000000000003701476636544500207550ustar00rootroot00000000000000from mkdocs.structure.files import File def pytest_assertrepr_compare(op, left, right): if isinstance(left, File) and isinstance(right, File) and op == "==": return [f"File({left.src_path}) != File({right.src_path})"] return None mkdocs-literate-nav-0.6.2/tests/nav/000077500000000000000000000000001476636544500173425ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/tests/nav/hybrid/000077500000000000000000000000001476636544500206235ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_empty.yml000066400000000000000000000000251476636544500235400ustar00rootroot00000000000000files: {} output: [] mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_files_in_subsection.yml000066400000000000000000000004561476636544500264400ustar00rootroot00000000000000nav: - foo/*: # Just acts as the title anyway - Foo: foo/ - bar/ # Doesn't exist, OK. files: foo/xxx.md: foo/yyy.md: foo/zzz.md: foo/bar/zzz.md: output: - foo/*: - Foo: - null: foo/xxx.md - null: foo/yyy.md - null: foo/zzz.md - Bar: - null: foo/bar/zzz.md - bar/ mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_flattened_files_in_subsection.yml000066400000000000000000000004311476636544500304570ustar00rootroot00000000000000nav: - foo/*: # Just acts as the title anyway - foo/* - bar/* # Doesn't exist, OK. files: foo/xxx.md: foo/yyy.md: foo/zzz.md: foo/bar/zzz.md: output: - foo/*: - null: foo/xxx.md - null: foo/yyy.md - null: foo/zzz.md - Bar: - null: foo/bar/zzz.md - bar/* mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_from_readme.yml000066400000000000000000000005051476636544500246650ustar00rootroot00000000000000nav: - Foo: foo.md - Usual: - usual/a.md - usual/b.md - '*.md' - Subdir: subdir/ files: bar.md: baz.md: foo.md: subdir/x.md: subdir/y.md: usual/a.md: usual/b.md: output: - Foo: foo.md - Usual: - usual/a.md - usual/b.md - null: bar.md - null: baz.md - Subdir: - null: subdir/x.md - null: subdir/y.md mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_keeps_original_nav.yml000066400000000000000000000002021476636544500262360ustar00rootroot00000000000000nav: - hi-hi: /ho-ho - test: test/ - sub: - Test: foo.md files: {} output: - hi-hi: /ho-ho - test: test - sub: - Test: foo.md mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_literate_in_subsection.yml000066400000000000000000000002451476636544500271430ustar00rootroot00000000000000nav: - foo/: - Bar: bar/ # Doesn't exist, OK. - Foo: foo/ files: foo/SUMMARY.md: | * [Hi](ho.md) output: - foo/: - Bar: bar - Foo: - Hi: foo/ho.md mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_nav_and_literate.yml000066400000000000000000000001131476636544500256770ustar00rootroot00000000000000nav: - foo.md files: SUMMARY.md: | * [Hi](ho.md) output: - Hi: ho.md mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_preserves_url.yml000066400000000000000000000001611476636544500253030ustar00rootroot00000000000000nav: - https://example.org/ - Foo: http://example.com/ output: - https://example.org/ - Foo: http://example.com/ mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_repeated.yml000066400000000000000000000002601476636544500241740ustar00rootroot00000000000000nav: - Foo: foo/ - Bar: bar/ # Doesn't exist, OK - Foo: foo/ files: foo/SUMMARY.md: | * [Hi](ho.md) output: - Foo: - Hi: foo/ho.md - Bar: bar - Foo: - Hi: foo/ho.md mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_slash_with_nav.yml000066400000000000000000000001201476636544500254070ustar00rootroot00000000000000nav: - '*' files: SUMMARY.md: | * [Hi](ho.md) a.md: output: - Hi: ho.md mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_very_nested.yml000066400000000000000000000004361476636544500247370ustar00rootroot00000000000000nav: - Foo: - Bar: - Baz: aa/aa/aa/ files: aa/aa/aa/SUMMARY.md: | * [test](bb/bb/bb.md) * [test](/aa/) aa/cc/cc/cc.md: output: - Foo: - Bar: - Baz: - test: aa/aa/aa/bb/bb/bb.md - test: - Cc: - Cc: - null: aa/cc/cc/cc.md mkdocs-literate-nav-0.6.2/tests/nav/hybrid/test_wildcard_slash.yml000066400000000000000000000001111476636544500253610ustar00rootroot00000000000000nav: - '*/' files: a.md: foo/c.md: output: - Foo: - null: foo/c.md mkdocs-literate-nav-0.6.2/tests/nav/nested/000077500000000000000000000000001476636544500206245ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/tests/nav/nested/test_basic.yml000066400000000000000000000004761476636544500234760ustar00rootroot00000000000000files: SUMMARY.md: | 1. Section 1 * [Item1](item1.md) * [Item2](item2.md) 2. [Section 2](section2/) item1.md: item2.md: section2/SUMMARY.md: | * [Item](item.md) section2/item.md: output: - Section 1: - Item1: item1.md - Item2: item2.md - Section 2: - Item: section2/item.md mkdocs-literate-nav-0.6.2/tests/nav/nested/test_borgs.yml000066400000000000000000000004721476636544500235250ustar00rootroot00000000000000files: index.md: SUMMARY.md: | * [Frob](index.md) * [Baz](baz.md) * [Borgs](borgs/) baz.md: borgs/index.md: borgs/SUMMARY.md: | * [Bar](bar.md) * [Foo](foo.md) borgs/bar.md: borgs/foo.md: output: - Frob: index.md - Baz: baz.md - Borgs: - Bar: borgs/bar.md - Foo: borgs/foo.md mkdocs-literate-nav-0.6.2/tests/nav/nested/test_dir_without_slash.yml000066400000000000000000000001311476636544500261340ustar00rootroot00000000000000files: SUMMARY.md: | * [Foo](foo) foo/index.md: foo/bar.md: output: - Foo: foo mkdocs-literate-nav-0.6.2/tests/nav/nested/test_go_up.yml000066400000000000000000000005071476636544500235210ustar00rootroot00000000000000files: SUMMARY.md: | * [item](item.md) * [Sub1](sub1/) item.md: item2.md: sub1/SUMMARY.md: | * [item1](item1.md) * [Sub2](../sub2/) sub1/item1.md: sub2/index.md: sub2/SUMMARY.md: | * [item2](../item2.md) output: - item: item.md - Sub1: - item1: sub1/item1.md - Sub2: - item2: item2.md mkdocs-literate-nav-0.6.2/tests/nav/nested/test_go_up_too_much.yml000066400000000000000000000004601476636544500254140ustar00rootroot00000000000000files: SUMMARY.md: | * [item](item.md) * [Sub1](sub1/) item.md: sub1/SUMMARY.md: | * [item1](item1.md) * [Sub2](../../sub2/) sub1/item1.md: sub2/SUMMARY.md: | * [item2](../item2.md) sub2/item2.md: output: - item: item.md - Sub1: - item1: sub1/item1.md - Sub2: ../sub2 mkdocs-literate-nav-0.6.2/tests/nav/nested/test_implicit_index_as_nav.yml000066400000000000000000000005071476636544500267400ustar00rootroot00000000000000files: index.md: | * [Baz](baz.md) * [Borgs](borgs/) baz.md: borgs/index.md: | * [Bar](bar.md) * [Foo](foo.md) borgs/bar.md: borgs/foo.md: implicit_index: true nav_file_name: index.md output: - null: index.md - Baz: baz.md - Borgs: - null: borgs/index.md - Bar: borgs/bar.md - Foo: borgs/foo.md mkdocs-literate-nav-0.6.2/tests/nav/nested/test_implicit_index_borgs.yml000066400000000000000000000005211476636544500266010ustar00rootroot00000000000000files: index.md: SUMMARY.md: | * [Baz](baz.md) * [Borgs](borgs/) baz.md: borgs/index.md: borgs/SUMMARY.md: | * [Bar](bar.md) * [Foo](foo.md) borgs/bar.md: borgs/foo.md: implicit_index: true output: - null: index.md - Baz: baz.md - Borgs: - null: borgs/index.md - Bar: borgs/bar.md - Foo: borgs/foo.md mkdocs-literate-nav-0.6.2/tests/nav/nested/test_missing.yml000066400000000000000000000001451476636544500240570ustar00rootroot00000000000000files: SUMMARY.md: | * [Foo](foo/) bar/SUMMARY.md: | * [Section 2](/) output: - Foo: foo mkdocs-literate-nav-0.6.2/tests/nav/nested/test_nested.yml000066400000000000000000000012161476636544500236700ustar00rootroot00000000000000files: SUMMARY.md: | * Foo * Bar * [item](item.md) * [Sub](sub/) item.md: sub/SUMMARY.md: | * Foo * Bar * [item](item.md) * [Sub](sub/) sub/item.md: sub/sub/SUMMARY.md: | * Foo * Bar * [item](item.md) * [Sub](sub/) sub/sub/item.md: sub/sub/sub/item.md: output: - Foo: - Bar: - item: item.md - Sub: - Foo: - Bar: - item: sub/item.md - Sub: - Foo: - Bar: - item: sub/sub/item.md - Sub: - null: sub/sub/sub/item.md mkdocs-literate-nav-0.6.2/tests/nav/nested/test_recursion.yml000066400000000000000000000023661476636544500244260ustar00rootroot00000000000000files: SUMMARY.md: | 1. Section 1 * [Item1](item1.md) * [Item2](item2.md) 2. [Section 2](section2/) 3. [Section 3](section3/) item1.md: item2.md: section2/index.md: section2/SUMMARY.md: | * [Section 2](/) * [Section 2](//) * [Section 2](./) * [Section 2](../section2/) * [Section 3](../section3/) * [Section 1](..) section3/index.md: section3/SUMMARY.md: | * [Section 2](../section2/) output: - Section 1: - Item1: item1.md - Item2: item2.md - Section 2: - Section 2: / - Section 2: // - Section 2: ./ - Section 2: ../section2/ - Section 3: - Section 2: ../section2/ - Section 1: . - Section 3: - Section 2: - Section 2: / - Section 2: // - Section 2: ./ - Section 2: ../section2/ - Section 3: ../section3/ - Section 1: . logs: - WARNING:Disallowing recursion '.' -> 'section2' -> '.' - WARNING:Disallowing recursion '.' -> 'section2' -> 'section2' - WARNING:Disallowing recursion '.' -> 'section2' -> 'section3' -> 'section2' - WARNING:Disallowing recursion '.' -> 'section3' -> 'section2' -> '.' - WARNING:Disallowing recursion '.' -> 'section3' -> 'section2' -> 'section2' - WARNING:Disallowing recursion '.' -> 'section3' -> 'section2' -> 'section3' mkdocs-literate-nav-0.6.2/tests/nav/nested/test_repeated.yml000066400000000000000000000005601476636544500242000ustar00rootroot00000000000000files: SUMMARY.md: | * Foo * [item](item.md) * [Sub](sub/) * [Sub](sub/) * [Sub](sub/) item.md: sub/SUMMARY.md: | * Bar * [item](item.md) sub/item.md: output: - Foo: - item: item.md - Sub: - Bar: - item: sub/item.md - Sub: - Bar: - item: sub/item.md - Sub: - Bar: - item: sub/item.md mkdocs-literate-nav-0.6.2/tests/nav/test_basic.yml000066400000000000000000000003711476636544500222060ustar00rootroot00000000000000files: SUMMARY.md: | 1. Section 1 * [Item1](item1.md) * [Item2](item2.md) 2. Section 2 * [Item](section2/item.md) output: - Section 1: - Item1: item1.md - Item2: item2.md - Section 2: - Item: section2/item.md mkdocs-literate-nav-0.6.2/tests/nav/test_broken_before_marker.yml000066400000000000000000000004211476636544500252640ustar00rootroot00000000000000files: SUMMARY.md: | * foo * Section 1 * [Item1](item1.md) * [Item2](item2.md) * Section 2 * [Item](section2/item.md) output: - Section 1: - Item1: item1.md - Item2: item2.md - Section 2: - Item: section2/item.md mkdocs-literate-nav-0.6.2/tests/nav/test_element_after.yml000066400000000000000000000004431476636544500237370ustar00rootroot00000000000000files: SUMMARY.md: | 1. Section 1 * [Item1](item1.md)[Item2](item2.md) exception: LiterateNavParseError: |- Expected no more elements, but got Item2. The problematic item:
  • Item1Item2
  • mkdocs-literate-nav-0.6.2/tests/nav/test_empty.yml000066400000000000000000000000631476636544500222610ustar00rootroot00000000000000files: SUMMARY.md: '' output: - null: SUMMARY.md mkdocs-literate-nav-0.6.2/tests/nav/test_empty_section.yml000066400000000000000000000005701476636544500240100ustar00rootroot00000000000000files: SUMMARY.md: | 1. Section 1 2. Section 2 * [Item](section2/item.md) exception: LiterateNavParseError: |- Did not find any item/section content specified. Examples: * [Item title](item_content.md) * Section title * [Sub content](sub/content.md) * *.md The problematic item:
  • Section 1
  • mkdocs-literate-nav-0.6.2/tests/nav/test_fancy_link.yml000066400000000000000000000004031476636544500232360ustar00rootroot00000000000000files: SUMMARY.md: | 1. Section 1 * [Item **1**](item1.md) * [Item 2](item2.md) 2. Section 2 * [`Item`](section2/item.md) output: - Section 1: - Item 1: item1.md - Item 2: item2.md - Section 2: - Item: section2/item.md mkdocs-literate-nav-0.6.2/tests/nav/test_multiple_nav.yml000066400000000000000000000001641476636544500236240ustar00rootroot00000000000000files: SUMMARY.md: | * [Foo](foo.md) * [Bar](bar.md) output: - Bar: bar.md mkdocs-literate-nav-0.6.2/tests/nav/test_multiple_nav_and_others.yml000066400000000000000000000002321476636544500260260ustar00rootroot00000000000000files: SUMMARY.md: | * [A](a.md) hi * [B](a.md) * [C](C.md) hi * [D](D.md) output: - C: C.md mkdocs-literate-nav-0.6.2/tests/nav/test_multiple_unmarked_nav.yml000066400000000000000000000001361476636544500255110ustar00rootroot00000000000000files: SUMMARY.md: | * [Foo](foo.md) hi * [Bar](bar.md) output: - Bar: bar.md mkdocs-literate-nav-0.6.2/tests/nav/test_nav_after_gap.yml000066400000000000000000000001661476636544500237230ustar00rootroot00000000000000files: SUMMARY.md: | * [Foo](foo.md) Hi Hmm * [Bar](bar.md) output: - Bar: bar.md mkdocs-literate-nav-0.6.2/tests/nav/test_nav_last.yml000066400000000000000000000001261476636544500227320ustar00rootroot00000000000000files: SUMMARY.md: | * [Foo](foo.md) output: - null: SUMMARY.md mkdocs-literate-nav-0.6.2/tests/nav/test_no_title.yml000066400000000000000000000005131476636544500227400ustar00rootroot00000000000000files: SUMMARY.md: | 1. * [Item](section2/item.md) exception: LiterateNavParseError: |- Did not find any title specified. Examples: * [Item title](item_content.md) * Section title * [Sub content](sub/content.md) * *.md The problematic item:
  • mkdocs-literate-nav-0.6.2/tests/nav/test_obscured_link.yml000066400000000000000000000010101476636544500237370ustar00rootroot00000000000000files: SUMMARY.md: | 1. Section 1 * [Item1](item1.md) * **[Item2](item2.md)** 2. Section 2 * [Item](section2/item.md) exception: LiterateNavParseError: |- Expected no more elements, but got Item2. Did not find any title specified. Examples: * [Item title](item_content.md) * Section title * [Sub content](sub/content.md) * *.md The problematic item:
  • [...]
  • mkdocs-literate-nav-0.6.2/tests/nav/test_obscured_section.yml000066400000000000000000000007741476636544500244660ustar00rootroot00000000000000files: SUMMARY.md: | 1. Section 1 * [Item1](item1.md) * [Item2](item2.md) 2. Section *2* * [Item](section2/item.md) exception: LiterateNavParseError: |- Expected no more elements, but got 2. Did not find any item/section content specified. Examples: * [Item title](item_content.md) * Section title * [Sub content](sub/content.md) * *.md The problematic item:
  • Section 2
  • mkdocs-literate-nav-0.6.2/tests/nav/test_preserves_url.yml000066400000000000000000000003401476636544500240210ustar00rootroot00000000000000files: SUMMARY.md: | - [hi](https://example.org/) - hello - [Foo](http://example.com/) - [other](test.md) output: - hi: https://example.org/ - hello: - Foo: http://example.com/ - other: test.md mkdocs-literate-nav-0.6.2/tests/nav/test_section_with_link.yml000066400000000000000000000004301476636544500246350ustar00rootroot00000000000000files: SUMMARY.md: | 1. [Section 1](section1.md) * [Item1](item1.md) * [Item2](item2.md) 2. Section 2 * [Item](section2/item.md) output: - Section 1: - section1.md - Item1: item1.md - Item2: item2.md - Section 2: - Item: section2/item.md mkdocs-literate-nav-0.6.2/tests/nav/test_special_chars.yml000066400000000000000000000003351476636544500237250ustar00rootroot00000000000000files: SUMMARY.md: | * [a&b](a.md) * [a&b](b.md) * [a&amp;b](c.md) * [\__init__](d.md) * [\`hi`](e.md) output: - a&b: a.md - a&b: b.md - a&amp;b: c.md - __init__: d.md - '`hi`': e.md mkdocs-literate-nav-0.6.2/tests/nav/test_text_after.yml000066400000000000000000000003761476636544500232770ustar00rootroot00000000000000files: SUMMARY.md: | 1. Section 1 * [Item1](item1.md)foo exception: LiterateNavParseError: |- Expected no text after Item1, but got 'foo'. The problematic item:
  • Item1foo
  • mkdocs-literate-nav-0.6.2/tests/nav/wildcard/000077500000000000000000000000001476636544500211335ustar00rootroot00000000000000mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_basic.yml000066400000000000000000000002341476636544500237750ustar00rootroot00000000000000files: SUMMARY.md: | - * item1.md: item2.md: section2/item.md: output: - null: item1.md - null: item2.md - Section2: - null: section2/item.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_dirs_then_files.yml000066400000000000000000000002501476636544500260530ustar00rootroot00000000000000files: SUMMARY.md: | - */ - *.md item1.md: item2.md: section2/item.md: output: - Section2: - null: section2/item.md - null: item1.md - null: item2.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_from_readme.yml000066400000000000000000000012641476636544500252000ustar00rootroot00000000000000files: index.md: SUMMARY.md: | - [Welcome](index.md) - Usage - [Foo](usage/foo.md) - usage/*.md - */ - *.md - [API docs](api/) - [License](license.md) changelog.md: credits.md: api/Foo.md: api/Bar/index.md: api/Bar/Baz.md: tips/other-stuff.md: tips/stuff.md: usage/bar.md: usage/baz.md: usage/foo.md: output: - Welcome: index.md - Usage: - Foo: usage/foo.md - null: usage/bar.md - null: usage/baz.md - Tips: - null: tips/other-stuff.md - null: tips/stuff.md - null: changelog.md - null: credits.md - API docs: - null: api/Foo.md - Bar: - null: api/Bar/index.md - null: api/Bar/Baz.md - License: license.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_implicitly_recursive.yml000066400000000000000000000002571476636544500271670ustar00rootroot00000000000000files: SUMMARY.md: | - foo/* foo/a.md: foo/bar/index.md: foo/bar/SUMMARY.md: | - [stuff](index.md) output: - null: foo/a.md - Bar: - stuff: foo/bar/index.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_multidir_file.yml000066400000000000000000000001761476636544500255510ustar00rootroot00000000000000files: SUMMARY.md: | - */foo.md aaa/bar.md: aaa/foo.md: bbb/foo.md: output: - null: aaa/foo.md - null: bbb/foo.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_no_files.yml000066400000000000000000000000521476636544500245100ustar00rootroot00000000000000files: SUMMARY.md: | - * output: [] mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_no_repeat_with_directory.yml000066400000000000000000000002341476636544500300070ustar00rootroot00000000000000files: SUMMARY.md: | - * - [sub](sub/index.md) - [a](a.md) a.md: b.md: sub/index.md: output: - null: b.md - sub: sub/index.md - a: a.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_non_matching.yml000066400000000000000000000001411476636544500253550ustar00rootroot00000000000000files: SUMMARY.md: | - [A](a.md) - a*.md - b*.md a.md: output: - A: a.md - b*.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_omits_competing_parent_first.yml000066400000000000000000000003251476636544500306750ustar00rootroot00000000000000files: SUMMARY.md: | - sub/*.md - [sub](sub/) sub/index.md: sub/SUMMARY.md: | - *.md sub/a.md: sub/b.md: output: - null: sub/index.md - null: sub/SUMMARY.md - null: sub/a.md - null: sub/b.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_omits_competing_subdir_first.yml000066400000000000000000000003131476636544500306710ustar00rootroot00000000000000files: SUMMARY.md: | - [sub](sub/) - sub/*.md sub/index.md: sub/SUMMARY.md: | - *.md sub/a.md: sub/b.md: output: - sub: - null: sub/index.md - null: sub/a.md - null: sub/b.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_omits_in_subdir.yml000066400000000000000000000004041476636544500261040ustar00rootroot00000000000000files: SUMMARY.md: | - [a](sub/a.md) - [sub](sub/) - [b](sub/b.md) - *.md sub/index.md: sub/SUMMARY.md: | - *.md sub/a.md: sub/b.md: sub/c.md: output: - a: sub/a.md - sub: - null: sub/index.md - null: sub/c.md - b: sub/b.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_omits_in_superdir.yml000066400000000000000000000003651476636544500264570ustar00rootroot00000000000000files: SUMMARY.md: | - [sub](sub/) - sub/*.md sub/index.md: sub/SUMMARY.md: | - [a](a.md) - [b](b.md) sub/a.md: sub/b.md: sub/c.md: output: - sub: - a: sub/a.md - b: sub/b.md - null: sub/index.md - null: sub/c.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_skips_nav_file.yml000066400000000000000000000003431476636544500257110ustar00rootroot00000000000000files: SUMMARY.md: | - *.md - [Sub](subdir/) - subother/* foo.md: subdir/SUMMARY.md: | - * subdir/bar.md: subother/baz.md: output: - null: foo.md - Sub: - null: subdir/bar.md - null: subother/baz.md mkdocs-literate-nav-0.6.2/tests/nav/wildcard/test_wildcard_under_index.yml000066400000000000000000000003541476636544500270740ustar00rootroot00000000000000files: index.md: SUMMARY.md: | - [b](b/index.md) - [stuff](b/stuff.md) - b/*.md b/index.md: b/a.md: b/stuff.md: b/z.md: output: - b: - b/index.md - stuff: b/stuff.md - null: b/a.md - null: b/z.md mkdocs-literate-nav-0.6.2/tests/test_plugin.py000066400000000000000000000027231476636544500214710ustar00rootroot00000000000000import pathlib import pytest from mkdocs.structure.files import File, Files from mkdocs_literate_nav import exceptions, plugin @pytest.mark.golden_test("nav/**/*.yml") def test_nav(tmp_path_factory, golden): src_dir, dest_dir = map(tmp_path_factory.mktemp, ["src", "dest"]) files = [] for fn, content in (golden.get("files") or {}).items(): path = src_dir / fn path.parent.mkdir(parents=True, exist_ok=True) if content is not None: path.write_text(content, encoding="utf-8") files.append(File(fn, src_dir, dest_dir, use_directory_urls=len(golden.path.name) % 2)) assert [f.src_path for f in sorted(files, key=file_sort_key)] == [f.src_path for f in files] files = Files(files) output = None with golden.may_raise(exceptions.LiterateNavError): with golden.capture_logs("mkdocs.plugins.mkdocs_literate_nav"): output = plugin.resolve_directories_in_nav( golden.get("nav"), files, nav_file_name=golden.get("nav_file_name") or "SUMMARY.md", implicit_index=golden.get("implicit_index"), ) assert output == golden.out.get("output") # https://github.com/oprypin/mkdocs-gen-files/blob/71a4825d5c/mkdocs_gen_files/editor.py#L16 def file_sort_key(f: File): parts = pathlib.PurePath(f.src_path).parts return tuple( chr(f.name != "index" if i == len(parts) - 1 else 2) + p for i, p in enumerate(parts) )