Skip to content

Commit 3b76ec6

Browse files
authored
♻️ REFACTOR: toc file top-level structure (#12)
The root file is now specified under the `root` key, and the initial `parts`/`sections` are at the top-level
1 parent 574458f commit 3b76ec6

16 files changed

+115
-133
lines changed

README.md

Lines changed: 52 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
[![Coverage Status][codecov-badge]][codecov-link]
55
[![Code style: black][black-badge]][black-link]
66

7-
A sphinx extension that allows the documentation toctree to be defined in a single file.
7+
A sphinx extension that allows the documentation site-map (a.k.a Table of Contents) to be defined external to the documentation files.
88

9-
In normal Sphinx documentation, the documentation structure is defined *via* a bottom-up approach - adding [`toctree` directives](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#table-of-contents) within pages of the documentation.
9+
In normal Sphinx documentation, the documentation site-map is defined *via* a bottom-up approach - adding [`toctree` directives](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#table-of-contents) within pages of the documentation.
1010

11-
This extension facilitates a **top-down** approach to defining the Table of Contents (ToC) structure, within a single YAML file that is external to the documentation.
11+
This extension facilitates a **top-down** approach to defining the site-map structure, within a single YAML file.
1212

1313
## User Guide
1414

@@ -24,24 +24,23 @@ external_toc_exclude_missing = False # optional, default: False
2424

2525
### Basic Structure
2626

27-
A minimal ToC defines the top level `main` key, and a single root document file:
27+
A minimal ToC defines the top level `root` key, for a single root document file:
2828

2929
```yaml
30-
main:
31-
file: intro
30+
root: intro
3231
```
3332
34-
The value of the `file` key will be a path to a file, in Unix format (folders split by `/`), relative to the source directory, and can be with or without the file extension.
33+
The value of the `root` key will be a path to a file, in Unix format (folders split by `/`), relative to the source directory, and can be with or without the file extension.
3534

3635
:::{note}
3736
This root file will be set as the [`master_doc`](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-master_doc).
3837
:::
3938

4039
Document files can then have a `parts` key - denoting a list of individual toctrees for that document - and in-turn each part should have a `sections` key - denoting a list of children links, that are one of: `file`, `url` or `glob`:
4140

42-
- `file`: relating to a single document file (see above)
43-
- `glob`: relating to one or more document files *via* Unix shell-style wildcards (similar to [`fnmatch`](https://docs.python.org/3/library/fnmatch.html), but single stars don't match slashes.)
44-
- `url`: relating to an external URL (e.g. `http` or `https`)
41+
- `file`: path to a single document file in Unix format, with or without the file extension (as for `root`)
42+
- `glob`: path to one or more document files *via* Unix shell-style wildcards (similar to [`fnmatch`](https://docs.python.org/3/library/fnmatch.html), but single stars don't match slashes.)
43+
- `url`: path for an external URL (starting e.g. `http` or `https`)
4544

4645
:::{important}
4746
Each document file can only occur once in the ToC!
@@ -50,16 +49,18 @@ Each document file can only occur once in the ToC!
5049
This can proceed recursively to any depth.
5150

5251
```yaml
53-
main:
54-
file: intro
55-
parts:
56-
- sections:
57-
- file: doc1
58-
parts:
59-
- sections:
60-
- file: doc2
61-
- url: https://example.com
62-
- glob: subfolder/other*
52+
root: intro
53+
parts:
54+
- sections:
55+
- file: doc1
56+
parts:
57+
- sections:
58+
- file: doc2
59+
parts:
60+
- sections:
61+
- file: doc3
62+
- url: https://example.com
63+
- glob: subfolder/other*
6364
```
6465

6566
This is equivalent to having a single `toctree` directive in `intro`, containing `doc1`,
@@ -69,47 +70,46 @@ As a shorthand, the `sections` key can be at the same level as the `file`, which
6970
For example, this file is exactly equivalent to the one above:
7071

7172
```yaml
72-
main:
73-
file: intro
73+
root: intro
74+
sections:
75+
- file: doc1
7476
sections:
75-
- file: doc1
77+
- file: doc2
7678
sections:
77-
- file: doc2
78-
- url: https://example.com
79-
- glob: subfolder/other*
79+
- file: doc3
80+
- url: https://example.com
81+
- glob: subfolder/other*
8082
```
8183

8284
### Titles and Captions
8385

8486
By default, ToCs will use the initial header within a document as its title.
8587

86-
With the `title` key you can set an alternative title for a document or URL.
88+
With the `title` key you can set an alternative title for a document or URL in the ToC.
8789
Each part can also have a `caption`, e.g. for use in ToC side-bars:
8890

8991
```yaml
90-
main:
91-
file: intro
92-
title: Introduction
93-
parts:
94-
- caption: Part Caption
95-
sections:
96-
- file: doc1
97-
- url: https://example.com
98-
title: Example Site
92+
root: intro
93+
parts:
94+
- caption: Part Caption
95+
sections:
96+
- file: doc1
97+
title: Document 1
98+
- url: https://example.com
99+
title: Example Site
99100
```
100101

101102
### Numbering
102103

103104
You can automatically add numbers to all docs with a part by adding the `numbered: true` flag to it:
104105

105106
```yaml
106-
main:
107-
file: intro
108-
parts:
109-
- numbered: true
110-
sections:
111-
- file: doc1
112-
- file: doc2
107+
root: intro
108+
parts:
109+
- numbered: true
110+
sections:
111+
- file: doc1
112+
- file: doc2
113113
```
114114

115115
You can also **limit the TOC numbering depth** by setting the `numbered` flag to an integer instead of `true`, e.g., `numbered: 3`.
@@ -126,13 +126,12 @@ To have e.g. `numbered` added to all toctrees, set it under a `defaults` top-lev
126126
```yaml
127127
defaults:
128128
numbered: true
129-
main:
130-
file: intro
129+
root: intro
130+
sections:
131+
- file: doc1
131132
sections:
132-
- file: doc1
133-
sections:
134-
- file: doc2
135-
- url: https://example.com
133+
- file: doc2
134+
- url: https://example.com
136135
```
137136

138137
Available keys: `numbered`, `titlesonly`, `reversed`
@@ -192,10 +191,9 @@ $ sphinx-etoc create-site -p path/to/site -e rst path/to/_toc.yml
192191
Note, you can also add additional files in `meta`/`create_files` amd append text to the end of files with `meta`/`create_append`, e.g.
193192

194193
```yaml
195-
main:
196-
file: intro
197-
sections:
198-
- glob: doc*
194+
root: intro
195+
sections:
196+
- glob: doc*
199197
meta:
200198
create_append:
201199
intro: |
@@ -236,7 +234,7 @@ intro:
236234
sections:
237235
- doc1
238236
titlesonly: true
239-
title: Introduction
237+
title: null
240238
```
241239

242240
## Development Notes

docs/_toc.yml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
defaults:
22
numbered: 3
33
titlesonly: false
4-
main:
5-
file: intro
6-
title: Introduction
7-
parts:
8-
- sections:
9-
- file: doc1
10-
- file: doc2
11-
sections:
12-
- file: subfolder/doc3
13-
- url: https://example.com
14-
title: Example Link
15-
- sections:
16-
- glob: subglobs/glob*
4+
root: intro
5+
parts:
6+
- caption: Part 1
7+
sections:
8+
- file: doc1
9+
- file: doc2
10+
sections:
11+
- file: subfolder/doc3
12+
- url: https://example.com
13+
title: Example Link
14+
- caption: Part 2
15+
sections:
16+
- glob: subglobs/glob*

sphinx_external_toc/api.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -158,24 +158,21 @@ def parse_toc_data(data: Dict[str, Any]) -> SiteMap:
158158
"""Parse a dictionary of the ToC."""
159159
defaults: Dict[str, Any] = data.get("defaults", {})
160160

161-
if "main" not in data:
162-
raise MalformedError("'main' key not present")
163-
164-
doc_item, docs_list = _parse_doc_item(data["main"], defaults, "main/")
161+
doc_item, docs_list = _parse_doc_item(data, defaults, "/", file_key="root")
165162

166163
site_map = SiteMap(root=doc_item, meta=data.get("meta"))
167164

168-
_parse_docs_list(docs_list, site_map, defaults, "main/")
165+
_parse_docs_list(docs_list, site_map, defaults, "/")
169166

170167
return site_map
171168

172169

173170
def _parse_doc_item(
174-
data: Dict[str, Any], defaults: Dict[str, Any], path: str
171+
data: Dict[str, Any], defaults: Dict[str, Any], path: str, file_key: str = "file"
175172
) -> Tuple[DocItem, Sequence[Dict[str, Any]]]:
176173
"""Parse a single doc item."""
177-
if "file" not in data:
178-
raise MalformedError(f"'file' key not found: '{path}'")
174+
if file_key not in data:
175+
raise MalformedError(f"'{file_key}' key not found: '{path}'")
179176
if "sections" in data:
180177
# this is a shorthand for defining a single part
181178
if "parts" in data:
@@ -224,7 +221,7 @@ def _parse_doc_item(
224221
# TODO this is a hacky fix for the fact that sphinx logs a warning
225222
# for nested toctrees, see:
226223
# sphinx/environment/collectors/toctree.py::TocTreeCollector::assign_section_numbers::_walk_toctree
227-
if keywords.get("numbered") and path != "main/":
224+
if keywords.get("numbered") and path != "/":
228225
keywords.pop("numbered")
229226

230227
try:
@@ -234,7 +231,7 @@ def _parse_doc_item(
234231
parts.append(toc_item)
235232

236233
try:
237-
doc_item = DocItem(docname=data["file"], title=data.get("title"), parts=parts)
234+
doc_item = DocItem(docname=data[file_key], title=data.get("title"), parts=parts)
238235
except TypeError as exc:
239236
raise MalformedError(f"doc validation: {path}") from exc
240237

tests/_toc_files/basic.yml

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
defaults:
22
numbered: true
3-
main:
4-
file: intro
5-
title: Introduction
6-
parts:
7-
- caption: Part Caption
8-
sections:
9-
- file: doc1
10-
- file: doc2
11-
- file: doc3
12-
parts:
13-
- sections:
14-
- file: subfolder/doc4
15-
- url: https://example.com
3+
root: intro
4+
parts:
5+
- caption: Part Caption
6+
sections:
7+
- file: doc1
8+
- file: doc2
9+
- file: doc3
10+
parts:
11+
- sections:
12+
- file: subfolder/doc4
13+
- url: https://example.com
1614
meta:
1715
regress: intro
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
defaults:
22
numbered: true
3-
main:
4-
file: intro
5-
title: Introduction
3+
root: intro
4+
sections:
5+
- file: doc1
6+
- file: doc2
7+
- file: doc3
68
sections:
7-
- file: doc1
8-
- file: doc2
9-
- file: doc3
10-
sections:
11-
- file: doc4
12-
- url: https://example.com
9+
- file: doc4
10+
- url: https://example.com
1311
meta:
1412
regress: intro

tests/_toc_files/exclude_missing.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
main:
2-
file: intro
3-
sections:
4-
- file: doc1
5-
- glob: subfolder/other*
1+
root: intro
2+
sections:
3+
- file: doc1
4+
- glob: subfolder/other*
65
meta:
76
create_files:
87
- doc2

tests/_toc_files/glob.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
main:
2-
file: intro
3-
title: Introduction
4-
sections:
5-
- glob: doc*
1+
root: intro
2+
sections:
3+
- glob: doc*
64
meta:
75
create_files:
86
- doc1

tests/_toc_files/tableofcontents.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
main:
2-
file: intro
3-
parts:
4-
- sections:
5-
- file: doc1
6-
- sections:
7-
- file: doc2
1+
root: intro
2+
parts:
3+
- sections:
4+
- file: doc1
5+
- sections:
6+
- file: doc2
87
meta:
98
create_append:
109
intro: |

tests/_warning_toc_files/contains_toctree.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
main:
2-
file: intro
1+
root: intro
32
meta:
43
create_files:
54
- doc1

tests/_warning_toc_files/file_not_in_toc.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
main:
2-
file: intro
1+
root: intro
32
meta:
43
create_files:
54
- doc1

0 commit comments

Comments
 (0)