Core: Support reversed rest items in meta.json

This commit is contained in:
Fuma Nama
2025-01-22 18:49:51 +08:00
parent a42dde106a
commit a763058695
4 changed files with 80 additions and 7 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-core': patch
---
Support reversed rest items in `meta.json`
@@ -114,7 +114,7 @@ When a meta file is present, items are not included unless you have explicitly a
### Path
The items of `pages` property can be a relative path to a page or folder. File extensions are not required.
The items of `pages` can also be a relative path to a page or folder, no file extensions needed.
```json
{
@@ -160,6 +160,17 @@ Add a Rest (`...`) item to automatically add and sort remaining page items.
}
```
#### Reversed Order
Instead of soring alphabetically, you can also sort items reversely.
```json
{
"title": "Folder",
"pages": ["guide", "z...a"]
}
```
### Except
In conjunction with the Rest item (`...`), you can use `!name` to exclude an item from the rest.
@@ -244,7 +255,7 @@ For example, when you are in a root folder called `core`, the other folders (e.g
### Index Pages
By default, index pages are not considered as a page "under" the folder, you must specify them in the `pages` property.
By default, index pages are not considered as the child item of a folder, you must specify them in the `pages` property.
## Internationalization
+10 -5
View File
@@ -55,7 +55,8 @@ export interface PageTreeBuilder {
const group = /^\((?<name>.+)\)$/;
const link = /^(?:\[(?<icon>[^\]]+)])?\[(?<name>[^\]]+)]\((?<url>[^)]+)\)$/;
const separator = /^---(?<name>.*?)---$/;
const rest = '...';
const rest = '...' as const;
const restReversed = 'z...a' as const;
const extractPrefix = '...';
const excludePrefix = '!';
@@ -113,8 +114,8 @@ function resolveFolderItem(
item: string,
ctx: PageTreeBuilderContext,
addedNodePaths: Set<string>,
): PageTree.Node[] | '...' {
if (item === rest) return '...';
): PageTree.Node[] | typeof rest | typeof restReversed {
if (item === rest || item === restReversed) return item;
let match = separator.exec(item);
if (match?.groups) {
@@ -194,7 +195,9 @@ function buildFolderNode(
const isRoot = metadata?.root ?? isGlobalRoot;
const addedNodePaths = new Set<string>();
const resolved = metadata?.pages?.flatMap<PageTree.Node | '...'>((item) => {
const resolved = metadata?.pages?.flatMap<
PageTree.Node | typeof rest | typeof restReversed
>((item) => {
return resolveFolderItem(folder, item, ctx, addedNodePaths);
});
@@ -205,8 +208,10 @@ function buildFolderNode(
);
const nodes = resolved?.flatMap<PageTree.Node>((item) => {
if (item === '...') {
if (item === rest) {
return restNodes;
} else if (item === restReversed) {
return restNodes.reverse();
}
return item;
+52
View File
@@ -456,3 +456,55 @@ test('Loader: Without meta.json', () => {
}
`);
});
test('Loader: Rest operator', () => {
const result = loader({
baseUrl: '/',
pageTree: {
noRef: true,
},
source: {
files: [
{
type: 'meta',
path: 'meta.json',
data: {
pages: ['z...a'],
},
},
{
type: 'page',
path: '1-2.mdx',
data: {
title: '1.2',
},
},
{
type: 'page',
path: '2-2.mdx',
data: {
title: '2.2',
},
},
],
},
});
expect(result.pageTree, 'Page Tree').toMatchInlineSnapshot(`
{
"children": [
{
"name": "2.2",
"type": "page",
"url": "/2-2",
},
{
"name": "1.2",
"type": "page",
"url": "/1-2",
},
],
"name": "",
}
`);
});