From 0f96b83d07fe0e0c2b75dfee364607eebb9775d8 Mon Sep 17 00:00:00 2001 From: shanyuhai123 <864299347@qq.com> Date: Wed, 25 Dec 2019 23:04:10 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=F0=9F=8E=89=20=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=20auto=20sidebar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 51 +++++++++++++++++++++++++++++++++++++++++ index.js | 37 ++++++++++++++++++++++++++++++ lib/options.js | 5 ++++ lib/utils.js | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 9 ++++++++ 5 files changed, 164 insertions(+) create mode 100644 README.md create mode 100644 index.js create mode 100644 lib/options.js create mode 100644 lib/utils.js create mode 100644 package.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..2b207e4 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# Vuepress Plugin Auto Sidebar + +## 介绍(Introduction) + +这是为 vuepress 自动生成侧边栏的插件。 + + + +### 1. 注意事项 + +若想要使用该插件,需要固定 docs 下路径(虽然在计划适配更多的情况,也添加了 `mode` 参数用于后期扩展,但在近两个月暂无计划)。 + + + +## 安装(Install) + +```bash +npm i vuepress-plugin-auto-sidebar -D +``` + + + +## 使用(Usage) + +```js +// 修改 docs/.vuepress/config.js + +module.exports = { + // 引入插件(import plugins) + plugins: [ + // 更多方式可参考(more use methods can refer to the documentation): + // https://v1.vuepress.vuejs.org/zh/plugin/using-a-plugin.html + "vuepress-plugin-auto-sidebar": {} // 可参考下方的 “可选项” + ], + // 配置 sidebar() + themeConfig: { + sidebar: require('./sidebar.js'), // 这是默认情况,当然你也可以自定义路径和文件名。(This is the default, of course you can also customize the path and filename.) + } +} +``` + + + +## 可选项(Optional) + +| 属性名称(key) | 类型(type) | 预设值(default) | 说明(description) | +| :-------------- | :----------: | :---------------: | :------------------------------- | +| mode | String | default | 可选的模式,当前仅支持 default。 | +| dest | String | .vuepress | 输出 sidebar 的路径。 | +| filename | String | sidebar | 输出 sidebar 的文件名。 | + diff --git a/index.js b/index.js new file mode 100644 index 0000000..bbe1793 --- /dev/null +++ b/index.js @@ -0,0 +1,37 @@ +const fs = require("fs"); +const path = require("path"); +const { filterRootMarkdowns, filterDepthOneMarkdowns, filterDepthTwoMarkdowns, addDepthOne, addDepthTwo, genSidebar, genRoute } = require("./lib/utils"); +const sidebarOptions = require("./lib/options"); + +const OPTIONAL_MODE = ['default']; // 待补充 + +module.exports = (options, ctx) => ({ + name: "vuepress-plugin-auto-sidebar", + async ready() { + try { + const mergeOptions = Object.assign({}, sidebarOptions, options); + const { sourceDir, pages } = ctx; + + // 映射 pages + const mapPages = pages.map(page => ({ + path: page.path, + split: page.path.split("/").slice(1) // 移除多余的空格 + })).filter(filterRootMarkdowns); + + const depthOnePages = addDepthOne(mapPages.filter(filterDepthOneMarkdowns)); + const depthTwoPages = addDepthTwo(mapPages.filter(filterDepthTwoMarkdowns)); + + let depthTwoPagesSidebar = Object.create(null); + const depthOnePagesSidebar = depthOnePages.reduce((acc, cur) => (acc[genRoute(cur.name)] = genSidebar(cur.name, cur.children), acc), {}); + depthTwoPages.forEach(group => group.children.reduce((acc, cur) => (acc[genRoute(group.name, cur.name)] = genSidebar(cur.name, cur.children), acc), depthTwoPagesSidebar)); + const SIDEBAR = Object.assign({}, depthOnePagesSidebar, depthTwoPagesSidebar); + + // 处理输出 + const filename = mergeOptions.filename.endsWith(".js") ? mergeOptions.filename : mergeOptions.filename + ".js"; + await fs.writeFileSync(path.resolve(sourceDir, mergeOptions.dest, filename), `module.exports = ${JSON.stringify(SIDEBAR)}`); + + } catch (ex) { + console.log(ex); + } + } +}); \ No newline at end of file diff --git a/lib/options.js b/lib/options.js new file mode 100644 index 0000000..42953ff --- /dev/null +++ b/lib/options.js @@ -0,0 +1,5 @@ +module.exports = { + mode: "default", // 模式 + dest: ".vuepress", // 暴露 sidebar 的路径 + filename: 'sidebar' +} \ No newline at end of file diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..b26127e --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,62 @@ +const filterRootMarkdowns = page => page.split.length !== 1; // 过滤 docs 目录下的 md 文件 +const filterDepthOneMarkdowns = page => page.split.length === 2; // 筛选出深度为 1 的 md 文件 +const filterDepthTwoMarkdowns = page => page.split.length === 3; // 筛选出深度为 2 的 md 文件 + +const addDepthOne = pages => pages.reduce((acc = [], cur) => { + const name = cur.split[0]; + const filename = cur.split[1]; + const findCur = acc.find(p => p.name === name); + + if (findCur) { + findCur.children.push(filename); + } else { + acc.push({ + name, + children: [filename] + }); + } + + return acc; +}, []); + +const addDepthTwo = pages => pages.reduce((acc = [], cur) => { + const name = cur.split[0]; + const sub = cur.split[1]; + const filename = cur.split[2]; + const findCur = acc.find(p => p.name === name); + + if (findCur) { + const findSub = findCur.children.find(p => p.name === sub); + + findSub ? findSub.children.push(filename) : findCur.children.push({ name: sub, children: [filename] }) + } else { + acc.push({ + name, + children: [{ name: sub, children: [filename] }] + }); + } + + return acc; +}, []); + +const genSidebar = (title, children = [''], collapsable = false, sidebarDepth = 1) => ([{ + title, + collapsable, + sidebarDepth, + children +}]); + +const genRoute = (...names) => { + const joins = names.join("/"); + return `${joins.startsWith("/") ? '' : '/'}${joins}${joins.endsWith("/") ? '' : '/'}`; +} + +module.exports = { + filterRootMarkdowns, + filterDepthOneMarkdowns, + filterDepthTwoMarkdowns, + addDepthOne, + addDepthTwo, + genSidebar, + genRoute +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..54afd9e --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "name": "vuepress-plugin-auto-sidebar", + "version": "0.0.1", + "description": "A vuepress plugin for generate sidebar", + "keywords": ["vuepress", "auto-sidebar", "sidebar"], + "main": "index.js", + "author": "shanyuhai123", + "license": "MIT" +}