[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: ulivz # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: ulivz # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with a single custom sponsorship URL\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.temp*\ndocs2\ndist\n"
  },
  {
    "path": ".release-it.json",
    "content": "{\n  \"src\": {\n    \"tagName\": \"v%s\",\n    \"commitMessage\": \"%s\"\n  },\n  \"increment\": \"conventional:angular\",\n  \"beforeChangelogCommand\": \"conventional-changelog -p angular -i CHANGELOG.md -s\",\n  \"changelogCommand\": \"conventional-changelog -p angular | tail -n +3\",\n  \"safeBump\": false\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [0.6.1](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.6.0...v0.6.1) (2020-01-15)\n\n\n### Bug Fixes\n\n* 1. fail to parse pre tag, may cause code loss issues; 2.transformheander should ignore empty string ([3726743](https://github.com/ulivz/vuepress-plugin-yuque/commit/3726743f97c722706e66d0a28048eda231102159))\n* re-instantiate when repoId has been changed ([565a347](https://github.com/ulivz/vuepress-plugin-yuque/commit/565a347039cad6ab13d94ab069025de319e40da8))\n\n\n\n<a name=\"0.6.0\"></a>\n# [0.6.0](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.5.5...v0.6.0) (2019-04-05)\n\n\n### Features\n\n* yuqueLink & yuqueLinkHtml option ([b3d7d06](https://github.com/ulivz/vuepress-plugin-yuque/commit/b3d7d06))\n\n\n\n<a name=\"0.5.5\"></a>\n## [0.5.5](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.5.4...v0.5.5) (2019-04-05)\n\n\n### Bug Fixes\n\n* typo ([2a0b86b](https://github.com/ulivz/vuepress-plugin-yuque/commit/2a0b86b))\n\n\n\n<a name=\"0.5.4\"></a>\n## [0.5.4](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.5.3...v0.5.4) (2019-04-05)\n\n\n### Bug Fixes\n\n* ## ... shouldn't be considered as title ([f30c893](https://github.com/ulivz/vuepress-plugin-yuque/commit/f30c893))\n\n\n\n<a name=\"0.5.3\"></a>\n## [0.5.3](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.5.2...v0.5.3) (2019-04-05)\n\n\n### Bug Fixes\n\n* **html:** table's styles cannot be removed ([1035eb3](https://github.com/ulivz/vuepress-plugin-yuque/commit/1035eb3))\n\n\n\n<a name=\"0.5.2\"></a>\n## [0.5.2](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.5.1...v0.5.2) (2019-04-05)\n\n\n### Bug Fixes\n\n* **html:** need to escape twice ([923b31a](https://github.com/ulivz/vuepress-plugin-yuque/commit/923b31a))\n\n\n\n<a name=\"0.5.1\"></a>\n## [0.5.1](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.5.0...v0.5.1) (2019-04-05)\n\n\n### Bug Fixes\n\n* **html:** regression of escape html in code ([8f638e3](https://github.com/ulivz/vuepress-plugin-yuque/commit/8f638e3))\n\n\n\n<a name=\"0.5.0\"></a>\n# [0.5.0](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.4.0...v0.5.0) (2019-04-05)\n\n\n### Features\n\n* **$core:** bump vuepress-plugin-medium ([cce0e73](https://github.com/ulivz/vuepress-plugin-yuque/commit/cce0e73))\n* **html:** remove html tags in code and remove table styles ([fe75e46](https://github.com/ulivz/vuepress-plugin-yuque/commit/fe75e46))\n\n\n\n<a name=\"0.4.0\"></a>\n# [0.4.0](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.3.1...v0.4.0) (2019-04-05)\n\n\n### Features\n\n* **$core:** functional source option (using markdown when return 'markdown') ([5ef63cd](https://github.com/ulivz/vuepress-plugin-yuque/commit/5ef63cd))\n\n\n\n<a name=\"0.3.1\"></a>\n## [0.3.1](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.3.0...v0.3.1) (2019-02-14)\n\n\n### Bug Fixes\n\n* **$core:** cannot use correct api base url for custom yuque domain ([818343e](https://github.com/ulivz/vuepress-plugin-yuque/commit/818343e))\n\n\n\n<a name=\"0.3.0\"></a>\n# [0.3.0](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.2.1...v0.3.0) (2019-02-11)\n\n\n### Bug Fixes\n\n* **$core:** throw error when toc's length is 1 ([df4e48c](https://github.com/ulivz/vuepress-plugin-yuque/commit/df4e48c))\n\n\n### Features\n\n* **$toc:** always set top-level node to branch node instead of leaf node ([44216dd](https://github.com/ulivz/vuepress-plugin-yuque/commit/44216dd))\n\n\n\n<a name=\"0.2.1\"></a>\n## [0.2.1](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.2.0...v0.2.1) (2019-02-11)\n\n\n### Bug Fixes\n\n* **$core:** cannot fetch data from private repo (close: [#2](https://github.com/ulivz/vuepress-plugin-yuque/issues/2)) ([a59c420](https://github.com/ulivz/vuepress-plugin-yuque/commit/a59c420))\n* **$core:** throw error since \"prettify\" doesn't check null (close: [#1](https://github.com/ulivz/vuepress-plugin-yuque/issues/1)) ([1110274](https://github.com/ulivz/vuepress-plugin-yuque/commit/1110274))\n\n\n\n<a name=\"0.2.0\"></a>\n# [0.2.0](https://github.com/ulivz/vuepress-plugin-yuque/compare/v0.1.0...v0.2.0) (2019-02-08)\n\n\n### Bug Fixes\n\n* **$core:** changing repoUrl under dev doesn't take effect ([93e0c06](https://github.com/ulivz/vuepress-plugin-yuque/commit/93e0c06))\n* **$core:** empty node: Cannot read property 'format' of undefined ([3c0c3bc](https://github.com/ulivz/vuepress-plugin-yuque/commit/3c0c3bc))\n* **$toc:** using safe pop to avoid empty stack ([6eb19b4](https://github.com/ulivz/vuepress-plugin-yuque/commit/6eb19b4))\n\n\n### Features\n\n* **$core:** enable .html suffix by default ([9a5167f](https://github.com/ulivz/vuepress-plugin-yuque/commit/9a5167f))\n\n\n\n<a name=\"0.1.0\"></a>\n# 0.1.0 (2019-02-08)\n\n\n### Bug Fixes\n\n* **$fetch:** cannot save cache properly ([4b21277](https://github.com/ulivz/vuepress-plugin-yuque/commit/4b21277))\n\n\n### Features\n\n* **$core:** `authToken` option ([e953197](https://github.com/ulivz/vuepress-plugin-yuque/commit/e953197))\n* **$core:** `html` option ([185fcab](https://github.com/ulivz/vuepress-plugin-yuque/commit/185fcab))\n* **$core:** `home` option and default title and description ([7b2505d](https://github.com/ulivz/vuepress-plugin-yuque/commit/7b2505d))\n* **$core:** enable `medium-zoom` by default ([3538cc8](https://github.com/ulivz/vuepress-plugin-yuque/commit/3538cc8))\n* **$core:** handle uncreated page ([5665483](https://github.com/ulivz/vuepress-plugin-yuque/commit/5665483))\n* **$fetch:** env: `SKIP_CACHE` and `AUTH_TOKEN` ([c0530d9](https://github.com/ulivz/vuepress-plugin-yuque/commit/c0530d9))\n* **$toc:** push branch node when the depth of last node is 1 ([8809986](https://github.com/ulivz/vuepress-plugin-yuque/commit/8809986))\n* **$html:** extract headers from yuque's HTML markups ([88900ae](https://github.com/ulivz/vuepress-plugin-yuque/commit/88900ae))\n* **$html:** highlight code fence block at build time ([475448b](https://github.com/ulivz/vuepress-plugin-yuque/commit/475448b))\n* **$core:** leverage \"html content\" by default for now ([85801e7](https://github.com/ulivz/vuepress-plugin-yuque/commit/85801e7))\n* **$fetch:** only enable cache under dev mode ([98cc5d1](https://github.com/ulivz/vuepress-plugin-yuque/commit/98cc5d1))\n* **$core:** `repoUrl` option ([81d07dd](https://github.com/ulivz/vuepress-plugin-yuque/commit/81d07dd))\n* **$core:** use page's default format ([7b41867](https://github.com/ulivz/vuepress-plugin-yuque/commit/7b41867))\n\n\n\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) ULVIZ <chl814@foxmail.com> (https://github.com/ulivz)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# vuepress-plugin-yuque\n\n[![NPM version](https://badgen.net/npm/v/vuepress-plugin-yuque)](https://npmjs.com/package/vuepress-plugin-yuque) [![NPM downloads](https://badgen.net/npm/dm/vuepress-plugin-yuque)](https://npmjs.com/package/vuepress-plugin-yuque) \n\n> 本插件需要 VuePress >= `1.0.0-alpha.37`。\n\n<img src=\"./.media/hero.png\">\n\n## 特性\n\n- **简单**：Zero-Markdown，只需配置你的语雀 repo 地址，就能获得一个 VuePress 站点；\n- **高效**：自动生成的文档主页、侧边栏让你享受 “高效” 的文档生成体验；\n- **缓存**：完美地解决语雀 Open API 调用次数超限的问题；\n\n想了解更多，请移步：\n\n- **案例**\n  - [视频演示](https://player.youku.com/embed/XNDA1MzAwMDIzNg==)\n  - [**Site**](https://antd-course.ulivz.com/)\n  - [语雀](https://www.yuque.com/ant-design/course)\n  - [源码](https://github.com/ulivz/vuepress-plugin-yuque/tree/master/example/.vuepress)\n- **文档**\n  - [**Site**](https://vuepress-plugin-yuque.ulivz.com/)\n  - [语雀](https://www.yuque.com/vuepress/vuepress-plugin-yuque)\n  - [源码](https://github.com/ulivz/vuepress-plugin-yuque/tree/master/docs/.vuepress)\n\n## 快速上手\n\n在 VuePress 中配置 `repoUrl`：\n\n```js\n// .vuepress/config.js\nmodule.exports = {\n  title: 'Ant Design 实战教程',\n  description: '基于 umi 的 Ant Design 实战教程',\n  plugins: [\n    ['vuepress-plugin-yuque', {\n      repoUrl: 'https://www.yuque.com/ant-design/course',\n    }]\n  ]\n}\n```\n\n你就能获得这个[**Site**](https://antd-course.ulivz.com/)，更多使用方法，可参见[文档](https://vuepress-plugin-yuque.ulivz.com/)。\n\n## Contributing\n\n1. Fork it!\n2. Create your feature branch: `git checkout -b my-new-feature`\n3. Commit your changes: `git commit -am 'Add some feature'`\n4. Push to the branch: `git push origin my-new-feature`\n5. Submit a pull request :D\n\n\n## Author\n\n**vuepress-plugin-yuque** © [ULVIZ](https://github.com/ulivz), Released under the [MIT](./LICENSE) License.<br>\nAuthored and maintained by ULVIZ with help from contributors ([list](https://github.com/ulivz/vuepress-plugin-yuque/contributors)).\n\n> [github.com/ulivz](https://github.com/ulivz) · GitHub [@ULVIZ](https://github.com/ulivz) · Twitter [@_ulivz](https://twitter.com/_ulivz)\n"
  },
  {
    "path": "docs/.vuepress/config.js",
    "content": "module.exports = {\n  head: [\n    ['link', { rel: 'icon', href: `https://cdn.nlark.com/yuque/0/2019/png/242808/1549571925285-2372b0a0-0234-421c-a139-00ea16f1a106.png` }],\n    ['meta', { name: 'theme-color', content: '#3eaf7c' }],\n    ['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],\n    ['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }],\n    ['meta', { name: 'msapplication-TileColor', content: '#000000' }],\n    ['meta', { name: 'referrer', content: 'no-referrer' }]\n  ],\n  themeConfig: {\n    repo: 'ulivz/vuepress-plugin-yuque',\n    nav: [\n      { text: '指南', link: '/intro.html' },\n      { text: '配置', link: '/config.html' },\n      { text: 'CHANGELOG', link: '/changelog.html' },\n    ]\n  },\n  async additionalPages () {\n    const fetch = require('node-fetch')\n    const response = await fetch('https://raw.githubusercontent.com/ulivz/vuepress-plugin-yuque/master/CHANGELOG.md')\n    const content = await response.text()\n    return [\n      {\n        path: '/changelog.html',\n        content\n      }\n    ]\n  },\n  plugins: [\n    [\n      require('../../lib'),\n      {\n        html: true,\n        yuqueLink: true,\n        repoUrl: 'https://www.yuque.com/vuepress/vuepress-plugin-yuque',\n        home: {\n          actionText: 'Getting Started →',\n          actionLink: '/intro.html',\n          heroImage: 'https://cdn.nlark.com/yuque/0/2019/png/242808/1549571925285-2372b0a0-0234-421c-a139-00ea16f1a106.png',\n          footer: `Copyright © ULIVZ`,\n          features: [\n            { title: '简单', details: 'Zero-Markdown，只需配置你的语雀 repo 地址，就能获得一个 VuePress 站点' },\n            { title: '高效', details: '自动生成的文档主页、侧边栏让你享受 “高效” 的文档生成体验' },\n            { title: '缓存', details: '完美地解决语雀 Open API 调用次数超限的问题' },\n          ]\n        }\n      }\n    ]\n  ]\n}\n"
  },
  {
    "path": "docs/.vuepress/styles/index.styl",
    "content": ".content\n  img\n    max-width 100% !important\n\n.home .hero img\n    max-height 250px!important\n"
  },
  {
    "path": "example/.vuepress/config.js",
    "content": "module.exports = {\n  title: 'Ant Design 实战教程',\n  description: '基于 umi 的 Ant Design 实战教程',\n  head: [\n    ['link', {\n      rel: 'icon',\n      href: `https://cdn.nlark.com/yuque/0/2019/png/242808/1549571925285-2372b0a0-0234-421c-a139-00ea16f1a106.png`\n    }],\n    ['meta', { name: 'theme-color', content: '#3eaf7c' }],\n    ['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],\n    ['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }],\n    ['meta', { name: 'msapplication-TileColor', content: '#000000' }],\n    ['meta', { name: 'referrer', content: 'no-referrer' }]\n  ],\n  plugins: [\n    [\n      require('../../lib'),\n      {\n        repoUrl: 'https://www.yuque.com/ant-design/course',\n        home: {\n          features: [\n            { title: '循序渐进', details: '本教程的难度依次递进，为阅读者呈现舒适的学习曲线' },\n            { title: '值得信赖', details: '由 antd 团队亲自打造，从技术栈、生态、研发流程等来为你提供系统化的学习体验' },\n            { title: '最佳实践', details: '通过结合实际开发过程中的案例，来描述不同场景下的最佳实践' },\n          ]\n        }\n      }\n    ]\n  ]\n}\n"
  },
  {
    "path": "lib/__test__/__snapshots__/toc.test.js.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`getSidebarByToc 1`] = `\nArray [\n  Object {\n    \"children\": Array [],\n    \"collapsable\": false,\n    \"path\": \"/intro.html\",\n    \"title\": \"前言\",\n  },\n  Object {\n    \"children\": Array [\n      Array [\n        \"/sc1lvc.html\",\n        \"前端开发的演变\",\n      ],\n      Array [\n        \"/wybhm9.html\",\n        \"初始化项目\",\n      ],\n      Array [\n        \"/fd5af7.html\",\n        \"第一个组件\",\n      ],\n      Array [\n        \"/agmsgo.html\",\n        \"使用 Ant Design 组件\",\n      ],\n      Array [\n        \"/goozth.html\",\n        \"受控组件与非受控组件\",\n      ],\n    ],\n    \"collapsable\": false,\n    \"title\": \"第一章: 基础知识\",\n  },\n  Object {\n    \"children\": Array [\n      Array [\n        \"/layout.html\",\n        \"基本布局\",\n      ],\n      Array [\n        \"/ghalng.html\",\n        \"侧边导航\",\n      ],\n      Array [\n        \"/ipsba8.html\",\n        \"路由配置\",\n      ],\n    ],\n    \"collapsable\": false,\n    \"path\": \"/chapter2.html\",\n    \"title\": \"第二章: 布局与路由\",\n  },\n  Object {\n    \"children\": Array [\n      Array [\n        \"/abl3ad.html\",\n        \"使用 model\",\n      ],\n      Array [\n        \"/dsl8ee.html\",\n        \"搭建基于 model 的卡片列表页面\",\n      ],\n      Array [\n        \"/ig6mzb.html\",\n        \"在 model 中请求服务端数据\",\n      ],\n      Array [\n        \"/kmmq56.html\",\n        \"模拟服务端数据\",\n      ],\n    ],\n    \"collapsable\": false,\n    \"path\": \"/chapter3.html\",\n    \"title\": \"第三章: 小试牛刀\",\n  },\n  Object {\n    \"children\": Array [\n      Array [\n        \"/ndfx96.html\",\n        \"表格\",\n      ],\n      Array [\n        \"/up1dn3.html\",\n        \"表单\",\n      ],\n      Array [\n        \"/dk8xsp.html\",\n        \"图表\",\n      ],\n    ],\n    \"collapsable\": false,\n    \"path\": \"/chapter4.html\",\n    \"title\": \"第四章: 复杂页面\",\n  },\n  Object {\n    \"children\": Array [\n      Array [\n        \"/customized_styles.html\",\n        \"自定义样式\",\n      ],\n      Array [\n        \"/wvbsue.html\",\n        \"上传与下载\",\n      ],\n      Array [\n        \"/aut0sr.html\",\n        \"国际化\",\n      ],\n      Array [\n        \"/lifemethods.html\",\n        \"React 的生命周期\",\n      ],\n      Array [\n        \"/auth.html\",\n        \"权限\",\n      ],\n      Array [\n        \"/unittest.html\",\n        \"单元测试\",\n      ],\n      Array [\n        \"/typescript.html\",\n        \"使用 TypeScript\",\n      ],\n    ],\n    \"collapsable\": false,\n    \"title\": \"第五章: 进阶功能\",\n  },\n  Object {\n    \"children\": Array [\n      Array [\n        \"/byllph.html\",\n        \"你需要了解的 ES6 语法\",\n      ],\n      Array [\n        \"/tydf0a.html\",\n        \"深入理解 umi\",\n      ],\n      Array [\n        \"/about.html\",\n        \"关于我们\",\n      ],\n    ],\n    \"collapsable\": false,\n    \"title\": \"附录\",\n  },\n]\n`;\n\nexports[`getSidebarByToc 2`] = `\nArray [\n  Object {\n    \"children\": Array [\n      Array [\n        \"/intro.html\",\n        \"介绍\",\n      ],\n      Array [\n        \"/getting-started.html\",\n        \"快速上手\",\n      ],\n      Array [\n        \"/export-first-website.html\",\n        \"导出第一个站点\",\n      ],\n    ],\n    \"collapsable\": false,\n    \"title\": \"指南\",\n  },\n  Object {\n    \"children\": Array [],\n    \"collapsable\": false,\n    \"path\": \"/config.html\",\n    \"title\": \"配置\",\n  },\n]\n`;\n\nexports[`getSidebarByToc 3`] = `\nArray [\n  Object {\n    \"children\": Array [\n      Array [\n        \"/intro.html\",\n        \"介绍\",\n      ],\n      Array [\n        \"/getting-started.html\",\n        \"快速上手\",\n      ],\n      Array [\n        \"/generate-homepage.html\",\n        \"生成主页\",\n      ],\n      Array [\n        \"/cache.html\",\n        \"缓存\",\n      ],\n      Array [\n        \"/private-repo.html\",\n        \"私有仓库\",\n      ],\n    ],\n    \"collapsable\": false,\n    \"title\": \"指南\",\n  },\n  Object {\n    \"children\": Array [],\n    \"collapsable\": false,\n    \"path\": \"/config.html\",\n    \"title\": \"配置\",\n  },\n  Object {\n    \"children\": Array [],\n    \"collapsable\": false,\n    \"title\": \"进阶\",\n  },\n  Object {\n    \"children\": Array [],\n    \"collapsable\": false,\n    \"path\": \"/a.html\",\n    \"title\": \"A\",\n  },\n  Object {\n    \"children\": Array [\n      Array [\n        \"/b-1.html\",\n        \"B-1\",\n      ],\n    ],\n    \"collapsable\": false,\n    \"path\": \"/b.html\",\n    \"title\": \"B\",\n  },\n  Object {\n    \"children\": Array [],\n    \"collapsable\": false,\n    \"path\": \"/c.html\",\n    \"title\": \"C\",\n  },\n]\n`;\n"
  },
  {
    "path": "lib/__test__/toc.constant.js",
    "content": "const TOC_1 = [\n  { title: '前言', slug: 'intro', depth: 1 },\n  { title: '第一章: 基础知识', slug: '#', depth: 1 },\n  { title: '前端开发的演变', slug: 'sc1lvc', depth: 2 },\n  { title: '初始化项目', slug: 'wybhm9', depth: 2 },\n  { title: '第一个组件', slug: 'fd5af7', depth: 2 },\n  { title: '使用 Ant Design 组件', slug: 'agmsgo', depth: 2 },\n  { title: '受控组件与非受控组件', slug: 'goozth', depth: 2 },\n  { title: '第二章: 布局与路由', slug: 'chapter2', depth: 1 },\n  { title: '基本布局', slug: 'layout', depth: 2 },\n  { title: '侧边导航', slug: 'ghalng', depth: 2 },\n  { title: '路由配置', slug: 'ipsba8', depth: 2 },\n  { title: '第三章: 小试牛刀', slug: 'chapter3', depth: 1 },\n  { title: '使用 model', slug: 'abl3ad', depth: 2 },\n  { title: '搭建基于 model 的卡片列表页面', slug: 'dsl8ee', depth: 2 },\n  { title: '在 model 中请求服务端数据', slug: 'ig6mzb', depth: 2 },\n  { title: '模拟服务端数据', slug: 'kmmq56', depth: 2 },\n  { title: '第四章: 复杂页面', slug: 'chapter4', depth: 1 },\n  { title: '表格', slug: 'ndfx96', depth: 2 },\n  { title: '表单', slug: 'up1dn3', depth: 2 },\n  { title: '图表', slug: 'dk8xsp', depth: 2 },\n  { title: '第五章: 进阶功能', slug: '#', depth: 1 },\n  { title: '自定义样式', slug: 'customized_styles', depth: 2 },\n  { title: '上传与下载', slug: 'wvbsue', depth: 2 },\n  { title: '国际化', slug: 'aut0sr', depth: 2 },\n  { title: 'React 的生命周期', slug: 'lifemethods', depth: 2 },\n  { title: '权限', slug: 'auth', depth: 2 },\n  { title: '单元测试', slug: 'unittest', depth: 2 },\n  { title: '使用 TypeScript', slug: 'typescript', depth: 2 },\n  { title: '附录', slug: '#', depth: 1 },\n  { title: '你需要了解的 ES6 语法', slug: 'byllph', depth: 2 },\n  { title: '深入理解 umi', slug: 'tydf0a', depth: 2 },\n  { title: '关于我们', slug: 'about', depth: 2 }\n]\n\nconst TOC_2 = [\n  { title: '指南', slug: '#', depth: 1 },\n  { title: '介绍', slug: 'intro', depth: 2 },\n  { title: '快速上手', slug: 'getting-started', depth: 2 },\n  { title: '导出第一个站点', slug: 'export-first-website', depth: 2 },\n  { title: '配置', slug: 'config', depth: 1 }\n]\n\nconst TOC_3 = [\n  { title: '指南', slug: '#', depth: 1 },\n  { title: '介绍', slug: 'intro', depth: 2 },\n  { title: '快速上手', slug: 'getting-started', depth: 2 },\n  { title: '生成主页', slug: 'generate-homepage', depth: 2 },\n  { title: '缓存', slug: 'cache', depth: 2 },\n  { title: '私有仓库', slug: 'private-repo', depth: 2 },\n  { title: '配置', slug: 'config', depth: 1 },\n  { title: '进阶', slug: '#', depth: 1 },\n  { title: 'A', slug: 'a', depth: 1 },\n  { title: 'B', slug: 'b', depth: 1 },\n  { title: 'B-1', slug: 'b-1', depth: 2 },\n  { title: 'C', slug: 'c', depth: 1 },\n]\n\nmodule.exports = [\n  TOC_1,\n  TOC_2,\n  TOC_3\n]\n"
  },
  {
    "path": "lib/__test__/toc.test.js",
    "content": "const { getSidebarByToc } = require('../toc')\nconst tocs = require('./toc.constant')\n\ntest('getSidebarByToc', () => {\n  tocs.forEach(toc => {\n    const sidebar = getSidebarByToc(toc)\n    expect(sidebar).toMatchSnapshot()\n  })\n})\n"
  },
  {
    "path": "lib/client.js",
    "content": "import './style.styl'\n"
  },
  {
    "path": "lib/compose.js",
    "content": "/**\n * Expose compose.\n */\n\nmodule.exports = function compose(...processors) {\n  if (processors.length === 0)\n    return (input) => input\n  if (processors.length === 1)\n    return processors[0]\n  return processors.reduce((prev, next) => {\n    return (...args) => next(prev(...args))\n  })\n}\n"
  },
  {
    "path": "lib/constant.js",
    "content": "const pkg = require('./../package')\n\nmodule.exports = {\n  PACKAGE_NAME: pkg.name\n}\n"
  },
  {
    "path": "lib/fetch.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst fetch = require('node-fetch')\n\n/**\n * Expose a wrapped fetch which handles network error.\n */\n\nmodule.exports = function (url, options = {}) {\n  return fetch(url, options)\n    .then(handleResponse, handleNetworkError)\n}\n\n/**\n * Response handler\n *\n * @param {Response} response\n * @returns {Promise<any>>|never}\n */\n\nfunction handleResponse(response) {\n  if (response.ok) {\n    return response.json()\n  }\n  return response.json().then(error => {\n    throw error\n  })\n}\n\n/**\n * Network error handler\n *\n * @param {Error} error\n */\n\nfunction handleNetworkError(error) {\n  throw {\n    msg: error.message\n  }\n}\n"
  },
  {
    "path": "lib/html.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst cheerio = require('cheerio')\nconst compose = require('./compose')\nconst escapeHtml = require('escape-html')\n\n/**\n * Expose a object containing the utilities of handling markups.\n */\n\nmodule.exports = {\n  prettify\n}\n\nconst transformHeaders = compose(\n  ...[\n    'h1',\n    'h2',\n    'h3',\n    'h4',\n    'h5',\n    'h6',\n  ].map((h, i) => $ => {\n      $(h).replaceWith((_i, el) => {\n        const text = $(el).text().trim()\n        if(!text) {\n          return\n        }\n        return `\\n\\n ${getHash(i + 1)} ${text} \\n\\n`\n      })\n      return $\n    }\n  ),\n  highlight,\n  escapeHTMLTagInCode,\n  removeTableStyls,\n)\n\nfunction getHash(i) {\n  return [...Array(i)].map(() => '#').join('')\n}\n\nfunction prettify(html) {\n  html = prune(html)\n  const $ = cheerio.load(html, {\n    // ref: https://github.com/cheeriojs/cheerio/issues/565\n    decodeEntities: false\n  })\n  transformHeaders($)\n  return $('body').html()\n}\n\nfunction prune(html) {\n  return html\n    .replace(/<p><br\\s\\/><\\/p>/g, '')\n    .replace(/<p><span><br\\s\\/><\\/span><\\/p>/g, '')\n}\n\nconst CODE_FENCE = '```'\n\nfunction highlight($) {\n  $('pre').replaceWith((i, el) => {\n    const $el = $(el)\n    const $code = $el.children('code')\n    const lang = $el.attr('data-lang')\n    const code = $code.length ? $code.text() : $el.text()\n    return `\\n\\n ${CODE_FENCE} ${lang} \\n ${code} \\n ${CODE_FENCE} \\n\\n`\n  })\n  return $\n}\n\nfunction escapeHTMLTagInCode($) {\n  $('code').replaceWith((i, el) => {\n    const content = $(el).text()\n    return escapeHtml(`<code>${escapeHtml(content)}</code>`)\n  })\n  return $\n}\n\nfunction removeTableStyls($) {\n  $('table').css('width', '')\n  return $\n}\n"
  },
  {
    "path": "lib/index.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst assert = require('assert')\nconst { chalk, parseFrontmatter, path } = require('@vuepress/shared-utils')\nconst Yuque = require('./yuque')\nconst { getSidebarByToc } = require('./toc')\nconst spinner = require('./spinner')\nconst { prettify } = require('./html')\nconst { PACKAGE_NAME } = require('./constant')\nconst debug = require('debug')(PACKAGE_NAME)\n\n/**\n * Expose vuepress-plugin-yuque\n */\n\nmodule.exports = (opts, ctx) => {\n  return {\n    name: PACKAGE_NAME,\n\n    enhanceAppFiles: [\n      path.join(__dirname, 'client.js')\n    ],\n\n    plugins: [\n      ['@vuepress/medium-zoom', true],\n    ],\n\n    chainMarkdown(config) {\n      if (opts.html) {\n        return\n      }\n      // Disable `html` for now. Many yuque writers would write raw HTML in the markdown\n      // But only these markups under inline code(`) will be transpiled successfully when\n      // `html` is enabled.\n      config\n        .options\n        .html(false)\n    },\n\n    async ready() {\n      let { repoId, repoUrl, authToken, source } = opts\n\n      if (repoId) {\n        assert(\n          typeof repoId === 'string' ||\n          typeof repoId === 'number',\n          `[${PACKAGE_NAME}] repoId should be string or number, but got ${repoId}`\n        )\n      } else if (repoUrl) {\n        assert(\n          typeof repoUrl === 'string',\n          `[${PACKAGE_NAME}] repoUrl should be string, but got ${repoId}`\n        )\n      } else {\n        throw new Error(`Expected repoId or repoUrl`)\n      }\n\n      Yuque.setAuthToken(authToken)\n\n      if (repoUrl) {\n        const targetRepo = await Yuque.inferRepoByUrl(repoUrl)\n        repoId = targetRepo.id\n      }\n\n      Yuque.setRepoId(repoId)\n      const yuque = Yuque.getInstance()\n\n      spinner.start(`Fetching repo detail ...`)\n      const repoDetail = await yuque.getRepoDetail()\n      if (!(repoDetail && repoDetail.data && repoDetail.data.name)) {\n        spinner.fail(\n          `Please check your repoId: ${chalk.yellow(repoId)} ` +\n          `response: ${JSON.stringify(repoDetail)}`\n        )\n        process.exit(1)\n      }\n      spinner.succeed(`Retrieved repo detail`)\n\n      const { name, description, user } = repoDetail.data\n      spinner.succeed(\n        `Your Yuque website: ${chalk.green(name)} ` +\n        `${chalk.gray(description)} ...`\n      )\n      spinner.start(`Fetching TOC ... `)\n\n      const toc = await yuque.getToc()\n      assert(\n        toc && toc.data,\n        `[${PACKAGE_NAME}] cannot get toc of ${repoId}`\n      )\n\n      debug('toc', toc.data)\n\n      spinner.succeed(`Retrieved TOC`)\n\n      // Apply sidebar config\n      const sidebar = getSidebarByToc(toc.data)\n      ctx.siteConfig.themeConfig = ctx.siteConfig.themeConfig || {}\n      ctx.siteConfig.themeConfig.sidebar = sidebar\n      if (!ctx.siteConfig.title) {\n        ctx.siteConfig.title = name\n      }\n      if (!ctx.siteConfig.description) {\n        ctx.siteConfig.description = description\n      }\n\n      let defaultActionLink\n\n      // Apply pages\n      for (const page of toc.data) {\n        const { title, slug } = page\n        // Once the slug is equal to '#', it means that current node\n        // is an empty node.\n        if (!slug || slug === '#') {\n          continue\n        }\n\n        spinner.start(`Fetching ${chalk.cyan(title)} ... `)\n\n        const { status, data } = await yuque.getPage(slug)\n        debug('status = ', status)\n\n        let postContent\n        if (status && status === 404) {\n          postContent = `# ${title}\\n > 此文档尚未创建`\n        } else {\n          const useMarkdown = typeof source === 'string'\n            ? source === 'markdown'\n            : typeof source === 'function'\n              ? source(page) === 'markdown'\n              : false\n          if (useMarkdown || data.format === 'markdown') {\n            postContent = data.body || ''\n          } else {\n            postContent = prettify(data.body_html || '')\n          }\n        }\n\n        const {\n          data: frontmatter,\n          content: strippedContent\n        } = parseFrontmatter(postContent)\n        const inferredTitle = inferTitle({}, strippedContent)\n\n        let content = inferredTitle\n          ? postContent\n          : `# ${title} \\n\\n ${postContent}`\n\n        if (opts.yuqueLink) {\n          content += opts.yuqueLinkHtml || `<br><br><a class=\"yuque-link\" target=\"_blank\" href=\"${repoUrl}/${slug}\"><svg viewBox=\"64 64 896 896\" class=\"\" data-icon=\"yuque\" width=\"1em\" height=\"1em\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M854.6 370.6c-9.9-39.4 9.9-102.2 73.4-124.4l-67.9-3.6s-25.7-90-143.6-98c-117.8-8.1-194.9-3-195-3 .1 0 87.4 55.6 52.4 154.7-25.6 52.5-65.8 95.6-108.8 144.7-1.3 1.3-2.5 2.6-3.5 3.7C319.4 605 96 860 96 860c245.9 64.4 410.7-6.3 508.2-91.1 20.5-.2 35.9-.3 46.3-.3 135.8 0 250.6-117.6 245.9-248.4-3.2-89.9-31.9-110.2-41.8-149.6zm-204.1 334c-10.6 0-26.2.1-46.8.3l-23.6.2-17.8 15.5c-47.1 41-104.4 71.5-171.4 87.6-52.5 12.6-110 16.2-172.7 9.6 18-20.5 36.5-41.6 55.4-63.1 92-104.6 173.8-197.5 236.9-268.5l1.4-1.4 1.3-1.5c4.1-4.6 20.6-23.3 24.7-28.1 9.7-11.1 17.3-19.9 24.5-28.6 30.7-36.7 52.2-67.8 69-102.2l1.6-3.3 1.2-3.4c13.7-38.8 15.4-76.9 6.2-112.8 22.5.7 46.5 1.9 71.7 3.6 33.3 2.3 55.5 12.9 71.1 29.2 5.8 6 10.2 12.5 13.4 18.7 1 2 1.7 3.6 2.3 5l5 17.7c-15.7 34.5-19.9 73.3-11.4 107.2 3 11.8 6.9 22.4 12.3 34.4 2.1 4.7 9.5 20.1 11 23.3 10.3 22.7 15.4 43 16.7 78.7 3.3 94.6-82.7 181.9-182 181.9z\"></path></svg> 使用语雀查看</a>`\n        }\n\n        const permalink = `/${slug}.html`\n\n        await ctx.addPage({\n          content,\n          frontmatter,\n          permalink\n        })\n\n        if (!defaultActionLink) {\n          defaultActionLink = permalink\n        }\n\n        spinner.succeed(`Retrieved ${chalk.cyan(title)} ... `)\n      }\n\n      if (ctx.pages.every(page => page.path !== '/')) {\n        const { home = {} } = opts\n        const { actionText, actionLink, heroImage, features, footer } = home\n\n        spinner.info(`Apply default homepage`)\n        await ctx.addPage({\n          content: '',\n          permalink: '/',\n          frontmatter: {\n            home: true,\n            heroImage: heroImage || user.large_avatar_url,\n            actionText: actionText || 'Getting Started →',\n            actionLink: actionLink || defaultActionLink,\n            features: features || undefined,\n            footer: footer || `Copyright © ${user.name}`,\n          }\n        })\n      }\n    }\n  }\n}\n\n/**\n * Infer title, forked from VuePress.\n */\nfunction inferTitle(frontmatter, strippedContent) {\n  if (frontmatter.home) {\n    return 'Home';\n  }\n  if (frontmatter.title) {\n    return frontmatter.title\n  }\n  const match = strippedContent.trim().match(/^#\\s+(.*)/);\n  if (match) {\n    return match[1];\n  }\n};\n"
  },
  {
    "path": "lib/spinner.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst ora = require('ora')\nconst { chalk } = require('@vuepress/shared-utils')\n\n/**\n * Expose a singleton of spinner\n */\n\nmodule.exports = !process.env.DEBUG\n  ? ora()\n  : [\n    'frame',\n    'clear',\n    'render',\n    'start',\n    'stop',\n    'succeed',\n    'fail',\n    'warn',\n    'info',\n    'stopAndPersist'\n  ].reduce((memo, key) => {\n    memo[key] = curry(key)\n    return memo\n  }, {})\n\nfunction curry(name) {\n  return (...args) => console.log(chalk.cyan(`spinner:${name}`), ...args)\n}\n"
  },
  {
    "path": "lib/stack.js",
    "content": "/**\n * Expose a simple stack\n */\n\nmodule.exports = class Stack {\n  constructor() {\n    this.elements = []\n  }\n\n  push(element) {\n    this.elements.push(element)\n  }\n\n  pop() {\n    return this.elements.pop()\n  }\n\n  peek() {\n    return this.elements[this.size() - 1]\n  }\n\n  size() {\n   return this.elements.length\n  }\n}\n"
  },
  {
    "path": "lib/store.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst Conf = require('conf')\n\n/**\n * Expose a object containing the utilities of cache.\n */\n\nmodule.exports = {\n  get,\n  init\n}\n\nlet store\n\nfunction init(configName) {\n  store = new Conf({\n    configName: configName\n  })\n  return store\n}\n\nfunction get(configName) {\n  if (store) {\n    return store\n  }\n  return init(configName)\n}\n\n\n"
  },
  {
    "path": "lib/style.styl",
    "content": ".yuque-link\n  border: 1px solid #333;\n  padding: 5px 10px;\n  color: #333;\n  border-radius: 3px;\n  font-weight: 200;\n  text-decoration none\n  svg\n    line-height: 20px;\n    vertical-align: text-bottom;\n"
  },
  {
    "path": "lib/toc.js",
    "content": "/**\n * Module dependencies.\n */\n\nconst Stack = require('./stack')\n\n/**\n * Expose a object containing the utilities of TOC.\n */\nmodule.exports = {\n  getSidebarByToc\n}\n\n/**\n * Transform yuque's toc to vuepress's sidebar config.\n *\n * @param {Array<TocNode>>} toc\n * @returns {Array<SidebarGroup>}\n */\n\nfunction getSidebarByToc(toc) {\n  if (toc.length === 1) {\n    return [{\n      path: toc[0].slug,\n      title: toc[0].title,\n      collapsable: false\n    }]\n  }\n\n  const stack = new Stack()\n  const sidebar = []\n  stack.push({\n    children: sidebar\n  })\n\n  for (let i = 0, l = toc.length; i < l; i++) {\n    const prev = toc[i - 1]\n    const cur = toc[i]\n    const next = toc[i + 1]\n\n    if (!prev) {\n      if (next.depth >= cur.depth) {\n        pushBranch(cur, stack)\n      } else {\n        pushLeaf(cur, stack)\n      }\n\n    } else if (!next) {\n      if (cur.depth >= prev.depth) {\n        pushLeaf(cur, stack)\n      } else {\n        stack.pop()\n        if (cur.depth === 1) {\n          pushBranch(cur, stack)\n        } else {\n          pushLeaf(cur, stack)\n        }\n      }\n\n    } else {\n      // Current node is the children node of previous node\n      if (cur.depth > prev.depth) {\n        if (next.depth > cur.depth) {\n          pushBranch(cur, stack)\n        } else {\n          pushLeaf(cur, stack)\n        }\n        // Current node is the adjacent node of previous node\n      } else if (cur.depth === prev.depth) {\n        if (next.depth > cur.depth) {\n          safePop(stack)\n          pushBranch(cur, stack)\n        } else if (next.depth === cur.depth) {\n          if (cur.depth === 1) {\n            safePop(stack)\n            pushBranch(cur, stack)\n          } else {\n            pushLeaf(cur, stack)\n          }\n        } else {\n          pushLeaf(cur, stack)\n        }\n        // Current node is the adjacent node previous node's parnent's node\n      } else if (cur.depth < prev.depth) {\n        if (next.depth > cur.depth) {\n          safePop(stack)\n          pushBranch(cur, stack)\n        } else if (next.depth === cur.depth) {\n          if (cur.depth === 1) {\n            safePop(stack)\n            pushBranch(cur, stack)\n          } else {\n            safePop(stack)\n            pushLeaf(cur, stack)\n          }\n        } else {\n          safePop(stack)\n          pushLeaf(cur, stack)\n        }\n      }\n    }\n  }\n  return sidebar\n}\n\nfunction safePop(stack) {\n  if (stack.size() === 1) {\n    return\n  }\n  stack.pop()\n}\n\n/**\n * Push branch node\n *\n * @param {TocNode} node\n * @param {Stack} stack\n */\n\nfunction pushBranch(node, stack) {\n  const group = getBranch(node)\n  stack.peek().children.push(group)\n  stack.push(group)\n}\n\n/**\n * Push leaf node\n *\n * @param {TocNode} node\n * @param {Stack} stack\n */\n\nfunction pushLeaf(node, stack) {\n  stack.peek().children.push(getLeaf(node))\n}\n\n/**\n * Get leaf node for vuepress's sidebar group\n *\n * @param {string} title\n * @param {string} slug\n * @returns {Array<string>}\n */\n\nfunction getLeaf({\n  title,\n  slug\n}) {\n  return [`/${slug}.html`, title]\n}\n\n/**\n * Get branch node for vuepress's sidebar group\n *\n * @param {string} title\n * @param {string} slug\n * @returns {SidebarGroup}\n */\n\nfunction getBranch({\n  title,\n  slug\n}) {\n  const group = {\n    title,\n    collapsable: false,\n    children: []\n  }\n  if (slug && slug !== '#') {\n    group.path = `/${slug}.html`\n  }\n  return group\n}\n\n"
  },
  {
    "path": "lib/yuque.js",
    "content": "const assert = require('assert')\nconst url = require('url')\nconst wfetch = require('./fetch')\nconst store = require('./store')\nconst { hash, logger, chalk } = require('@vuepress/shared-utils')\nconst { PACKAGE_NAME } = require('./constant')\nconst debug = require('debug')(`${PACKAGE_NAME}:yuque`)\n\nconst AUTH_TOKEN = process.env.YUQUE_QUTH_TOKEN\nconst SKIP_CACHE = process.env.SKIP_CACHE\nconst isProduction = process.env.NODE_ENV === 'production'\n\nlet instance\nlet repoId\nlet authToken\n\nmodule.exports = class Yuque {\n  static setRepoId(id) {\n    repoId = id\n  }\n\n  static setAuthToken(token) {\n    authToken = token\n  }\n\n  static getInstance() {\n    if (!instance) {\n      instance = new Yuque(repoId)\n    }\n    if (instance.repoId !== repoId) {\n      instance = new Yuque(repoId)\n    }\n    return instance\n  }\n\n  static async fetch(url, options = {}) {\n    debug('fetch', url, 'with', JSON.stringify(options, null, 2))\n    const { useCache = true } = options\n    const key = hash(url + JSON.stringify(options))\n    const cacheKey = `fetch.${key}`\n    let yuque\n    if (repoId) {\n      yuque = Yuque.getInstance()\n    }\n    if (yuque && !isProduction && useCache && !SKIP_CACHE) {\n      const cached = yuque.store.get(cacheKey)\n      if (cached) {\n        debug(`Using cache for ${chalk.yellow(url)}`)\n        return cached\n      }\n    }\n\n    let response\n    const foptions = {}\n    if (authToken || AUTH_TOKEN) {\n      foptions.headers = {\n        'X-Auth-Token': authToken || AUTH_TOKEN\n      }\n    }\n\n    try {\n      response = await wfetch(url, foptions)\n      yuque && yuque.store.set(cacheKey, response)\n      return response\n    } catch (e) {\n      return e\n    }\n  }\n\n  static async get(base, path) {\n    path = `${base}${path}`\n    return Yuque.fetch(path)\n  }\n\n  static async getRepos(base, repoId) {\n    return Yuque.get(base, `groups/${repoId}/repos`)\n  }\n\n  static async getRepoDetail(base, repoId) {\n    return Yuque.get(base, `repos/${repoId}`)\n  }\n\n  static async getToc(base, repoId) {\n    return this.get(base, `repos/${repoId}/toc`)\n  }\n\n  static async getPage(base, repoId, slug) {\n    return this.get(base, `repos/${repoId}/docs/${slug}?raw=1`)\n  }\n\n  static async inferRepoByUrl(repoUrl) {\n    const { protocol, host, pathname } = url.parse(repoUrl)\n    assert(\n      typeof pathname === 'string',\n      `[CANNOT_RESOLVE_PATHNAME] Cannot infer repoId from repoUrl: ${repoUrl}`\n    )\n\n    const normalizedPathname = pathname.replace(/(^\\/|\\/$)/g, '')\n    const [groupId, repoId] = normalizedPathname.split('/')\n    assert(\n      typeof groupId === 'string' &&\n      typeof repoId === 'string',\n      `[CANNOT_PARSE_PATHNAME] Cannot infer repoId from repoUrl: ${repoUrl}`\n    )\n\n    const base = `${protocol}//${host}/api/v2/`\n    Yuque.base = base\n\n    const { data: repos } = await Yuque.getRepos(base, groupId)\n    assert(\n      Array.isArray(repos),\n      `[CANNOT_FIND_GROUP] Cannot infer repoId from repoUrl: ${repoUrl}`\n    )\n\n    const targetRepo = repos.find(repo => repo.namespace === normalizedPathname)\n    assert(\n      typeof targetRepo === 'object',\n      `[CANNOT_FIND_REPO] Cannot infer repoId from repoUrl: ${repoUrl}`\n    )\n\n    return targetRepo\n  }\n\n  constructor(repoId) {\n    this.repoId = repoId\n    this.store = store.get(`yuque_repo_${repoId}`)\n  }\n\n  get base() {\n    return Yuque.base || 'https://www.yuque.com/api/v2/'\n  }\n\n  async getRepos() {\n    return Yuque.getRepos(this.base, this.repoId)\n  }\n\n  async getRepoDetail() {\n    return Yuque.getRepoDetail(this.base, this.repoId)\n  }\n\n  async getToc() {\n    return Yuque.getToc(this.base, this.repoId)\n  }\n\n  async getPage(slug) {\n    return Yuque.getPage(this.base, this.repoId, slug)\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"vuepress-plugin-yuque\",\n  \"version\": \"0.6.1\",\n  \"description\": \"I: Yuque Repo, O: VuePress Site!\",\n  \"main\": \"lib/index.js\",\n  \"files\": [\n    \"lib\"\n  ],\n  \"scripts\": {\n    \"test\": \"jest\",\n    \"lint\": \"xo\",\n    \"dev\": \"vuepress dev docs --temp .temp\",\n    \"build\": \"vuepress build docs --temp .temp\",\n    \"dev:example\": \"vuepress dev example --temp .temp2\",\n    \"build:example\": \"vuepress build example --temp .temp2\",\n    \"release\": \"release-it\"\n  },\n  \"repository\": {\n    \"url\": \"ulivz/vuepress-plugin-yuque\",\n    \"type\": \"git\"\n  },\n  \"author\": \"ulivz<chl814@foxmail.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@vuepress/plugin-medium-zoom\": \"^1.0.0-alpha.44\",\n    \"cheerio\": \"^1.0.0-rc.2\",\n    \"conf\": \"^2.2.0\",\n    \"debug\": \"^4.1.1\",\n    \"node-fetch\": \"^2.3.0\",\n    \"ora\": \"^3.0.0\"\n  },\n  \"devDependencies\": {\n    \"conventional-changelog-cli\": \"^2.0.1\",\n    \"eslint-config-sherry\": \"0.0.1\",\n    \"husky\": \"1.2.0\",\n    \"jest\": \"23.6.0\",\n    \"lint-staged\": \"8.1.0\",\n    \"release-it\": \"v7.4.8\",\n    \"vuepress\": \"1.0.0-alpha.44\",\n    \"xo\": \"0.23.0\",\n    \"escape-html\": \"^1.0.3\"\n  },\n  \"jest\": {\n    \"testEnvironment\": \"node\"\n  },\n  \"xo\": {\n    \"extends\": [\n      \"sherry\"\n    ],\n    \"envs\": [\n      \"jest\"\n    ]\n  },\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged\"\n    }\n  },\n  \"lint-staged\": {\n    \"*.{js}\": [\n      \"xo --fix\",\n      \"git add\"\n    ]\n  }\n}\n"
  },
  {
    "path": "test/index.test.js",
    "content": "const vuepressPluginYuque = require('../')\n\ntest('main', () => {\n  expect(typeof vuepressPluginYuque).toBe('function')\n})\n"
  }
]