Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions packages/plugin-docs-cli/src/scanner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,26 @@ describe('scanDocsFolder', () => {
expect(pages[2].file).toBe('advanced.md');
});

it('should not include headings in page objects', async () => {
it('should extract h2/h3 headings into page objects', async () => {
const result = await scanDocsFolder(testDocsPath);

const pages = result.manifest.pages;
for (const page of pages) {
expect(page).not.toHaveProperty('headings');
}
const configPage = result.manifest.pages.find((p: Page) => p.slug === 'config');
const settingsPage = configPage?.children?.find((p: Page) => p.slug === 'config/settings');

expect(settingsPage?.headings).toEqual([
{ level: 2, text: 'General Settings', id: 'general-settings' },
{ level: 3, text: 'Display Name', id: 'display-name' },
{ level: 2, text: 'Advanced Settings', id: 'advanced-settings' },
]);
});

it('should omit headings on pages without h2/h3 content', async () => {
const result = await scanDocsFolder(testDocsPath);

// home.md has only an h1, no h2/h3 — field should be omitted
const homePage = result.manifest.pages.find((p: Page) => p.slug === 'home');
expect(homePage).toBeDefined();
expect(homePage).not.toHaveProperty('headings');
});

it('should throw error when no valid markdown files found', async () => {
Expand Down
15 changes: 14 additions & 1 deletion packages/plugin-docs-cli/src/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { join, relative, parse, sep } from 'node:path';
import GithubSlugger from 'github-slugger';
import matter from 'gray-matter';
import createDebug from 'debug';
import type { Manifest, Page, MarkdownFiles, Frontmatter } from '@grafana/plugin-docs-parser';
import {
parseMarkdown,
type Manifest,
type Page,
type MarkdownFiles,
type Frontmatter,
} from '@grafana/plugin-docs-parser';

const debug = createDebug('plugin-docs-cli:scanner');

Expand Down Expand Up @@ -226,6 +232,13 @@ function treeToPages(node: TreeNode): Page[] {
file: child.file.relativePath,
};

// extract h2/h3 headings via the canonical parser pipeline so heading
// IDs in the manifest match the IDs rendered at serve time
const { headings } = parseMarkdown(child.file.content);
if (headings.length > 0) {
page.headings = headings;
}

// if this file has children (folder with same name), add them
if (child.children.size > 0) {
page.children = treeToPages(child);
Expand Down
6 changes: 6 additions & 0 deletions packages/plugin-docs-parser/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export interface Page {
*/
file: string;

/**
* Optional headings (h2, h3) extracted from the page's markdown body.
* Present only on pages backed by a real file; omitted on category nodes.
*/
headings?: Heading[];

/**
* Optional nested child pages.
*/
Expand Down
Loading