Skip to content

feat(toc): warn about headings that skip a level - #187

Merged
ekalinin merged 2 commits into
masterfrom
feat/skipped-level-warning
Oct 30, 2026
Merged

ekalinin merged 2 commits into
masterfrom
feat/skipped-level-warning

Conversation

@ekalinin

Copy link
Copy Markdown
Owner

Summary

Fixes #75: when a heading skips a level (# First followed by ### Third), GitHub
renders its TOC entry as text of the parent entry, on one line (First * Third).

The TOC does not change. For every TOC entry whose heading level is more than one level
deeper than its parent, a line goes to stderr:

Warning: heading 'Skipped' (level 3) skips a level after 'Title two' (level 1), see https://github.com/ekalinin/github-markdown-toc/issues/75

How GitHub renders a skipped level today (checked with the markdown API):

marker indent # -> ### # -> ####
* 2 nested list one line
* 3 (default) one line one line
* 4 one line one line
1. 3 nested list one line
  • gh-md-toc (common_awk_script in gh_toc_grab, shared by the default and OS/390
    branches):
    • The parent is the nearest previous entry with a lower level, the same one the
      --numbered outline numbers use: the check runs right after the stack of outline
      numbers pops down to it. Entries without a parent (### before ##) get no
      warning. With --depth, only the entries in the TOC are checked.
    • The warning goes to stderr through | "cat 1>&2" (POSIX), so it never ends up in
      the TOC that --insert writes or in the output of --stdout. The exit code does
      not change.
    • With several inputs, the line starts with the input:
      tests/test directory/test_numbered.md: Warning: ....
  • tests/tests.bats: 7 new tests (#75). bats run merges stderr into lines, so
    the three existing tests on test_numbered.md now run gh-md-toc through a new helper
    without stderr; their assertions do not change.
  • openspec: the add-skipped-level-warning change (proposal, design, specs, tasks),
    not archived yet.

Not included: a change of the TOC for skipped levels (an indent by the depth in the
heading tree, or placeholder entries for the missing levels); a warning only when GitHub
actually renders the TOC wrong (with --indent 2 or --numbered list, one skipped
level is still rendered as a nested list, and the warning is printed anyway); a document
whose first heading is deeper than a later one with --indent 4 or more; an option to
turn the warning off.

Testing

  • The 5 new warning tests fail without the change; all 57 tests pass with it (macOS,
    BSD awk 20200816).
  • stdout for README.md, every fixture, the printf inputs from the spec and the four
    remote pages from the remote-toc spec is byte-for-byte the same as with the script
    from master; stderr is empty for all of them except test_numbered.md and the
    printf inputs.
  • make lint passes.
  • Not checked locally: mawk (CI) and OS/390 awk.

Fixes #75. When a heading skips a level (`# First` followed by
`### Third`), GitHub renders its TOC entry as text of the parent entry,
on one line. The TOC does not change; for every such entry a warning
goes to stderr:
`Warning: heading 'Third' (level 3) skips a level after 'First' (level 1), see https://github.com/ekalinin/github-markdown-toc/issues/75`
@ekalinin
ekalinin merged commit 6f2164a into master Oct 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TOC becomes ugly if some heading level is missing

1 participant