Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugin-auto-nav): support _meta.{js,ts} #1044

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
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
5 changes: 5 additions & 0 deletions .changeset/brave-cycles-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rspress/plugin-auto-nav-sidebar": minor
---

support \_meta.{js,ts}
10 changes: 10 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"text": "Guide",
"link": "/guide/"
},
{
"text": "Api",
"link": "/api/"
}
]
19 changes: 19 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/api/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[
{
"type": "file",
"name": "index",
"label": "API Overview"
},
{
"type": "dir",
"name": "config",
"label": "Config"
},
{
"type": "dir",
"name": "client-api",
"label": "Client API"
},
"commands",
"single-page"
]
13 changes: 13 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/api/client-api/_meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default [
{
type: 'file',
name: 'index',
label: 'Client API Overview',
},
{
type: 'file',
name: 'api-runtime',
overviewHeaders: [],
},
'api-components',
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Components

## Usage

## Example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Runtime API

## usePageData

## useLang
3 changes: 3 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/api/client-api/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
overview: true
---
5 changes: 5 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/api/commands.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Commands

## rspress dev

## rspress build
4 changes: 4 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/api/config.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
overview: true
overviewHeaders: [2]
---
14 changes: 14 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/api/config/_meta.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default [
'config-basic',
'config-theme',
'config-frontmatter',
{
type: 'file',
name: 'config-build',
overviewHeaders: [2, 3],
},
{
type: 'file',
name: 'config-extname.json',
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Basic Config

## root

## logoText
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Build Config

## builderConfig

### Default Config

## markdown

### markdown.remarkPlugins
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Extname Config
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
overviewHeaders: []
---

# Front Matter Config

## title

## description
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Theme Config

## nav

## sidebar
3 changes: 3 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/api/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
overview: true
---
11 changes: 11 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/api/single-page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
overviewHeaders: []
---

# Single

## Single-1

### Single-11

## Single-2
8 changes: 8 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/guide/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
"index",
{
"type": "dir",
"name": "advanced",
"label": "Advanced"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Plugin

This plugin is a simple plugin that allows you to create a custom command that will send a message to a channel of your choice.
1 change: 1 addition & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/guide/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Guide
1 change: 1 addition & 0 deletions e2e/fixtures/auto-nav-sidebar-js/doc/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Hello World
16 changes: 16 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "@rspress-fixture/rspress-auto-nav-sidebar-js",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "rspress dev",
"build": "rspress build",
"preview": "rspress preview"
},
"dependencies": {
"rspress": "workspace:*"
},
"devDependencies": {
"@types/node": "^14"
}
}
6 changes: 6 additions & 0 deletions e2e/fixtures/auto-nav-sidebar-js/rspress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as path from 'path';
import { defineConfig } from 'rspress/config';

export default defineConfig({
root: path.join(__dirname, 'doc'),
});
1 change: 1 addition & 0 deletions e2e/fixtures/auto-nav-sidebar-js/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
2 changes: 2 additions & 0 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import chalk from 'chalk';
import { loadConfigFile } from './config/loadConfigFile';
import update from './update';

// for config reload, restart the server
const CONFIG_FILES = [
'rspress.config.ts',
'rspress.config.js',
'_meta.json',
'_meta.js',
'i18n.json',
];

Expand Down
137 changes: 79 additions & 58 deletions packages/plugin-auto-nav-sidebar/src/walk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,84 @@ import {
import { NavMeta, SideMeta } from './type';
import { detectFilePath, extractTitleAndOverviewHeaders } from './utils';
import { logger } from '@rspress/shared/logger';
import { loadConfig } from '@rspress/shared/node-utils';

// Get the sidebar config from the `_meta.json` file
async function getSideMetaFromMetaFile(
workDir: string,
rootDir: string,
): Promise<SideMeta> {
const metaJsFilePath = path.resolve(workDir, '_meta.js');
if (await fs.exists(metaJsFilePath)) {
const { content: sideMeta } = (await loadConfig({
path: metaJsFilePath,
})) as any;
return sideMeta;
}

const metaJsonFilePath = path.resolve(workDir, '_meta.json');
if (await fs.exists(metaJsonFilePath)) {
const sideMeta = (await fs.readJSON(metaJsonFilePath, 'utf8')) as SideMeta;
return sideMeta;
}

// If `_meta.js` or `_meta.json` file doesn't exist, we will generate the sidebar config from the directory structure.
let subItems = await fs.readdir(workDir);
// If there exists a file with the same name of the directory folder
// we don't need to generate SideMeta for this single file
subItems = subItems.filter(item => {
const hasExtension = ['.md', '.mdx'].some(ext => item.endsWith(ext));
const hasSameBaseName = subItems.some(elem => {
const baseName = elem.replace(/\.[^/.]+$/, '');
return baseName === item.replace(/\.[^/.]+$/, '') && elem !== item;
});
return !(hasExtension && hasSameBaseName);
});
const sideMeta = (
await Promise.all(
subItems.map(async item => {
// Fix https://github.com/web-infra-dev/rspress/issues/346
if (
item === '_meta.json' ||
item === '_meta.js' ||
item === '_meta.ts'
) {
return null;
}
const stat = await fs.stat(path.join(workDir, item));
// If the item is a directory, we will transform it to a object with `type` and `name` property.
if (stat.isDirectory()) {
// set H1 title to sidebar label when have same name md/mdx file
const mdFilePath = path.join(workDir, `${item}.md`);
const mdxFilePath = path.join(workDir, `${item}.mdx`);
let label = item;

const setLabelFromFilePath = async (filePath: string) => {
const { title } = await extractTitleAndOverviewHeaders(
filePath,
rootDir,
);
label = title;
};

if (fs.existsSync(mdxFilePath)) {
await setLabelFromFilePath(mdxFilePath);
} else if (fs.existsSync(mdFilePath)) {
await setLabelFromFilePath(mdFilePath);
}

return {
type: 'dir',
name: item,
label,
};
}
return item;
}),
)
).filter(Boolean) as SideMeta;
return sideMeta;
}

export async function scanSideMeta(
workDir: string,
Expand All @@ -32,64 +110,7 @@ export async function scanSideMeta(
const metaFile = path.resolve(workDir, '_meta.json');
// Fix the windows path
const relativePath = slash(path.relative(rootDir, workDir));
let sideMeta: SideMeta | undefined;
// Get the sidebar config from the `_meta.json` file
try {
// Don't use require to avoid require cache, which make hmr not work.
sideMeta = (await fs.readJSON(metaFile, 'utf8')) as SideMeta;
} catch (e) {
// If the `_meta.json` file doesn't exist, we will generate the sidebar config from the directory structure.
let subItems = await fs.readdir(workDir);
// If there exists a file with the same name of the directory folder
// we don't need to generate SideMeta for this single file
subItems = subItems.filter(item => {
const hasExtension = ['.md', '.mdx'].some(ext => item.endsWith(ext));
const hasSameBaseName = subItems.some(elem => {
const baseName = elem.replace(/\.[^/.]+$/, '');
return baseName === item.replace(/\.[^/.]+$/, '') && elem !== item;
});
return !(hasExtension && hasSameBaseName);
});
sideMeta = (
await Promise.all(
subItems.map(async item => {
// Fix https://github.com/web-infra-dev/rspress/issues/346
if (item === '_meta.json') {
return null;
}
const stat = await fs.stat(path.join(workDir, item));
// If the item is a directory, we will transform it to a object with `type` and `name` property.
if (stat.isDirectory()) {
// set H1 title to sidebar label when have same name md/mdx file
const mdFilePath = path.join(workDir, `${item}.md`);
const mdxFilePath = path.join(workDir, `${item}.mdx`);
let label = item;

const setLabelFromFilePath = async (filePath: string) => {
const { title } = await extractTitleAndOverviewHeaders(
filePath,
rootDir,
);
label = title;
};

if (fs.existsSync(mdxFilePath)) {
await setLabelFromFilePath(mdxFilePath);
} else if (fs.existsSync(mdFilePath)) {
await setLabelFromFilePath(mdFilePath);
}

return {
type: 'dir',
name: item,
label,
};
}
return item;
}),
)
).filter(Boolean) as SideMeta;
}
const sideMeta: SideMeta = await getSideMetaFromMetaFile(workDir, rootDir);

const sidebarFromMeta: (
| SidebarGroup
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/node-utils.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './node-utils/loadFrontMatter';
export * from './node-utils/loadConfig';
2 changes: 2 additions & 0 deletions packages/shared/src/node-utils/loadConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// TODO: load config file logic of _meta.js
export { loadConfig } from '@rsbuild/core';
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading