mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
fix: do not add the same page twice in the sidebar tree (#2244)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@fumadocs/core": patch
|
||||
---
|
||||
|
||||
Fix duplicate pages in page tree when referencing subpage in meta.json and using `...` or adding the subfolder again
|
||||
@@ -27,6 +27,7 @@ export interface PageTreeBuilderContext<
|
||||
|
||||
storages?: Record<string, ContentStorage<Page, Meta>>;
|
||||
locale?: string;
|
||||
visitedPages?: Set<string>;
|
||||
}
|
||||
|
||||
export interface PageTreeTransformer<
|
||||
@@ -120,9 +121,13 @@ function buildAll(
|
||||
);
|
||||
|
||||
for (const path of sortedPaths) {
|
||||
if (ctx.visitedPages?.has(path)) continue;
|
||||
|
||||
const fileNode = buildFileNode(path, ctx);
|
||||
if (!fileNode) continue;
|
||||
|
||||
ctx.visitedPages?.add(path);
|
||||
|
||||
if (basename(path, extname(path)) === 'index') output.unshift(fileNode);
|
||||
else output.push(fileNode);
|
||||
}
|
||||
@@ -205,6 +210,9 @@ function resolveFolderItem(
|
||||
}
|
||||
|
||||
const fileNode = buildFileNode(path, ctx);
|
||||
if (fileNode) {
|
||||
ctx.visitedPages?.add(path);
|
||||
}
|
||||
return fileNode ? [fileNode] : [];
|
||||
}
|
||||
|
||||
@@ -302,6 +310,7 @@ function buildFileNode(
|
||||
ctx: PageTreeBuilderContext,
|
||||
): PageTree.Item | undefined {
|
||||
const { options, getUrl, storage, locale, transformers } = ctx;
|
||||
|
||||
const page = storage.read(path);
|
||||
if (page?.format !== 'page') return;
|
||||
|
||||
@@ -400,6 +409,7 @@ export function createPageTreeBuilder(getUrl: UrlFn): PageTreeBuilder {
|
||||
locale,
|
||||
storage,
|
||||
storages,
|
||||
visitedPages: new Set<string>(),
|
||||
resolveName(name, format) {
|
||||
return resolve(name, format) ?? name;
|
||||
},
|
||||
|
||||
@@ -252,3 +252,172 @@ test('Loader: Rest operator', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('Loader: Allow duplicate pages when explicitly referenced twice', () => {
|
||||
const result = loader({
|
||||
baseUrl: '/',
|
||||
pageTree: {
|
||||
noRef: true,
|
||||
},
|
||||
source: {
|
||||
files: [
|
||||
{
|
||||
type: 'meta',
|
||||
path: 'meta.json',
|
||||
data: {
|
||||
pages: ['page1', 'page1', 'page2'],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'page',
|
||||
path: 'page1.mdx',
|
||||
data: {
|
||||
title: 'Page 1',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'page',
|
||||
path: 'page2.mdx',
|
||||
data: {
|
||||
title: 'Page 2',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const treeChildren = result.pageTree.children;
|
||||
expect(treeChildren.length).toBe(3);
|
||||
expect(treeChildren[0].$id).toBe('page1.mdx');
|
||||
expect(treeChildren[1].$id).toBe('page1.mdx');
|
||||
expect(treeChildren[2].$id).toBe('page2.mdx');
|
||||
});
|
||||
|
||||
test('Loader: No duplicate pages when referencing subfolder items and folder', () => {
|
||||
const result = loader({
|
||||
baseUrl: '/',
|
||||
pageTree: {
|
||||
noRef: true,
|
||||
},
|
||||
source: {
|
||||
files: [
|
||||
{
|
||||
type: 'meta',
|
||||
path: 'meta.json',
|
||||
data: {
|
||||
pages: [
|
||||
'index',
|
||||
'subfolder/page1', // Reference specific page in subfolder
|
||||
'subfolder/page2', // Reference another specific page
|
||||
'other-page',
|
||||
'subfolder', // Reference the entire folder
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'page',
|
||||
path: 'index.mdx',
|
||||
data: {
|
||||
title: 'Home',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'page',
|
||||
path: 'other-page.mdx',
|
||||
data: {
|
||||
title: 'Other Page',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'page',
|
||||
path: 'subfolder/page1.mdx',
|
||||
data: {
|
||||
title: 'Subfolder Page 1',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'page',
|
||||
path: 'subfolder/page2.mdx',
|
||||
data: {
|
||||
title: 'Subfolder Page 2',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'page',
|
||||
path: 'subfolder/page3.mdx',
|
||||
data: {
|
||||
title: 'Subfolder Page 3',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// Check that pages are not duplicated
|
||||
const pages = result.getPages();
|
||||
const pagePaths = pages.map((page) => page.slugs.join('/'));
|
||||
|
||||
// Should have exactly 5 pages total
|
||||
expect(pages.length).toBe(5);
|
||||
|
||||
// Check that each page appears only once
|
||||
const uniquePaths = new Set(pagePaths);
|
||||
expect(uniquePaths.size).toBe(pagePaths.length);
|
||||
|
||||
// Verify all pages are present
|
||||
expect(pagePaths.sort()).toEqual([
|
||||
'', // index
|
||||
'other-page',
|
||||
'subfolder/page1',
|
||||
'subfolder/page2',
|
||||
'subfolder/page3',
|
||||
]);
|
||||
|
||||
// Check the page tree structure
|
||||
expect(removeUndefined(result.pageTree, true), 'Page Tree')
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"$id": "root",
|
||||
"children": [
|
||||
{
|
||||
"$id": "index.mdx",
|
||||
"name": "Home",
|
||||
"type": "page",
|
||||
"url": "/",
|
||||
},
|
||||
{
|
||||
"$id": "subfolder/page1.mdx",
|
||||
"name": "Subfolder Page 1",
|
||||
"type": "page",
|
||||
"url": "/subfolder/page1",
|
||||
},
|
||||
{
|
||||
"$id": "subfolder/page2.mdx",
|
||||
"name": "Subfolder Page 2",
|
||||
"type": "page",
|
||||
"url": "/subfolder/page2",
|
||||
},
|
||||
{
|
||||
"$id": "other-page.mdx",
|
||||
"name": "Other Page",
|
||||
"type": "page",
|
||||
"url": "/other-page",
|
||||
},
|
||||
{
|
||||
"$id": "subfolder",
|
||||
"children": [
|
||||
{
|
||||
"$id": "subfolder/page3.mdx",
|
||||
"name": "Subfolder Page 3",
|
||||
"type": "page",
|
||||
"url": "/subfolder/page3",
|
||||
},
|
||||
],
|
||||
"name": "Subfolder",
|
||||
"type": "folder",
|
||||
},
|
||||
],
|
||||
"name": "",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user