From f30a1586fe7b16d5a300afe584cc0bfbe3ef31d5 Mon Sep 17 00:00:00 2001 From: Avocado Date: Tue, 1 Sep 2026 09:17:23 +0900 Subject: [PATCH] fix(html): list pages without a document-level stability index The generated index page is built from every page carrying a stability index, so a document that has none is dropped from the listing. A document-level stability index is optional. Documents such as `cli`, `process` and `errors` place stability on their individual sections instead, and `cli` alone carries 50 of them, so having none at the document level says nothing about whether the page belongs in a listing of the documentation. Against the current nodejs/node docs this drops 13 of 68 pages, including `module`, the one the issue reports, along with `process`, `errors` and `cli`. The sidebar, built from the same input by `buildPageList()`, applies no such filter and lists all of them. List every page instead, excluding only the index itself, which is the page doing the listing. The stability badge renders only when the entry has an index, so a page without one no longer produces an empty badge labelled `Stability: undefined`. Fixes: https://github.com/nodejs/doc-kit/issues/1055 Signed-off-by: Avocado --- .changeset/index-page-missing-docs.md | 5 +++ .../components/DocumentationIndex/index.jsx | 19 ++++---- .../src/html/utils/__tests__/config.test.mjs | 43 ++++++++++++++++++- packages/react/src/html/utils/config.mjs | 12 ++++-- 4 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 .changeset/index-page-missing-docs.md diff --git a/.changeset/index-page-missing-docs.md b/.changeset/index-page-missing-docs.md new file mode 100644 index 00000000..0bb8248f --- /dev/null +++ b/.changeset/index-page-missing-docs.md @@ -0,0 +1,5 @@ +--- +'@doc-kit/generator-react': patch +--- + +fix(html): list pages without a document-level stability index diff --git a/packages/react/src/html/ui/components/DocumentationIndex/index.jsx b/packages/react/src/html/ui/components/DocumentationIndex/index.jsx index d809c82f..abcd61a0 100644 --- a/packages/react/src/html/ui/components/DocumentationIndex/index.jsx +++ b/packages/react/src/html/ui/components/DocumentationIndex/index.jsx @@ -9,7 +9,8 @@ import { documentationIndex } from '#theme/config'; * @typedef {Object} DocumentationIndexEntry * @property {string} api - Basename of the document, linked as `${api}.html` * @property {string} name - Human-readable name from the document's heading - * @property {string} index - Stability index (e.g. `'2'` or `'1.1'`) + * @property {string} [index] - Stability index (e.g. `'2'` or `'1.1'`), absent + * on documents that carry stability only on their individual sections * @property {string} [description] - The document's `llm_description`, or its * first paragraph, rendered to HTML at build time */ @@ -26,13 +27,15 @@ const IndexEntry = ({ api, name, index, description }) => { {name} - - {label} - + {index !== undefined && ( + + {label} + + )} {description && ( diff --git a/packages/react/src/html/utils/__tests__/config.test.mjs b/packages/react/src/html/utils/__tests__/config.test.mjs index 999c9de5..3f036d03 100644 --- a/packages/react/src/html/utils/__tests__/config.test.mjs +++ b/packages/react/src/html/utils/__tests__/config.test.mjs @@ -52,6 +52,7 @@ const makeEntry = (api, name, path, extra = {}) => ({ api, path, heading: { depth: 1, data: { name } }, + content: { type: 'root', children: [] }, ...extra, }); @@ -131,7 +132,7 @@ describe('buildPageList', () => { }); describe('buildDocumentationIndex', () => { - it('lists only pages with a stability index, with their descriptions', () => { + it('lists every page but the index itself, with their descriptions', () => { const input = [ { api: 'fs', @@ -183,6 +184,46 @@ describe('buildDocumentationIndex', () => { ]); }); + it('keeps pages that carry no document-level stability index', () => { + // `process` and `errors` are documented this way: stability lives on their + // individual sections rather than on the document. + const input = [ + { + api: 'process', + path: '/process', + heading: { depth: 1, data: { name: 'Process' } }, + stability: null, + llm_description: 'Information about the current process.', + content: { type: 'root', children: [] }, + }, + { + api: 'fs', + path: '/fs', + heading: { depth: 1, data: { name: 'File System' } }, + stability: { data: { index: '2' } }, + llm_description: 'File system APIs.', + content: { type: 'root', children: [] }, + }, + ]; + + const result = buildDocumentationIndex(input); + + assert.deepStrictEqual(result, [ + { + api: 'fs', + name: 'File System', + index: '2', + description: 'File system APIs.', + }, + { + api: 'process', + name: 'Process', + index: undefined, + description: 'Information about the current process.', + }, + ]); + }); + it('renders descriptions to HTML, without the links entries cannot nest', () => { const input = [ { diff --git a/packages/react/src/html/utils/config.mjs b/packages/react/src/html/utils/config.mjs index 7b3d9f11..8a83dfad 100644 --- a/packages/react/src/html/utils/config.mjs +++ b/packages/react/src/html/utils/config.mjs @@ -116,18 +116,22 @@ export function buildChunkGroups(input) { /** * Pre-compute the entries rendered by the `` component: - * every page with a stability index, plus its description. + * every page other than the index itself, plus its description. + * + * A document-level stability index is optional. Documents such as `process` + * and `errors` carry stability only on their individual sections, and pages + * that list them by document, this one included, still need to link to them. * * @param {Array} input - * @returns {Array<{api: string, name: string, index: string, description: string}>} + * @returns {Array<{api: string, name: string, index: string | undefined, description: string}>} */ export function buildDocumentationIndex(input) { return getSortedHeadNodes(input) - .filter(entry => entry.stability) + .filter(entry => entry.api !== 'index') .map(entry => ({ api: entry.api, name: entry.heading.data.name, - index: entry.stability.data.index, + index: entry.stability?.data.index, description: renderAsHTML(parseInline(getEntryDescription(entry), true)), })); }