Skip to content

Commit a8fc67c

Browse files
committed
Update isEmptyMarkdownPage
1 parent ebf0a00 commit a8fc67c

File tree

1 file changed

+43
-22
lines changed

1 file changed

+43
-22
lines changed

packages/gitbook/src/routes/markdownPage.ts

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@ import { getIndexablePages } from '@/lib/sitemap';
55
import { getMarkdownForPagesTree } from '@/routes/llms';
66
import { type RevisionPageDocument, type RevisionPageGroup, RevisionPageType } from '@gitbook/api';
77
import type { Root } from 'mdast';
8-
import { fromMarkdown } from 'mdast-util-from-markdown';
9-
import { frontmatterFromMarkdown } from 'mdast-util-frontmatter';
10-
import { gfmFromMarkdown } from 'mdast-util-gfm';
118
import { toMarkdown } from 'mdast-util-to-markdown';
12-
import { frontmatter } from 'micromark-extension-frontmatter';
13-
import { gfm } from 'micromark-extension-gfm';
14-
import { remove } from 'unist-util-remove';
9+
import remarkParse from 'remark-parse';
10+
import { unified } from 'unified';
1511

1612
/**
1713
* Generate a markdown version of a page.
@@ -45,7 +41,7 @@ export async function servePageMarkdown(context: GitBookSiteContext, pagePath: s
4541
);
4642

4743
// Handle empty document pages which have children
48-
if (isEmptyPage(markdown) && page.pages.length > 0) {
44+
if (isEmptyMarkdownPage(markdown) && page.pages.length > 0) {
4945
return servePageGroup(context, page);
5046
}
5147

@@ -60,26 +56,51 @@ export async function servePageMarkdown(context: GitBookSiteContext, pagePath: s
6056
* Determine if a page is empty.
6157
* A page is empty if it has no content or only a title.
6258
*/
63-
function isEmptyPage(pageMarkdown: string): boolean {
64-
const trimmedMarkdown = pageMarkdown.trim();
65-
66-
// Check if the markdown is empty
67-
if (!trimmedMarkdown) {
68-
return true;
59+
function isEmptyMarkdownPage(markdown: string): boolean {
60+
// Remove frontmatter
61+
const stripped = markdown
62+
.trim()
63+
.replace(/^---\n[\s\S]*?\n---\n?/g, '')
64+
.trim();
65+
66+
// Fast path: try to quickly detect obvious matches
67+
if (/^[ \t]*# .+$/m.test(stripped)) {
68+
// If there's a single heading line or empty lines, and no other content
69+
return (
70+
/^#{1,6} .+\s*$/.test(stripped) &&
71+
!/\n\S+/g.test(stripped.split('\n').slice(1).join('\n'))
72+
);
6973
}
7074

71-
// Parse the markdown to check if it only contains a title
75+
// Fallback: parse with remark for safety
76+
const tree = unified().use(remarkParse).parse(stripped) as Root;
7277

73-
const tree = fromMarkdown(pageMarkdown, {
74-
extensions: [frontmatter(['yaml']), gfm()],
75-
mdastExtensions: [frontmatterFromMarkdown(['yaml']), gfmFromMarkdown()],
76-
});
78+
let seenHeading = false;
7779

78-
// Remove frontmatter
79-
remove(tree, 'yaml');
80+
for (const node of tree.children) {
81+
if (node.type === 'heading') {
82+
if (seenHeading) {
83+
return false;
84+
}
85+
seenHeading = true;
86+
continue;
87+
}
88+
89+
// Allow empty whitespace-only text nodes (e.g., extra newlines)
90+
if (
91+
node.type === 'paragraph' &&
92+
node.children.length === 1 &&
93+
node.children[0].type === 'text' &&
94+
!node.children[0].value.trim()
95+
) {
96+
continue;
97+
}
98+
99+
// Anything else is disallowed
100+
return false;
101+
}
80102

81-
// If the page has no content or only a title, it is empty
82-
return tree.children.length <= 1 && tree.children[0]?.type === 'heading';
103+
return seenHeading;
83104
}
84105

85106
/**

0 commit comments

Comments
 (0)