diff options
author | pennae <github@quasiparticle.net> | 2023-02-18 20:48:12 +0100 |
---|---|---|
committer | pennae <github@quasiparticle.net> | 2023-02-21 18:26:40 +0100 |
commit | 768794d6c11b5e37f954405a3f03d63ef45897f6 (patch) | |
tree | cd1b0a40f0b9fa739f19b732a4d58729b5a2fe52 /pkgs/tools/nix/nixos-render-docs | |
parent | 163b667352e19411473fdf8603f0883c1b106d58 (diff) | |
download | nixpkgs-768794d6c11b5e37f954405a3f03d63ef45897f6.tar nixpkgs-768794d6c11b5e37f954405a3f03d63ef45897f6.tar.gz nixpkgs-768794d6c11b5e37f954405a3f03d63ef45897f6.tar.bz2 nixpkgs-768794d6c11b5e37f954405a3f03d63ef45897f6.tar.lz nixpkgs-768794d6c11b5e37f954405a3f03d63ef45897f6.tar.xz nixpkgs-768794d6c11b5e37f954405a3f03d63ef45897f6.tar.zst nixpkgs-768794d6c11b5e37f954405a3f03d63ef45897f6.zip |
nixos-render-docs: check book structure
text content in the toplevel file of a book will not render properly. the first proper element will be a preface, part, or chapter anyway, and those require includes to produce. parts do not currently allow headings in the part file itself, but that's mainly a renderer limitation. we can add support for headings in part intros when we need them in all other cases includes must be followed by either another include, a heading, or end of file. text content could not be properly linked to from a TOC without a preceding heading.
Diffstat (limited to 'pkgs/tools/nix/nixos-render-docs')
-rw-r--r-- | pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual.py | 6 | ||||
-rw-r--r-- | pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual_structure.py | 43 |
2 files changed, 45 insertions, 4 deletions
diff --git a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual.py b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual.py index 7e1923f35ec..858ecad9c11 100644 --- a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual.py +++ b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual.py @@ -12,7 +12,7 @@ from markdown_it.token import Token from . import md, options from .docbook import DocBookRenderer, Heading -from .manual_structure import check_titles, FragmentType, TocEntryType +from .manual_structure import check_structure, FragmentType, is_include, TocEntryType from .md import Converter class BaseConverter(Converter[md.TR], Generic[md.TR]): @@ -30,9 +30,9 @@ class BaseConverter(Converter[md.TR], Generic[md.TR]): def _parse(self, src: str) -> list[Token]: tokens = super()._parse(src) - check_titles(self._current_type[-1], tokens) + check_structure(self._current_type[-1], tokens) for token in tokens: - if token.type != "fence" or not token.info.startswith("{=include=} "): + if not is_include(token): continue typ = token.info[12:].strip() if typ == 'options': diff --git a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual_structure.py b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual_structure.py index 32b6287b34a..93a8ecc3f93 100644 --- a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual_structure.py +++ b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual_structure.py @@ -8,7 +8,41 @@ FragmentType = Literal['preface', 'part', 'chapter', 'section', 'appendix'] # in the TOC all fragments are allowed, plus the all-encompassing book. TocEntryType = Literal['book', 'preface', 'part', 'chapter', 'section', 'appendix'] -def check_titles(kind: TocEntryType, tokens: Sequence[Token]) -> None: +def is_include(token: Token) -> bool: + return token.type == "fence" and token.info.startswith("{=include=} ") + +# toplevel file must contain only the title headings and includes, anything else +# would cause strange rendering. +def _check_book_structure(tokens: Sequence[Token]) -> None: + for token in tokens[6:]: + if not is_include(token): + assert token.map + raise RuntimeError(f"unexpected content in line {token.map[0] + 1}, " + "expected structural include") + +# much like books, parts may not contain headings other than their title heading. +# this is a limitation of the current renderers that do not handle this case well +# even though it is supported in docbook (and probably supportable anywhere else). +def _check_part_structure(tokens: Sequence[Token]) -> None: + _check_fragment_structure(tokens) + for token in tokens[3:]: + if token.type == 'heading_open': + assert token.map + raise RuntimeError(f"unexpected heading in line {token.map[0] + 1}") + +# two include blocks must either be adjacent or separated by a heading, otherwise +# we cannot generate a correct TOC (since there'd be nothing to link to between +# the two includes). +def _check_fragment_structure(tokens: Sequence[Token]) -> None: + for i, token in enumerate(tokens): + if is_include(token) \ + and i + 1 < len(tokens) \ + and not (is_include(tokens[i + 1]) or tokens[i + 1].type == 'heading_open'): + assert token.map + raise RuntimeError(f"unexpected content in line {token.map[0] + 1}, " + "expected heading or structural include") + +def check_structure(kind: TocEntryType, tokens: Sequence[Token]) -> None: wanted = { 'h1': 'title' } wanted |= { 'h2': 'subtitle' } if kind == 'book' else {} for (i, (tag, role)) in enumerate(wanted.items()): @@ -46,3 +80,10 @@ def check_titles(kind: TocEntryType, tokens: Sequence[Token]) -> None: raise RuntimeError(f"heading in line {token.map[0] + 1} skips one or more heading levels, " "which is currently not allowed") last_heading_level = level + + if kind == 'book': + _check_book_structure(tokens) + elif kind == 'part': + _check_part_structure(tokens) + else: + _check_fragment_structure(tokens) |