From 09e0ae43ef8fddc85919e1529d08bebbfee66675 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Sun, 4 Oct 2026 13:14:29 +0200 Subject: [PATCH] doc/nav: add explicit ids to every doc resource We need stable resource ids for docs.nixos.org this commit enrolls initial resource ids for every documented 'thing' leaf id are inert for now group ids are targets for open state html output is not effected by this change yet --- doc/nav.json | 219 ++++++++++++++++-- nixos/doc/manual/default.nix | 12 +- nixos/doc/manual/nav.json | 154 ++++++++++-- .../src/nixos_render_docs/manual.py | 7 +- .../src/tests/test_manual.py | 13 +- 5 files changed, 361 insertions(+), 44 deletions(-) diff --git a/doc/nav.json b/doc/nav.json index 4fd503ed9d8f..9c07f5e82114 100644 --- a/doc/nav.json +++ b/doc/nav.json @@ -2,598 +2,776 @@ "open": [], "items": [ { + "id": "preface", "file": "preface.chapter.md" }, { - "label": "Getting started", "id": "getting-started", + "label": "Getting started", "children": [ { + "id": "index", "file": "getting-started/getting-started.part.md" }, { + "id": "first-package", "file": "getting-started/first-package.chapter.md" }, { + "id": "dev-environments", "file": "getting-started/dev-environments.md" } ] }, { - "label": "Guides", "id": "guides", + "label": "Guides", "children": [ { + "id": "using-nixpkgs", "file": "using-nixpkgs.md" }, { + "id": "channels", "file": "channels.chapter.md" }, { + "id": "platform-support", "file": "using/platform-support.chapter.md" }, { + "id": "configuration", "file": "using/configuration.chapter.md" }, { + "id": "overlays", "file": "using/overlays.chapter.md" }, { + "id": "overrides", "file": "using/overrides.chapter.md" }, { + "id": "stdenv", "label": "Standard environment", - "id": "part-stdenv", "children": [ { + "id": "index", "file": "stdenv.md" }, { + "id": "stdenv", "file": "stdenv/stdenv.chapter.md" }, { + "id": "meta", "file": "stdenv/meta.chapter.md" }, { + "id": "passthru", "file": "stdenv/passthru.chapter.md" }, { + "id": "multiple-output", "file": "stdenv/multiple-output.chapter.md" }, { + "id": "cross-compilation", "file": "stdenv/cross-compilation.chapter.md" }, { + "id": "platform-notes", "file": "stdenv/platform-notes.chapter.md" } ] }, { + "id": "languages", "label": "Languages and frameworks", - "id": "chap-language-support", "children": [ { + "id": "index", "file": "languages-frameworks/index.md" }, { + "id": "agda", "file": "languages-frameworks/agda.section.md" }, { + "id": "android", "file": "languages-frameworks/android.section.md" }, { + "id": "astal", "file": "languages-frameworks/astal.section.md" }, { + "id": "beam", "file": "languages-frameworks/beam.section.md" }, { + "id": "chicken", "file": "languages-frameworks/chicken.section.md" }, { + "id": "cosmic", "file": "languages-frameworks/cosmic.section.md" }, { + "id": "crystal", "file": "languages-frameworks/crystal.section.md" }, { + "id": "cuda", "file": "languages-frameworks/cuda.section.md" }, { + "id": "cuelang", "file": "languages-frameworks/cuelang.section.md" }, { + "id": "dart", "file": "languages-frameworks/dart.section.md" }, { + "id": "dhall", "file": "languages-frameworks/dhall.section.md" }, { + "id": "dlang", "file": "languages-frameworks/dlang.section.md" }, { + "id": "dotnet", "file": "languages-frameworks/dotnet.section.md" }, { + "id": "emscripten", "file": "languages-frameworks/emscripten.section.md" }, { + "id": "factor", "file": "languages-frameworks/factor.section.md" }, { + "id": "gnome", "file": "languages-frameworks/gnome.section.md" }, { + "id": "go", "file": "languages-frameworks/go.section.md" }, { + "id": "gradle", "file": "languages-frameworks/gradle.section.md" }, { + "id": "hare", "file": "languages-frameworks/hare.section.md" }, { + "id": "haskell", "file": "languages-frameworks/haskell.section.md" }, { + "id": "hy", "file": "languages-frameworks/hy.section.md" }, { + "id": "idris", "file": "languages-frameworks/idris.section.md" }, { + "id": "idris2", "file": "languages-frameworks/idris2.section.md" }, { + "id": "ios", "file": "languages-frameworks/ios.section.md" }, { + "id": "java", "file": "languages-frameworks/java.section.md" }, { + "id": "javascript", "file": "languages-frameworks/javascript.section.md" }, { + "id": "julia", "file": "languages-frameworks/julia.section.md" }, { + "id": "lean4", "file": "languages-frameworks/lean4.section.md" }, { + "id": "lisp", "file": "languages-frameworks/lisp.section.md" }, { + "id": "lua", "file": "languages-frameworks/lua.section.md" }, { + "id": "maven", "file": "languages-frameworks/maven.section.md" }, { + "id": "nim", "file": "languages-frameworks/nim.section.md" }, { + "id": "ocaml", "file": "languages-frameworks/ocaml.section.md" }, { + "id": "octave", "file": "languages-frameworks/octave.section.md" }, { + "id": "perl", "file": "languages-frameworks/perl.section.md" }, { + "id": "php", "file": "languages-frameworks/php.section.md" }, { + "id": "pkg-config", "file": "languages-frameworks/pkg-config.section.md" }, { + "id": "python", "file": "languages-frameworks/python.section.md" }, { + "id": "qt", "file": "languages-frameworks/qt.section.md" }, { + "id": "r", "file": "languages-frameworks/r.section.md" }, { + "id": "rocq", "file": "languages-frameworks/rocq.section.md" }, { + "id": "ruby", "file": "languages-frameworks/ruby.section.md" }, { + "id": "rust", "file": "languages-frameworks/rust.section.md" }, { + "id": "scheme", "file": "languages-frameworks/scheme.section.md" }, { + "id": "swift", "file": "languages-frameworks/swift.section.md" }, { + "id": "tcl", "file": "languages-frameworks/tcl.section.md" }, { + "id": "texlive", "file": "languages-frameworks/texlive.section.md" }, { + "id": "typst", "file": "languages-frameworks/typst.section.md" }, { + "id": "vim", "file": "languages-frameworks/vim.section.md" }, { + "id": "neovim", "file": "languages-frameworks/neovim.section.md" } ] }, { + "id": "toolchains", "label": "Toolchains", - "id": "part-toolchains", "children": [ { + "id": "index", "file": "toolchains.md" }, { + "id": "llvm", "file": "toolchains/llvm.chapter.md" } ] }, { + "id": "build-helpers", "label": "Build helpers", - "id": "part-builders", "children": [ { + "id": "index", "file": "build-helpers.md" }, { + "id": "fixed-point-arguments", "file": "build-helpers/fixed-point-arguments.chapter.md" }, { + "id": "fetchers", "file": "build-helpers/fetchers.chapter.md" }, { + "id": "trivial-build-helpers", "file": "build-helpers/trivial-build-helpers.chapter.md" }, { + "id": "testers", "file": "build-helpers/testers.chapter.md" }, { + "id": "dev-shell-tools", "file": "build-helpers/dev-shell-tools.chapter.md" }, { + "id": "special", "label": "Special build helpers", - "id": "chap-special", "children": [ { + "id": "index", "file": "build-helpers/special.md" }, { + "id": "buildenv", "file": "build-helpers/special/buildenv.section.md" }, { + "id": "fakenss", "file": "build-helpers/special/fakenss.section.md" }, { + "id": "fhs-environments", "file": "build-helpers/special/fhs-environments.section.md" }, { + "id": "makesetuphook", "file": "build-helpers/special/makesetuphook.section.md" }, { + "id": "mkshell", "file": "build-helpers/special/mkshell.section.md" }, { + "id": "vm-tools", "file": "build-helpers/special/vm-tools.section.md" }, { + "id": "checkpoint-build", "file": "build-helpers/special/checkpoint-build.section.md" } ] }, { + "id": "images", "label": "Images", - "id": "chap-images", "children": [ { + "id": "index", "file": "build-helpers/images.md" }, { + "id": "appimagetools", "file": "build-helpers/images/appimagetools.section.md" }, { + "id": "dockertools", "file": "build-helpers/images/dockertools.section.md" }, { + "id": "ocitools", "file": "build-helpers/images/ocitools.section.md" }, { + "id": "portableservice", "file": "build-helpers/images/portableservice.section.md" }, { + "id": "makediskimage", "file": "build-helpers/images/makediskimage.section.md" }, { + "id": "binarycache", "file": "build-helpers/images/binarycache.section.md" } ] }, { + "id": "hooks", "label": "Hooks reference", - "id": "chap-hooks", "children": [ { + "id": "index", "file": "hooks/index.md" }, { + "id": "autoconf", "file": "hooks/autoconf.section.md" }, { + "id": "automake", "file": "hooks/automake.section.md" }, { + "id": "autopatchcil", "file": "hooks/autopatchcil.section.md" }, { + "id": "autopatchelf", "file": "hooks/autopatchelf.section.md" }, { + "id": "aws-c-common", "file": "hooks/aws-c-common.section.md" }, { + "id": "bmake", "file": "hooks/bmake.section.md" }, { + "id": "breakpoint", "file": "hooks/breakpoint.section.md" }, { + "id": "cernlib", "file": "hooks/cernlib.section.md" }, { + "id": "check-phase-thread-limit-hook", "file": "hooks/check-phase-thread-limit-hook.section.md" }, { + "id": "cmake", "file": "hooks/cmake.section.md" }, { + "id": "desktop-file-utils", "file": "hooks/desktop-file-utils.section.md" }, { + "id": "gdk-pixbuf", "file": "hooks/gdk-pixbuf.section.md" }, { + "id": "gnome", "file": "hooks/gnome.section.md" }, { + "id": "haredo", "file": "hooks/haredo.section.md" }, { + "id": "installagentskills", "file": "hooks/installAgentSkills.section.md" }, { + "id": "installshellfiles", "file": "hooks/installShellFiles.section.md" }, { + "id": "installfonts", "file": "hooks/installFonts.section.md" }, { + "id": "juce", "file": "hooks/juce.section.md" }, { + "id": "julec", "file": "hooks/julec.section.md" }, { + "id": "just", "file": "hooks/just.section.md" }, { + "id": "libglycin", "file": "hooks/libglycin.section.md" }, { + "id": "libiconv", "file": "hooks/libiconv.section.md" }, { + "id": "libxml2", "file": "hooks/libxml2.section.md" }, { + "id": "memcached-test-hook", "file": "hooks/memcached-test-hook.section.md" }, { + "id": "meson", "file": "hooks/meson.section.md" }, { + "id": "mpi-check-hook", "file": "hooks/mpi-check-hook.section.md" }, { + "id": "ninja", "file": "hooks/ninja.section.md" }, { + "id": "nodejs-install-executables", "file": "hooks/nodejs-install-executables.section.md" }, { + "id": "nodejs-install-manuals", "file": "hooks/nodejs-install-manuals.section.md" }, { + "id": "npm-build-hook", "file": "hooks/npm-build-hook.section.md" }, { + "id": "npm-config-hook", "file": "hooks/npm-config-hook.section.md" }, { + "id": "npm-install-hook", "file": "hooks/npm-install-hook.section.md" }, { + "id": "patch-rc-path-hooks", "file": "hooks/patch-rc-path-hooks.section.md" }, { + "id": "perl", "file": "hooks/perl.section.md" }, { + "id": "pkg-config", "file": "hooks/pkg-config.section.md" }, { + "id": "postgresql-test-hook", "file": "hooks/postgresql-test-hook.section.md" }, { + "id": "premake", "file": "hooks/premake.section.md" }, { + "id": "python", "file": "hooks/python.section.md" }, { + "id": "redis-test-hook", "file": "hooks/redis-test-hook.section.md" }, { + "id": "scons", "file": "hooks/scons.section.md" }, { + "id": "tauri", "file": "hooks/tauri.section.md" }, { + "id": "tetex-tex-live", "file": "hooks/tetex-tex-live.section.md" }, { + "id": "udevcheckhook", "file": "hooks/udevCheckHook.section.md" }, { + "id": "unzip", "file": "hooks/unzip.section.md" }, { + "id": "validatepkgconfig", "file": "hooks/validatePkgConfig.section.md" }, { + "id": "versioncheckhook", "file": "hooks/versionCheckHook.section.md" }, { + "id": "waf", "file": "hooks/waf.section.md" }, { + "id": "writable-tmpdir-as-home-hook", "file": "hooks/writable-tmpdir-as-home-hook.section.md" }, { + "id": "zig", "file": "hooks/zig.section.md" }, { + "id": "xcbuild", "file": "hooks/xcbuild.section.md" }, { + "id": "xfce4-dev-tools", "file": "hooks/xfce4-dev-tools.section.md" } ] }, { + "id": "packages", "label": "Packages", - "id": "chap-packages", "children": [ { + "id": "index", "file": "packages/index.md" }, { + "id": "citrix", "file": "packages/citrix.section.md" }, { + "id": "darwin-builder", "file": "packages/darwin-builder.section.md" }, { + "id": "dlib", "file": "packages/dlib.section.md" }, { + "id": "eclipse", "file": "packages/eclipse.section.md" }, { + "id": "elm", "file": "packages/elm.section.md" }, { + "id": "emacs", "file": "packages/emacs.section.md" }, { + "id": "firefox", "file": "packages/firefox.section.md" }, { + "id": "friction-graphics", "file": "packages/friction-graphics.section.md" }, { + "id": "fish", "file": "packages/fish.section.md" }, { + "id": "fuse", "file": "packages/fuse.section.md" }, { + "id": "geant4", "file": "packages/geant4.section.md" }, { + "id": "ibus", "file": "packages/ibus.section.md" }, { + "id": "inkscape", "file": "packages/inkscape.section.md" }, { + "id": "kakoune", "file": "packages/kakoune.section.md" }, { + "id": "krita", "file": "packages/krita.section.md" }, { + "id": "linux", "file": "packages/linux.section.md" }, { + "id": "lhapdf", "file": "packages/lhapdf.section.md" }, { + "id": "locales", "file": "packages/locales.section.md" }, { + "id": "etc-files", "file": "packages/etc-files.section.md" }, { + "id": "nginx", "file": "packages/nginx.section.md" }, { + "id": "nrfutil", "file": "packages/nrfutil.section.md" }, { + "id": "opengl", "file": "packages/opengl.section.md" }, { + "id": "packer", "file": "packages/packer.section.md" }, { + "id": "shell-helpers", "file": "packages/shell-helpers.section.md" }, { + "id": "python-tree-sitter", "file": "packages/python-tree-sitter.section.md" }, { - "label": "treefmt", "id": "treefmt", + "label": "treefmt", "children": [ { + "id": "index", "file": "packages/treefmt.section.md" }, { + "id": "treefmt-functions", "id-prefix": "auto-generated-treefmt-functions", "file": "packages/treefmt-functions.section.md" } ] }, { + "id": "steam", "file": "packages/steam.section.md" }, { + "id": "cataclysm-dda", "file": "packages/cataclysm-dda.section.md" }, { + "id": "urxvt", "file": "packages/urxvt.section.md" }, { + "id": "vcpkg", "file": "packages/vcpkg.section.md" }, { + "id": "weechat", "file": "packages/weechat.section.md" }, { + "id": "uv", "file": "packages/uv.section.md" }, { + "id": "build-support", "file": "packages/build-support.md" } ] @@ -601,13 +779,15 @@ ] }, { - "label": "Modules", "id": "modules", + "label": "Modules", "children": [ { + "id": "index", "file": "modules/index.md" }, { + "id": "generic", "file": "modules/generic.chapter.md" } ] @@ -615,16 +795,19 @@ ] }, { - "label": "Reference", "id": "reference", + "label": "Reference", "children": [ { + "id": "lib", "file": "lib.md" }, { + "id": "functions", "file": "functions.md" }, { + "id": "library", "file": "functions/library.md" }, { @@ -632,28 +815,35 @@ "type": "nixdoc" }, { + "id": "generators", "file": "functions/generators.section.md" }, { + "id": "debug", "file": "functions/debug.section.md" }, { + "id": "prefer-remote-fetch", "file": "functions/prefer-remote-fetch.section.md" }, { + "id": "nix-gitignore", "file": "functions/nix-gitignore.section.md" }, { + "id": "module-system", "file": "module-system/module-system.chapter.md" }, { + "id": "interoperability", "label": "Interoperability Standards", - "id": "part-interoperability", "children": [ { + "id": "index", "file": "interoperability.md" }, { + "id": "cyclonedx", "file": "interoperability/cyclonedx.md" } ] @@ -661,6 +851,7 @@ ] }, { + "id": "contributing", "file": "contributing.md" } ] diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index e894bcab5fd7..07deebc32b46 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -18,6 +18,7 @@ let evalModules hasPrefix removePrefix + removeSuffix flip foldr types @@ -41,6 +42,13 @@ let prefixesToStrip = map (p: "${toString p}/") ([ prefix ] ++ extraSources); stripAnyPrefixes = flip (foldr removePrefix) prefixesToStrip; + moduleChapterId = + p: + let + stem = removeSuffix ".nix" (baseNameOf p.file); + in + if stem == "default" then baseNameOf (dirOf p.file) else stem; + optionsDoc = buildPackages.nixosOptionsDoc { inherit options @@ -113,7 +121,9 @@ let --replace-fail \ '"@MODULE_CHAPTERS@"' \ ${escapeShellArg ( - concatMapStringsSep ",\n" (p: ''{ "file": "${p.value}" }'') (sortOn (p: p.file) config.meta.doc) + concatMapStringsSep ",\n" (p: ''{ "id": "${moduleChapterId p}", "file": "${p.value}" }'') ( + sortOn (p: p.file) config.meta.doc + ) )} substituteInPlace ./nixos-options.md \ --replace-fail \ diff --git a/nixos/doc/manual/nav.json b/nixos/doc/manual/nav.json index bab2e4cb7bb1..d956c6028d5a 100644 --- a/nixos/doc/manual/nav.json +++ b/nixos/doc/manual/nav.json @@ -2,251 +2,311 @@ "open": [], "items": [ { + "id": "preface", "file": "preface.md" }, { + "id": "getting-started", "label": "Getting started", - "id": "ch-installation", "children": [ { + "id": "index", "file": "installation/installation.md" }, { + "id": "obtaining", "file": "installation/obtaining.chapter.md" }, { + "id": "installing", "label": "Installing NixOS", - "id": "sec-installation", "children": [ { + "id": "index", "file": "installation/installing.chapter.md" }, { + "id": "installing-usb", "file": "installation/installing-usb.section.md" }, { + "id": "installing-pxe", "file": "installation/installing-pxe.section.md" }, { + "id": "installing-kexec", "file": "installation/installing-kexec.section.md" }, { + "id": "installing-virtualbox-guest", "file": "installation/installing-virtualbox-guest.section.md" }, { + "id": "installing-from-other-distro", "file": "installation/installing-from-other-distro.section.md" }, { + "id": "installing-behind-a-proxy", "file": "installation/installing-behind-a-proxy.section.md" } ] }, { + "id": "changing-config", "file": "installation/changing-config.chapter.md" }, { + "id": "upgrading", "file": "installation/upgrading.chapter.md" } ] }, { + "id": "guides", "label": "Guides", - "id": "ch-configuration", "children": [ { + "id": "index", "file": "configuration/configuration.md" }, { + "id": "configuration-syntax", "label": "Configuration Syntax", - "id": "sec-configuration-syntax", "children": [ { + "id": "index", "file": "configuration/config-syntax.chapter.md" }, { + "id": "config-file", "file": "configuration/config-file.section.md" }, { + "id": "abstractions", "file": "configuration/abstractions.section.md" }, { + "id": "modularity", "file": "configuration/modularity.section.md" } ] }, { + "id": "package-management", "label": "Package Management", - "id": "sec-package-management", "children": [ { + "id": "index", "file": "configuration/package-mgmt.chapter.md" }, { + "id": "declarative-packages", "file": "configuration/declarative-packages.section.md" }, { + "id": "customizing-packages", "file": "configuration/customizing-packages.section.md" }, { + "id": "adding-custom-packages", "file": "configuration/adding-custom-packages.section.md" }, { + "id": "ad-hoc-packages", "file": "configuration/ad-hoc-packages.section.md" } ] }, { + "id": "user-mgmt", "file": "configuration/user-mgmt.chapter.md" }, { + "id": "file-systems", "label": "File Systems", - "id": "ch-file-systems", "children": [ { + "id": "index", "file": "configuration/file-systems.chapter.md" }, { + "id": "luks-file-systems", "file": "configuration/luks-file-systems.section.md" }, { + "id": "sshfs-file-systems", "file": "configuration/sshfs-file-systems.section.md" }, { + "id": "nfs-file-systems", "file": "configuration/nfs-file-systems.section.md" }, { + "id": "overlayfs", "file": "configuration/overlayfs.section.md" } ] }, { + "id": "networking", "label": "Networking", - "id": "sec-networking", "children": [ { + "id": "index", "file": "configuration/networking.chapter.md" }, { + "id": "network-manager", "file": "configuration/network-manager.section.md" }, { + "id": "ssh", "file": "configuration/ssh.section.md" }, { + "id": "ipv4-config", "file": "configuration/ipv4-config.section.md" }, { + "id": "ipv6-config", "file": "configuration/ipv6-config.section.md" }, { + "id": "firewall", "file": "configuration/firewall.section.md" }, { + "id": "wireless", "file": "configuration/wireless.section.md" }, { + "id": "ad-hoc-network-config", "file": "configuration/ad-hoc-network-config.section.md" }, { + "id": "renaming-interfaces", "file": "configuration/renaming-interfaces.section.md" } ] }, { + "id": "desktops", "label": "Graphical Desktops", - "id": "sec-x11", "children": [ { + "id": "index", "file": "configuration/x-windows.chapter.md" }, { + "id": "wayland", "file": "configuration/wayland.chapter.md" }, { + "id": "gpu-accel", "file": "configuration/gpu-accel.chapter.md" }, { + "id": "xfce", "file": "configuration/xfce.chapter.md" } ] }, { + "id": "building-images", "label": "Building Images", - "id": "sec-building-image", "children": [ { + "id": "index", "file": "installation/building-nixos.chapter.md" }, { + "id": "building-images-via-nixos-rebuild-build-image", "file": "installation/building-images-via-nixos-rebuild-build-image.chapter.md" }, { + "id": "building-images-via-systemd-repart", "file": "installation/building-images-via-systemd-repart.chapter.md" } ] }, { + "id": "administration", "label": "Administration", - "id": "ch-running", "children": [ { + "id": "index", "file": "administration/running.md" }, { + "id": "service-mgmt", "file": "administration/service-mgmt.chapter.md" }, { + "id": "rebooting", "file": "administration/rebooting.chapter.md" }, { + "id": "user-sessions", "file": "administration/user-sessions.chapter.md" }, { + "id": "logging", "file": "administration/logging.chapter.md" }, { + "id": "cleaning-store", "file": "administration/cleaning-store.chapter.md" } ] }, { + "id": "containers", "label": "Container Management", - "id": "ch-containers", "children": [ { + "id": "index", "file": "administration/containers.chapter.md" }, { + "id": "imperative-containers", "file": "administration/imperative-containers.section.md" }, { + "id": "declarative-containers", "file": "administration/declarative-containers.section.md" }, { + "id": "container-networking", "file": "administration/container-networking.section.md" } ] }, { + "id": "troubleshooting", "label": "Troubleshooting", - "id": "ch-troubleshooting", "children": [ { + "id": "index", "file": "administration/troubleshooting.chapter.md" }, { + "id": "boot-problems", "file": "administration/boot-problems.section.md" }, { + "id": "maintenance-mode", "file": "administration/maintenance-mode.section.md" }, { + "id": "rollback", "file": "administration/rollback.section.md" }, { + "id": "store-corruption", "file": "administration/store-corruption.section.md" }, { + "id": "network-problems", "file": "administration/network-problems.section.md" } ] @@ -254,212 +314,266 @@ ] }, { + "id": "services", "label": "Services and Programs", - "id": "ch-services", "children": [ { + "id": "index", "file": "services.md" }, "@MODULE_CHAPTERS@", { + "id": "subversion", "file": "configuration/subversion.chapter.md" }, { + "id": "mattermost", "file": "configuration/mattermost.chapter.md" }, { + "id": "kubernetes", "file": "configuration/kubernetes.chapter.md" } ] }, { + "id": "reference", "label": "Reference", - "id": "ch-reference", "children": [ { + "id": "index", "file": "reference.md" }, { + "id": "profiles", "label": "Profiles", - "id": "ch-profiles", "children": [ { + "id": "index", "file": "configuration/profiles.chapter.md" }, { + "id": "all-hardware", "file": "configuration/profiles/all-hardware.section.md" }, { + "id": "base", "file": "configuration/profiles/base.section.md" }, { + "id": "clone-config", "file": "configuration/profiles/clone-config.section.md" }, { + "id": "demo", "file": "configuration/profiles/demo.section.md" }, { + "id": "docker-container", "file": "configuration/profiles/docker-container.section.md" }, { + "id": "graphical", "file": "configuration/profiles/graphical.section.md" }, { + "id": "headless", "file": "configuration/profiles/headless.section.md" }, { + "id": "installation-device", "file": "configuration/profiles/installation-device.section.md" }, { + "id": "perlless", "file": "configuration/profiles/perlless.section.md" }, { + "id": "minimal", "file": "configuration/profiles/minimal.section.md" }, { + "id": "qemu-guest", "file": "configuration/profiles/qemu-guest.section.md" } ] }, { + "id": "linux-kernel", "file": "configuration/linux-kernel.chapter.md" }, { + "id": "system-state", "label": "Necessary system state", - "id": "ch-system-state", "children": [ { + "id": "index", "file": "administration/system-state.chapter.md" }, { + "id": "nixos-state", "file": "administration/nixos-state.section.md" }, { + "id": "systemd-state", "file": "administration/systemd-state.section.md" }, { + "id": "zfs-state", "file": "administration/zfs-state.section.md" } ] }, { + "id": "system-switch", "label": "What happens during a system switch?", - "id": "sec-switching-systems", "children": [ { + "id": "index", "file": "development/what-happens-during-a-system-switch.chapter.md" }, { + "id": "unit-handling", "file": "development/unit-handling.section.md" }, { + "id": "activation-script", "file": "development/activation-script.section.md" }, { + "id": "non-switchable-systems", "file": "development/non-switchable-systems.section.md" }, { + "id": "etc-overlay", "file": "development/etc-overlay.section.md" } ] }, { + "id": "control-groups", "file": "administration/control-groups.chapter.md" }, { + "id": "bootspec", "file": "development/bootspec.chapter.md" }, { + "id": "modular-services", "file": "development/modular-services.md" } ] }, { + "id": "contributing", "label": "Contributing", - "id": "ch-development", "children": [ { + "id": "index", "file": "development/development.md" }, { + "id": "sources", "file": "development/sources.chapter.md" }, { + "id": "writing-modules", "label": "Writing NixOS Modules", - "id": "sec-writing-modules", "children": [ { + "id": "index", "file": "development/writing-modules.chapter.md" }, { + "id": "option-declarations", "file": "development/option-declarations.section.md" }, { + "id": "option-types", "file": "development/option-types.section.md" }, { + "id": "option-def", "file": "development/option-def.section.md" }, { + "id": "assertions", "file": "development/assertions.section.md" }, { + "id": "meta-attributes", "file": "development/meta-attributes.section.md" }, { + "id": "importing-modules", "file": "development/importing-modules.section.md" }, { + "id": "replace-modules", "file": "development/replace-modules.section.md" }, { + "id": "freeform-modules", "file": "development/freeform-modules.section.md" }, { + "id": "settings-options", "file": "development/settings-options.section.md" }, { + "id": "state-revision", "file": "development/state-revision.section.md" } ] }, { + "id": "nixos-tests", "label": "NixOS Tests", - "id": "sec-nixos-tests", "children": [ { + "id": "index", "file": "development/nixos-tests.chapter.md" }, { + "id": "writing-nixos-tests", "file": "development/writing-nixos-tests.section.md" }, { + "id": "running-nixos-tests", "file": "development/running-nixos-tests.section.md" }, { + "id": "running-nixos-tests-interactively", "file": "development/running-nixos-tests-interactively.section.md" }, { + "id": "linking-nixos-tests-to-packages", "file": "development/linking-nixos-tests-to-packages.section.md" }, { + "id": "testing-hardware-features", "file": "development/testing-hardware-features.section.md" } ] }, { + "id": "building-parts", "file": "development/building-parts.chapter.md" }, { + "id": "developing-the-test-driver", "file": "development/developing-the-test-driver.chapter.md" }, { + "id": "testing-installer", "file": "development/testing-installer.chapter.md" }, { + "id": "writing-documentation", "file": "development/writing-documentation.chapter.md" }, { + "id": "contributing-to-this-manual", "file": "contributing-to-this-manual.chapter.md" } ] diff --git a/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py b/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py index 40b106176681..673f7a7c9afd 100644 --- a/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py +++ b/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py @@ -618,7 +618,7 @@ def _to_base26(n: int) -> str: return (_to_base26(n // 26) if n > 26 else "") + chr(ord("A") + n % 26) # lowercase words joined by dashes -_ID_SEGMENT = re.compile(r"[a-z0-9]+(?:-[a-z0-9]+)*") +_ID_SEGMENT = re.compile(r"[a-z][a-z0-9]*(?:-[a-z0-9]+)*") _NON_ALNUM = re.compile(r"[^a-z0-9]+") def _id_segment(fname: str) -> str: @@ -726,7 +726,7 @@ class HTMLConverter(BaseConverter[ManualHTMLRenderer]): nid = item.get("id") if nid: if nid in seen: - raise SrcError(src=src, description=f"{where}: id must be unique, got {nid}") + raise SrcError(src=src, description=f"{where}: `id` must be unique within `children`, got duplicate `{nid!r}`") seen.add(nid) return nodes @@ -763,7 +763,8 @@ class HTMLConverter(BaseConverter[ManualHTMLRenderer]): if not isinstance(nid, str) or not _ID_SEGMENT.fullmatch(nid): raise SrcError( src=src, - description=f"{where}: 'id' must be lowercase letters, digits and dashes, got {nid!r}") + description=f"{where}: 'id' must be lowercase letters and digits optionally separated by dashes (regex {_ID_SEGMENT!r}), got {nid!r}" + ) if kinds[0] == 'file': if not isinstance(item['file'], str): diff --git a/pkgs/by-name/ni/nixos-render-docs/src/tests/test_manual.py b/pkgs/by-name/ni/nixos-render-docs/src/tests/test_manual.py index 803cdca20b21..0e150eac5660 100644 --- a/pkgs/by-name/ni/nixos-render-docs/src/tests/test_manual.py +++ b/pkgs/by-name/ni/nixos-render-docs/src/tests/test_manual.py @@ -5,7 +5,6 @@ from html.entities import name2codepoint from pathlib import Path import pytest - from nixos_render_docs.manual import HTMLConverter, HTMLParameters @@ -512,10 +511,12 @@ def test_config_id_prefix_fails(tmp_path: Path) -> None: def test_config_id_must_be_url_safe(tmp_path: Path) -> None: for bad in ( - {"file": "intro.md"}, - {"id": "Intro", "file": "intro.md"}, - {"id": "a/b", "file": "intro.md"}, - {"id": "", "file": "intro.md"}, + {"file": "intro.md"}, # missing id + {"id": "Intro", "file": "intro.md"}, # No uppercase + {"id": "a/b", "file": "intro.md"}, # no "/" (or other special characters) + {"id": "", "file": "intro.md"}, # no empty strings + {"id": "0a", "file": "intro.md"}, # no leading number + {"id": "foo-bar-", "file": "intro.md"}, # no trailing - ): with pytest.raises(RuntimeError) as excinfo: _render_with_config( @@ -523,7 +524,7 @@ def test_config_id_must_be_url_safe(tmp_path: Path) -> None: {"items": [bad]}, {"intro.md": "# Introduction {#intro}\n\nBody.\n"}, ) - assert "'id' must be lowercase letters, digits and dashes" in str(excinfo.value.__cause__) + assert "'id' must be lowercase letters and digits optionally separated by dashes" in str(excinfo.value.__cause__) _NIXDOC_EXPORT = {