You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

252 lines
8.7 KiB

import startCase from 'lodash-es/startCase';
import sortBy from 'lodash-es/sortBy';
import remove from 'lodash-es/remove';
import path, { sep } from 'path';
import glob from 'fast-glob';
import fs from 'fs-extra';
import grayMatter from "gray-matter";
type Sidebar = SidebarGroup[] | SidebarMulti;
interface SidebarMulti {
[path: string]: SidebarGroup[]
}
interface SidebarGroup {
text: string
items: SidebarItem[]
collapsible?: boolean
collapsed?: boolean
}
interface SidebarItem {
text: string
link: string
}
interface Options {
startsDirs?: Array<string>, // Directoty path to ignore from being captured.
ignoreDirectory?: Array<string>, // Directoty path to ignore from being captured.
ignoreMDFiles?: Array<string>, // File path to ignore from being captured.
}
// handle md file name
const getName = (path: string) => {
let name = path.split(sep).pop() || path;
const argsIndex = name.lastIndexOf('--');
if (argsIndex > -1) {
name = name.substring(0, argsIndex);
}
// "001.guide" or "001-guide" or "001_guide" or "001 guide" -> "guide"
name = name.replace(/^\d+[.\-_ ]?/, '');
return startCase(name);
};
// handle dir name
const getDirName = (path: string) => {
let name = path.split(sep).shift() || path;
name = name.replace(/^\d+[.\-_ ]?/, '');
return startCase(name);
};
// Load all MD files in a specified directory
const getChildren = function (parentPath: string, ignoreMDFiles: Array<string> = []) {
const pattern = '/**/*.md';
const files = glob.sync(parentPath + pattern, {ignore: ["**/node_modules/**", "**/dist/**"]}).map((path) => {
let end = -3
const newPath = path.slice(parentPath.length + 1, end);
if (ignoreMDFiles?.length && ignoreMDFiles.findIndex(item => newPath.endsWith(item)) !== -1) {
return undefined;
}
return { path: newPath };
});
remove(files, file => file === undefined);
// Return the ordered list of files, sort by 'path'
return sortBy(files, ['path']).map(file => file?.path || '');
};
// Return sidebar config for given baseDir.
function side(baseDir: string, options?: Options) {
const mdFiles = getChildren(baseDir, options?.ignoreMDFiles);
const sidebars: Sidebar = [];
const dirs = options?.startsDirs ?? []
mdFiles.forEach((item) => {
if (options?.ignoreDirectory?.length
&& options?.ignoreDirectory.findIndex(one => item.includes(one)) !== -1) {
return;
}
let index = dirs.findIndex(text => item.startsWith(text))
if (index != -1) {
let curDir = dirs[index]
const filePath = path.resolve(baseDir, item)
let p = filePath + ".md"
const {
data: { title, first, name, category },
} = grayMatter(fs.readFileSync(p, "utf8"));
const [pkg, _name, i] = item.split('/').slice(-3)
let _title = title ?? _name
// @ts-ignore
const sidebarItemIndex = sidebars.findIndex(sidebar => sidebar._realtext === curDir);
if (sidebarItemIndex !== -1) {
if (first!=undefined) {
if(category) {
// @ts-ignore
let ff = sidebars.find(v=>v._category === category)
if(!ff) {
ff = {
text: category,
// @ts-ignore
_sort: 0,
// @ts-ignore
_category: category,
items: []
}
// @ts-ignore
sidebars.push(ff)
}
// @ts-ignore
ff.items.push({
text: _title,
link: '/' + item.replace('index', ''),
});
} else {
sidebars[sidebarItemIndex].items.splice(first,0,{
text: _title,
link: '/' + item.replace('index', ''),
})
if (name) {
sidebars[sidebarItemIndex].text = name
}
}
}else{
if(category) {
// @ts-ignore
let ff = sidebars.find(v=>v._category === category)
if(!ff) {
ff = {
text: category,
// @ts-ignore
_sort: 0,
// @ts-ignore
_category: category,
items: []
}
// @ts-ignore
sidebars.push(ff)
}
// @ts-ignore
ff.items.push({
text: _title,
link: '/' + item.replace('index', ''),
});
} else {
sidebars[sidebarItemIndex].items.push({
text: _title,
link: '/' + item.replace('index', ''),
});
}
}
sidebars[sidebarItemIndex].items.sort((a,b)=>{
// @ts-ignore
return a._sort - b._sort
})
} else {
if(category) {
// @ts-ignore
let ff = sidebars.find(v=>v._category === category)
if(!ff) {
ff = {
text: category,
// @ts-ignore
_sort: -999,
// @ts-ignore
_category: category,
items: []
}
// @ts-ignore
sidebars.push(ff)
}
// @ts-ignore
ff.items.push({
text: _title,
link: '/' + item.replace('index', ''),
});
} else {
sidebars.push({
text: name || curDir,
// @ts-ignore
_sort: index,
// @ts-ignore
_realtext: curDir,
items: [{
text: _title,
link: '/' + item.replace('index', ''),
}],
});
}
}
sidebars.sort((a,b)=>{
// @ts-ignore
return (a._sort || 0) - (b._sort || 0)
})
}
})
sidebars.sort((a,b)=>{
// @ts-ignore
return b._sort - a._sort
})
// const sidebars: Sidebar = [];
// // strip number of folder's name
// mdFiles.forEach((item) => {
// const dirName = getDirName(item);
// if (options?.ignoreDirectory?.length
// && options?.ignoreDirectory.findIndex(one => item.includes(one)) !== -1) {
// return;
// }
// const mdFileName = getName(item);
// const filePath = path.resolve(baseDir, item)
// const {
// data: { title },
// content,
// } = grayMatter(fs.readFileSync(filePath+".md", "utf8"));
// console.log(item);
// const sidebarItemIndex = sidebars.findIndex(sidebar => sidebar.text === mdFileName);
// if (sidebarItemIndex !== -1) {
// sidebars[sidebarItemIndex].items.push({
// text: title ?? mdFileName,
// link: '/'+item,
// });
// } else {
// sidebars.push({
// text: dirName,
// items: [{
// text: title ?? mdFileName,
// link: '/'+item,
// }],
// });
// }
// });
// console.info('sidebar is create:', JSON.stringify(sidebars));
return sidebars;
}
/**
* Returns `sidebar` configuration for VitePress calculated using structure of directory and files in given path.
* @param {String} rootDir - Directory to get configuration for.
* @param {Options} options - Option to create configuration.
*/
export const getSideBar = (rootDir = './', options?: Options) => side(rootDir, options);