[
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org\nroot = 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\n\n[*.less]\nindent_style = space\nindent_size = 2\n\n[Makefile]\nindent_style = tab\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "const eslintrc = {\n  \"parser\": \"babel-eslint\",\n  \"extends\": \"airbnb\",\n  \"env\": {\n    \"browser\": true,\n    \"node\": true,\n    \"es6\": true,\n    \"mocha\": true,\n    \"jest\": true,\n    \"jasmine\": true\n  },\n  \"plugins\": [\n    \"react\",\n    \"import\"\n  ],\n  \"parserOptions\": {\n    parser: 'babel-eslint',\n  },\n  \"rules\": {\n    \"linebreak-style\": 0,\n    \"func-names\": 0,\n    \"sort-imports\": 0,\n    \"arrow-body-style\": 0,\n    \"prefer-destructuring\": 0,\n    \"max-len\": 0,\n    \"consistent-return\": 0,\n    \"comma-dangle\": [\n      \"error\",\n      \"always-multiline\"\n    ],\n    \"function-paren-newline\": 0,\n    \"class-methods-use-this\": 0,\n    \"react/sort-comp\": 0,\n    \"react/prop-types\": 0,\n    \"react/jsx-first-prop-new-line\": 0,\n    \"react/require-extension\": 0,\n    \"react/jsx-filename-extension\": [\n      1,\n      {\n        \"extensions\": [\n          \".js\",\n          \".jsx\"\n        ]\n      }\n    ],\n    \"import/extensions\": 0,\n    \"import/no-unresolved\": 0,\n    \"import/no-extraneous-dependencies\": 0,\n    \"import/prefer-default-export\": 0,\n    \"jsx-a11y/no-static-element-interactions\": 0,\n    \"jsx-a11y/anchor-has-content\": 0,\n    \"jsx-a11y/click-events-have-key-events\": 0,\n    \"jsx-a11y/anchor-is-valid\": 0,\n    \"jsx-a11y/label-has-for\": 0,\n    \"jsx-a11y/no-noninteractive-element-interactions\": 0,\n    \"jsx-a11y/mouse-events-have-key-events\": 0,\n    \"react/no-danger\": 0,\n    \"react/jsx-no-bind\": 0,\n    \"react/forbid-prop-types\": 0,\n    \"react/require-default-props\": 0,\n    \"react/no-did-mount-set-state\": 0,\n    \"react/no-array-index-key\": 0,\n    \"react/no-find-dom-node\": 0,\n    \"react/no-unused-state\": 0,\n    \"react/no-unused-prop-types\": 0,\n    \"react/default-props-match-prop-types\": 0,\n    \"react/jsx-curly-spacing\": 0,\n    \"react/no-render-return-value\": 0,\n    'react/jsx-uses-react': 0,\n    'react/react-in-jsx-scope': 0,\n    \"object-curly-newline\": 0,\n    \"no-param-reassign\": 0,\n    \"no-return-assign\": 0,\n    \"no-redeclare\": 0,\n    \"no-restricted-globals\": 0,\n    \"no-restricted-syntax\": 0,\n    \"no-underscore-dangle\": 0,\n    \"no-unused-expressions\": 0,\n    \"no-use-before-define\": 0,\n    \"semi\": [\"error\", \"never\"],\n    \"quotes\": 0,\n    \"no-plusplus\": 0\n  }\n}\n\nif (process.env.NODE_ENV === 'development') {\n  Object.assign(eslintrc.rules,\n  {\n    'no-console': 0,\n    'no-unused-vars': 0,\n  });\n}\n\nmodule.exports = eslintrc\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # 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\n# Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\ncustom: ['http://muyunyun.cn/sponsor/']\n"
  },
  {
    "path": ".github/config.yml",
    "content": "todo:\n  keyword: \"@makeAnIssue\"\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# see https://github.com/yi-Xu-0100/traffic-to-badge/blob/main/.github/dependabot.yml\nversion: 2\nupdates:\n  # Enable version updates for npm\n  - package-ecosystem: 'npm'\n    directory: '/'\n    schedule:\n      interval: 'daily'\n  # Maintain dependencies for GitHub Actions\n  - package-ecosystem: 'github-actions'\n    directory: '/'\n    schedule:\n      interval: 'daily'\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Configuration for probot-stale - https://github.com/probot/stale\n\n# Number of days of inactivity before an Issue or Pull Request becomes stale\ndaysUntilStale: 60\n\n# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.\n# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.\ndaysUntilClose: 7\n\n# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)\nonlyLabels: []\n\n# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable\nexemptLabels:\n  - pinned\n  - security\n  - \"[Status] Maybe Later\"\n\n# Set to true to ignore issues in a project (defaults to false)\nexemptProjects: false\n\n# Set to true to ignore issues in a milestone (defaults to false)\nexemptMilestones: false\n\n# Set to true to ignore issues with an assignee (defaults to false)\nexemptAssignees: false\n\n# Label to use when marking as stale\nstaleLabel: wontfix\n\n# Comment to post when marking as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed if no further activity occurs. Thank you\n  for your contributions.\n\n# Comment to post when removing the stale label.\n# unmarkComment: >\n#   Your comment here.\n\n# Comment to post when closing a stale Issue or Pull Request.\n# closeComment: >\n#   Your comment here.\n\n# Limit the number of actions per hour, from 1-30. Default is 30\nlimitPerRun: 30\n\n# Limit to only `issues` or `pulls`\n# only: issues\n\n# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':\n# pulls:\n#   daysUntilStale: 30\n#   markComment: >\n#     This pull request has been automatically marked as stale because it has not had\n#     recent activity. It will be closed if no further activity occurs. Thank you\n#     for your contributions.\n\n# issues:\n#   exemptLabels:\n#     - confirmed"
  },
  {
    "path": ".github/workflows/gh-pages.yml",
    "content": "name: GitHub Pages\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\njobs:\n  deploy:\n    runs-on: ubuntu-22.04\n    permissions:\n      contents: write\n    concurrency:\n      group: ${{ github.workflow }}-${{ github.ref }}\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Setup Node\n        uses: actions/setup-node@v3\n        with:\n          node-version: '14'\n\n      - name: Get yarn cache\n        id: yarn-cache\n        run: echo \"YARN_CACHE_DIR=$(yarn cache dir)\" >> \"${GITHUB_OUTPUT}\"\n\n      - name: Cache dependencies\n        uses: actions/cache@v3\n        with:\n          path: ${{ steps.yarn-cache.outputs.YARN_CACHE_DIR }}\n          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}\n          restore-keys: |\n            ${{ runner.os }}-yarn-\n\n      - run: yarn install --frozen-lockfile\n      - run: yarn build\n\n      - name: Deploy\n        uses: peaceiris/actions-gh-pages@v3\n        if: ${{ github.ref == 'refs/heads/main' }}\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          publish_dir: .crd-dist\n"
  },
  {
    "path": ".github/workflows/greetings.yml",
    "content": "name: Greetings\n\non: [pull_request, issues]\n\njobs:\n  greeting:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/first-interaction@v1\n      with:\n        repo-token: ${{ secrets.GITHUB_TOKEN }}\n        issue-message: 'Welcome your first issue here, thanks'\n        pr-message: 'Welcome your first pr here, thanks'\n"
  },
  {
    "path": ".github/workflows/traffic2badge.yml",
    "content": "name: traffic2badge\non:\n  push:\n    branches:\n      - main\n  schedule:\n    - cron: '1 0 * * *' #UTC\n\njobs:\n  run:\n    name: Make GitHub Traffic to Badge\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@v2.3.3\n\n      - name: Get Commit Message\n        id: message\n        uses: actions/github-script@v3.0.0\n        env:\n          FULL_COMMIT_MESSAGE: '${{ github.event.head_commit.message }}'\n        with:\n          result-encoding: string\n          script: |\n            var message = `${process.env.FULL_COMMIT_MESSAGE}`;\n            core.info(message);\n            if (message != '') return message;\n            var time = new Date(Date.now()).toISOString();\n            core.info(time);\n            return `Get traffic data at ${time}`;\n\n      - name: Set Traffic\n        id: traffic\n        uses: yi-Xu-0100/traffic-to-badge@v1.4.0\n        with:\n          my_token: ${{ secrets.TRAFFIC_TOKEN }}\n          #(default) static_list: ${{ github.repository }}\n          #(default) traffic_branch: traffic\n          #(default) views_color: brightgreen\n          #(default) clones_color: brightgreen\n          #(default) logo: github\n          #(default) year:\n\n      - name: Deploy\n        uses: peaceiris/actions-gh-pages@v3.7.3\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          publish_branch: ${{ steps.traffic.outputs.traffic_branch }}\n          publish_dir: ${{ steps.traffic.outputs.traffic_path }}\n          user_name: 'github-actions[bot]'\n          user_email: 'github-actions[bot]@users.noreply.github.com'\n          full_commit_message: ${{ steps.message.outputs.result }}\n\n      - name: Show Traffic Data\n        run: |\n          echo ${{ steps.traffic.outputs.traffic_branch }}\n          echo ${{ steps.traffic.outputs.traffic_path }}\n          cd ${{ steps.traffic.outputs.traffic_path }}\n          ls -a"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.create-react-doc-dist\npackage-lock.json\n.cache\n.DS_Store\n.crd-dist/\n\n*.bak\n*.tem\n*.log\n*.temp\n#.swp\n*.*~\n~*.*\n\ndocs/忽略文件.md"
  },
  {
    "path": ".npmignore",
    "content": ".cache\n.gitignore\n.editorconfig\n.create-react-doc-dist\nnode_modules\npackage-lock.json\ndist"
  },
  {
    "path": ".npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n"
  },
  {
    "path": ".yarnrc",
    "content": "# .yarnrc\nregistry \"https://registry.npmjs.org/\"\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# HOW TO CONTRIBUTE\n\n1. Welcome your pr! Before pr, talk about situations in the [issue](https://github.com/MuYunyun/create-react-doc/issues/new) firstly. If the situation is reasonable, go to the next step;\n2. Switch to the new branch based main, submit the pr to branch `qa/latest` after finishing development.\n\n## DEV\n\nRun these bash command firstly.\n\n```bash\n$ git clone https://github.com/MuYunyun/create-react-doc\n$ cd create-react-doc\n$ yarn && yarn bootstrap && yarn start\n```\n\nAnd now you can see the document is running at http://localhost:3000.\n\n## Test\n\nAfter merging pr to qa/latest and publish beta package. You should verify the feature/bugfix with following bash:\n\n```js\nyarn add create-react-doc@beta\n```"
  },
  {
    "path": "README-en.md",
    "content": "                                                     _.-\"\\\n                                                _.-\"      \\\n                                              ,-\"          \\\n                                              \\    create    \\\n                                              \\ \\    react    \\\n                                              \\ \\      doc     \\\n                                                \\ \\         _.-;\n                                                \\ \\    _.-\"   :\n                                                  \\ \\,-\"    _.-\"\n                                                  \\(   _.-\"\n                                                    `--\"\n\n[![npm version](https://img.shields.io/npm/v/create-react-doc)](https://badge.fury.io/js/create-react-doc)\n[![week download](https://img.shields.io/npm/dw/create-react-doc.svg)](https://www.npmjs.com/package/create-react-doc)\n![views](https://raw.githubusercontent.com/MuYunyun/create-react-doc/traffic/traffic-create-react-doc/views.svg)\n![views](https://raw.githubusercontent.com/MuYunyun/create-react-doc/traffic/traffic-create-react-doc/views_per_week.svg)\n![clones](https://raw.githubusercontent.com/MuYunyun/create-react-doc/traffic/traffic-create-react-doc/clones_per_week.svg)\n![LICENSE MIT](https://img.shields.io/npm/l/create-react-doc.svg)\n\nEnglish | [简体中文](./README.md)\n\n# Create React Doc\n\n[Create React Doc](https://github.com/MuYunyun/create-react-doc) is a markdown document site generation tool using React just like [create-react-app](https://github.com/facebook/create-react-app), developers can use Create React Doc to develop, deploy documents or blog sites without worrying about additional environment configuration information.\n\n## Features\n\n* The idea of ​​building a site: Just write markdown files as a blog site [like me](https://github.com/MuYunyun/blog).\n* Out of box: One-click generation of documents and blog sites by specifying directories or documents, no need to care about site environment configuration information.\n* Performance: greatly improve site loading speed through pre-rendering and lazy loading.\n* Based on mdx: Support writing React components, mathematical formulas, etc. in markdown.\n* Search engine optimization: Support SEO, making documents easier to search.\n* Personalization: Support [custom theme](https://muyunyun.cn/create-react-doc/9f41fc98).\n* Workflow: Integrate Github actions, support automated packaging and publishing sites.\n\n> [Quick Start](https://muyunyun.cn/create-react-doc/290a4219)\n\n## Subject\n\nCreate React Doc provides the official default theme [crd-seed](https://github.com/MuYunyun/create-react-doc/tree/main/packages/crd-seed). The theme supports the following features:\n\n* Adapt to mobile and PC multi-terminal display.\n* Support dark mode.\n* The document supports embedded codepen, codesandbox.\n* GitHub linkage.\n* Support using tags to customize aggregate article content.\n\n[my blog](http://muyunyun.cn/blog) is based [crd-seed](https://github.com/MuYunyun/create-react-doc/tree/main/packages/crd-seed) theme to build。\n\n![](http://with.muyunyun.cn/90d3e357a31649b9466a828a92b6d88d.jpg)\n![](http://with.muyunyun.cn/2e7440e4256debda2d73a4e6392c7146.jpg-300)\n\nIf you want to customize or share personal themes, you can refer to the [Custom Theme](https://muyunyun.cn/create-react-doc/9f41fc98) chapter.\n\n## Get started quickly\n\n**Create React Doc** is very easy to use. Developers don't need to install or configure additional tools such as webpack or Babel, they are built-in and hidden in the scaffolding, so developers can concentrate on document writing.\n\nIf you want to create a site file `doc` under the current file, here are three ways to quickly build a site:\n\n### npx\n\n```bash\nnpx create-react-doc doc\n```\n\n### npm\n\n```bash\nnpm init create-react-doc doc\n```\n\n### yarn\n\n```bash\nyarn create react-doc doc\n```\n\n![](http://with.muyunyun.cn/0f0cf6e8cb68b18399eac2927f74b063.jpg)\n\n> If you want to pull the content of the template to the current folder, you can replace the `doc` of the above command with `.`, such as executing `npx create-react-doc .`.\n\nThen execute `cd doc && yarn && yarn start`, you can preview the site at `localhost: 3000`, if the site document changes, the site will automatically reload.\n\n<img src=\"http://with.muyunyun.cn/2bbd4d8da3165e1a09a88f5e6a114009.jpg\" width=\"900\" />\n\n## Site release\n\nIn the [Quick Start](http://muyunyun.cn/create-react-doc/QuickStart) section, it introduces how to quickly build a site. This section will introduce how to package and publish the built site to gh-pages.\n\n### Automatically package and publish to gh-pages (recommended)\n\nThe initialized template project integrates the [ci configuration](https://github.com/MuYunyun/create-react-doc/blob/main/packages/templates/default/.github/workflows/gh-pages.yml) of `Github action`, the user only needs to execute `git push` on the main branch to complete the automatic deployment of the site.\n\n![](http://with.muyunyun.cn/ea24d511f76efe5ba5d13bb6b1609aac.jpg)\n\nIf it is the first deployment, after performing the following operations, you need to select Github Pages as gh-pages in the setting tab of the project. (See [First Deployment with GITHUB_TOKEN](https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-first-deployment-with-github_token) for details)\n\n```bash\ngit init\ngit add.\ngit commit -m \"first commit\"\ngit branch -M main\ngit remote add origin https://github.com/user or organization name/project name.git\ngit push -u origin main\n```\n\n> For more content, please visit [Site Release](http://muyunyun.cn/create-react-doc/SiteRelease), [Advanced Usage](http://muyunyun.cn/create-react-doc/HighOrderusage), [other tools](http://muyunyun.cn/create-react-doc/othertools) and other chapters.\n\n## Practice Sharing\n\n* [基于 SSR 的预渲染首屏直出方案](http://muyunyun.cn/blog/g3v1c5bq)\n* [SEO 在 SPA 站点中的实践](http://muyunyun.cn/blog/ettzfags)\n"
  },
  {
    "path": "README.md",
    "content": "<!--\nabbrlink: s31w9gd1\n-->\n                                                     _.-\"\\\n                                                _.-\"      \\\n                                              ,-\"          \\\n                                              \\    create    \\\n                                              \\ \\    react    \\\n                                              \\ \\      doc     \\\n                                                \\ \\         _.-;\n                                                \\ \\    _.-\"   :\n                                                  \\ \\,-\"    _.-\"\n                                                  \\(   _.-\"\n                                                    `--\"\n\n[![npm version](https://img.shields.io/npm/v/create-react-doc)](https://badge.fury.io/js/create-react-doc)\n[![week download](https://img.shields.io/npm/dw/create-react-doc.svg)](https://www.npmjs.com/package/create-react-doc)\n![views](https://raw.githubusercontent.com/MuYunyun/create-react-doc/traffic/traffic-create-react-doc/views.svg)\n![views](https://raw.githubusercontent.com/MuYunyun/create-react-doc/traffic/traffic-create-react-doc/views_per_week.svg)\n![clones](https://raw.githubusercontent.com/MuYunyun/create-react-doc/traffic/traffic-create-react-doc/clones_per_week.svg)\n![LICENSE MIT](https://img.shields.io/npm/l/create-react-doc.svg)\n\n[English](./README-en.md) | 简体中文\n\n# Create React Doc\n\n[Create React Doc](https://github.com/MuYunyun/create-react-doc) 是一个使用 React 的 markdown 文档站点生成工具。就像 [create-react-app](https://github.com/facebook/create-react-app) 一样，开发者可以使用 Create React Doc 来开发、部署文档或者博客站点而无需关心额外的环境配置信息。\n\n## 特性\n\n* 建站理念: `文件即站点` (Files as a Site)。\n* 开箱即用: 通过指定目录或文档, 一键生成文档、博客站点, 无需关心站点环境配置信息。\n* 流畅的用户体验: 内置 SSR 首屏直出方案(基于 gp-pages 服务)，以提升用户体验。\n* 基于 mdx: 支持在 markdown 中`书写 React 组件`、数学公式等。\n* 搜索引擎优化: 支持 SEO, 让文档更易被搜索。\n* 个性化: 支持[自定义主题](https://muyunyun.cn/create-react-doc/9f41fc98)。\n* 工作流: 集成 Github action, 支持自动化打包、发布站点。\n\n> [快速上手](https://muyunyun.cn/create-react-doc/290a4219)\n\n## 主题\n\ncreate-react-doc 提供了默认主题 [crd-seed](https://github.com/MuYunyun/create-react-doc/tree/main/packages/crd-seed)。\n\n该主题支持以下特性:\n\n- [x] 适配网页/移动端展示。\n- [x] 支持暗黑模式。\n- [x] 支持标签页自定义聚合文章内容。\n- [x] 内置评论模块。\n- [x] 支持内嵌展示 codepen、codesandbox 案例。\n- [x] 支持从文档页快速跳转到对应的 Github 文档页进行在线编辑。\n\n该主题效果可以参考[笔者博客](http://muyunyun.cn/blog)。\n\n![](http://with.muyunyun.cn/90d3e357a31649b9466a828a92b6d88d.jpg)\n![](http://with.muyunyun.cn/2e7440e4256debda2d73a4e6392c7146.jpg-300)\n\n如果您想定制化或者分享个人主题，可以参考[自定义主题](https://muyunyun.cn/create-react-doc/9f41fc98)章节。\n\n## 快速上手\n\n**create-react-doc** 非常容易上手。开发者不需要额外安装或配置 webpack 或者 Babel 等工具，它们被内置隐藏在脚手架中，因此开发者可以专心于文档的书写。\n\n如果你想在当前文件下建立站点文件 `doc`, 这里提供如下三种方式快速建站:\n\n### npx\n\n```bash\nnpx create-react-doc doc\n```\n\n### npm\n\n```bash\nnpm init create-react-doc doc\n```\n\n### yarn\n\n```bash\nyarn create react-doc doc\n```\n\n![](http://with.muyunyun.cn/0f0cf6e8cb68b18399eac2927f74b063.jpg)\n\n> 如果想把模板内容内容拉取到当前文件夹, 则可以将如上命令的 `doc` 替换为 `.`, 比如执行 `npx create-react-doc .`。\n\n接着执行 `cd doc && yarn && yarn start`, 可以在 `localhost: 3000` 预览站点, 如果站点文档发生改变, 站点将自动重新加载。\n\n<img src=\"http://with.muyunyun.cn/2bbd4d8da3165e1a09a88f5e6a114009.jpg\" width=\"900\" />\n\n## 站点发布\n\n在 [快速上手](https://muyunyun.cn/create-react-doc/290a4219) 一节中介绍了如何快速搭建站点, 本节将介绍如何将搭建好的站点打包、发布到 gh-pages。\n\n### 自动打包发布到 gh-pages (推荐)\n\n初始化的模板项目集成了 `Github action` 的 [ci 配置](https://github.com/MuYunyun/create-react-doc/blob/main/packages/templates/default/.github/workflows/gh-pages.yml), 使用方只需在 main 分支执行 `git push` 即可以完成站点的自动部署。\n\n![](http://with.muyunyun.cn/ea24d511f76efe5ba5d13bb6b1609aac.jpg)\n\n如果是第一次部署, 在执行以下操作后, 需要在项目的 setting 选项卡中将 Github Pages 选择为 gh-pages。(详情见 [First Deployment with GITHUB_TOKEN](https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-first-deployment-with-github_token))\n\n```bash\ngit init\ngit add .\ngit commit -m \"first commit\"\ngit branch -M main\ngit remote add origin https://github.com/用户或组织名/项目名.git\ngit push -u origin main\n```\n\n## 更多内容\n\n* [站点发布](http://muyunyun.cn/create-react-doc/ude9296y)\n* [高阶用法](http://muyunyun.cn/create-react-doc/9v9ug9h8)\n* [其它工具](http://muyunyun.cn/create-react-doc/292h2c5k)\n* [Front-matter](http://muyunyun.cn/create-react-doc/49g6b239)\n\n## 实践分享\n\n* [基于 SSR 的预渲染首屏直出方案](http://muyunyun.cn/blog/g3v1c5bq)\n* [SEO 在 SPA 站点中的实践](http://muyunyun.cn/blog/ettzfags)\n"
  },
  {
    "path": "components/Button/index.jsx",
    "content": "import styles from './index.less'\n\nconst Button = ({\n  children,\n}) => {\n  return <button className={styles.btn}>{children}</button>\n}\n\nexport default Button\n"
  },
  {
    "path": "components/Button/index.less",
    "content": ".btn {\n  color: #fff;\n  background: #1890ff;\n  border-color: #1890ff;\n  text-shadow: 0 -1px 0 rgb(0 0 0 / 12%);\n  box-shadow: 0 2px #0000000b;\n  height: 40px;\n  padding: 6.4px 15px;\n  font-size: 16px;\n  border-radius: 2px;\n  line-height: 1.5715;\n  position: relative;\n  display: inline-block;\n  font-weight: 400;\n  white-space: nowrap;\n  text-align: center;\n}"
  },
  {
    "path": "components/index.jsx",
    "content": "import Button from './Button/index.jsx'\n\nexport {\n  Button,\n}\n"
  },
  {
    "path": "config.yml",
    "content": "# create-react-doc configuration.\n\n# Site\ntitle: Create React Doc\n\n# Menu dir\n## you can also set detailed dir, such as BasicSkill/css\n## todo: auto menu\nmenu: [\n  docs/快速上手.md,\n  docs/更新日志.md,\n  docs/主题,\n  docs/站点发布.md,\n  docs/Front-matter.md,\n  docs/数学公式.md,\n  docs/书写组件.md,\n  docs/高阶用法.md,\n  docs/其它工具.md,\n  docs/测试\n]\n## set init open menu keys\n# menuOpenKeys:\n\n# site theme\ndevTheme: packages/crd-seed/index\n# theme: crd-seed\n\n# Github\n## if you want to editing pages on github, you should config these arguments.\nuser: MuYunyun\nrepo: create-react-doc\ngithub-ribbons: true\ndomain: https://muyunyun.cn\nseo:\n  google: true\n\n# Available values: en | zh-cn\nlanguage: en\n\n# Inject Custom Logic\ninject: injectLogic/index.js\n\n# Use abbrlink\nabbrlink: true\n\n# Show Tags in head\ntags: true\n\n# Config comment section\ncomment:\n  # Giscus Config, The config parameter that's supported can be seen in [giscus-component](https://github.com/giscus/giscus-component#documentation).\n  GiscusConfig:\n    repoId: MDEwOlJlcG9zaXRvcnkyNjgwMTE4MzA=\n    categoryId: DIC_kwDOD_mJNs4CSd1W\n"
  },
  {
    "path": "docs/Front-matter.md",
    "content": "<!--\nabbrlink: 49g6b239\n-->\n\n## Front-matter\n\nFront-matter 是文件最上方包裹在 `<!--` 与 `-->` 之间的区域，用于指定个别文件的变量，举例来说：\n\n```md\n<!--\nabbrlink: 290a4219\ntags: ['customTag1', 'customTag2']\n-->\n```\n\n以下是预先定义的参数，您可在模板中使用这些参数值并加以利用。\n\n| 参数     | 描述                                                            | 类型     |\n| :------- | :-------------------------------------------------------------- | :------- |\n| abbrlink | 短链。用于指定页面路由展示为指定短链，使用短链有助于 SEO 搜索。 |          |\n| tags     | 自定义标签                                                      | string[] |\n\n## 链接持久化\n\n在以下场景需求场合中，可以展示短链以优化 URL 的显示。\n\n* SEO 场景下需要链接持久化。\n* URL 链接中存在中文会被转码展示。\n* 文档的路径与文件名经常变更。\n\n### 如何使用短链\n\n在 `config.yml` 增加配置 `abbrlink: true`\n\n```diff\n+ abbrlink: true\n```\n\n做好上述配置后，接着在控制台执行 `react-doc generate` 即可给 menu 配置属性中的所有文章目录文件加上短链资源。\n\n```bash\nreact-doc generate // 一键给所有文章加上短链\n```\n"
  },
  {
    "path": "docs/主题/自定义主题.md",
    "content": "<!--\ntitle: 自定义主题\nabbrlink: 9f41fc98\ndate: 2019-05-12 13:23:44\ntags: ['主题', '自定义标签1']\n-->\n\n## 使用自定义主题\n\n切换主题非常简单, 只需要将根目录文件 `config.yml` 中的 `theme` 更改为您想使用的主题即可。\n\n```diff\n+ theme: custom-theme\n```\n\n### 如何开发自定义主题包\n\ncreate-react-doc 脚手架提供了脚本命令 `react-doc theme` 用来一键创建主题包开发环境。\n\n![](http://with.muyunyun.cn/2e4a4b11f96c0d38759700c05fe96267.gif)\n\n```js\n// 安装 create-react-doc\nyarn add create-react-doc -g\n// 执行 react-doc theme 并输入主题包名字\nreact-doc theme\n```\n\n进入到所创建主题目录, 执行 `yarn && yarn start`, 此时会自动打开浏览器, 并在屏幕中央显示 `Write docs happily now.`。如下图所示:\n\n![](http://with.muyunyun.cn/1a2bf34700afd77a95014d2d5f359ffa.jpg)\n\n恭喜你, 此时你已经将主题开发环境配置完成。接着便可以开始愉快地定制个人主题了。\n\n在所创建的主题项目中使用了 `react v18`，`react-router-dom v6`，项目支持使用 `less` 语法。\n\n```js\nimport { Switch, Route } from 'react-router-dom'\nimport styles from './index.less'\n\nconst CustomTheme = (props: CustomThemeProps) => {\n  return (\n    <Routes>\n      <Route path=\"/\">\n        <div className={styles.center}>Welcome to your own theme</div>\n      </Route>\n    </Routes>\n  )\n}\n\nexport default CustomTheme\n```\n\nCustomThemeProps 的接口类型暴露了菜单资源 `menuSource` 与路由资源 `routeData`, 自定义主题时可以按需使用它们。\n\n```js\ninterface CustomThemeProps {\n  /** 菜单资源 */\n  menuSource: {\n    /** 文件名称 eg: '快速上手.md' */\n    name: string\n    /** 文件扩展名 eg: '.md' */\n    extension: string\n    /** 文件路径 eg: '/docs/快速上手.md' */\n    path: string\n    /** 路由路径 eg: ‘/快速上手’ */\n    routePath: string\n    /** 文件大小 eg: 924 */\n    size: number\n    /** 文件类型 eg: 'file' */\n    type: string\n    /** 文件创建日期 eg: '2020-11-11' */\n    birthtime: string\n    /** 文件修改日期 eg: '2021-01-14' */\n    mtime: string\n  }[]\n  /** 路由资源 */\n  routeData: {\n    /** 文件名称 eg: '快速上手.md' */\n    article: string\n    /** 异步加载 markdown 组件函数 */\n    component: AsyncRouteComponent(props)\n    /** markdown 文章信息对象。若为文件则有 title 字段, 若为文件夹则无 title 字段 */\n    mdconf: { title?: string }\n    /** 文件路径 eg: '/docs/快速上手' */\n    path: string\n  }[]\n}\n```\n\n此外在自定义主题文件中可以自由使用由 webpack 注入的 `DOCSCONFIG` 对象中的变量, DOCSCONFIG 中的变量与项目根目录中的 `config.yml` 文件变量一一对应。\n\n比如 `config.yml` 配置如下所示:\n\n```bash\nmenu: ['Introduction']\ntheme: crd-seed\nuser: muyunyun\nrepo: https://github.com/MuYunyun/create-react-doc\nlanguage: en\n```\n\n则主题项目中可以通过如下方式获取到 `config.yml` 配置属性。\n\n```js\nconst { menu, theme, user } = DOCSCONFIG || {}\n```\n"
  },
  {
    "path": "docs/主题/默认主题.md",
    "content": "<!--\nabbrlink: 85li8wdd\n-->\n\n## 默认主题\n\ncreate-react-doc 的默认主题为 [crd-seed](https://github.com/MuYunyun/create-react-doc/tree/main/packages/crd-seed)。\n\n该主题支持以下特性:\n\n- [x] 适配网页/移动端展示。\n- [x] 支持暗黑模式。\n- [x] 支持标签页自定义聚合文章内容。\n- [x] 内置评论模块。\n- [x] 支持内嵌展示 codepen、codesandbox 案例。\n- [x] 支持从文档页快速跳转到对应的 Github 文档页进行在线编辑。\n\n使用该主题搭建的项目有:\n\n* [blog](https://github.com/MuYunyun/blog), [站点](http://muyunyun.cn/blog)\n  * ![](http://with.muyunyun.cn/90d3e357a31649b9466a828a92b6d88d.jpg)\n  * ![](http://with.muyunyun.cn/2e7440e4256debda2d73a4e6392c7146.jpg-300)\n* [diana](https://github.com/MuYunyun/diana), [站点](https://muyunyun.cn/diana/)\n\n> 如果您有其它的改进优化想法, 欢迎<a href=\"https://github.com/MuYunyun/create-react-doc/issues/new\" target=\"_blank\">留言补充</a>\n\n## config.yml\n\n[config.yml](https://github.com/MuYunyun/create-react-doc/blob/main/packages/templates/default/_config.yml) 文件是配置站点主题功能的地方。\n\n它支持配置的属性如下:\n\n|     属性名     |                 作用                 |                                        类型                                         |   默认   |\n| :------------: | :----------------------------------: | :---------------------------------------------------------------------------------: | :------: |\n|     title      |                站点名                |                                       string                                        |          |\n|      menu      |    作为站点菜单的文件/文件夹路径     |                                      string[]                                       |          |\n|  menuOpenKeys  |       默认展开菜单的文件夹路径       |                                       string                                        |          |\n|      user      |            Github 用户名             |                                       string                                        |          |\n|      repo      |            Github 项目名             |                                       string                                        |          |\n|    language    |               站点语言               |                                     en \\| zh-cn                                     |    en    |\n| github-ribbons |     是否在右上角显示 github 丝带     |                                       boolean                                       |  false   |\n|     theme      |               使用主题               |                                       string                                        | crd-seed |\n|    devTheme    |  开发自定义主题时, 需设置其为 true   |                                       string                                        | ./index  |\n|      seo       |          是否开启 SEO 优化           |                                { google?: boolean }                                 |          |\n|     domain     | SEO 优化的站点域名, 用于生成 sitemap |                                       string                                        |          |\n|    comment     |      开启评论区，并进行相关配置      | { GiscusConfig: [Props](https://github.com/giscus/giscus-component#documentation) } |          |\n\n详细用法可以参考 [config.yml](https://github.com/MuYunyun/blog/blob/main/config.yml)。"
  },
  {
    "path": "docs/书写组件.md",
    "content": "<!--\nabbrlink: lx1euo1b\ntags: ['组件']\n-->\n\nimport { Button } from '../components/index.jsx'\n\n## 书写组件\n\n[create-react-doc](https://github.com/MuYunyun/create-react-doc) 内置了 [mdx](https://github.com/mdx-js/mdx), 你可以在 .md 文件中书写 React 组件, 因此你可以选择 create-react-doc 来快速搭建组件站点。\n\n## 例子\n### Button 组件\n\n```js\nimport { Button } from '../components/index.jsx'\n\n<Button>Primary</Button>\n```\n\n<Button>Primary</Button>"
  },
  {
    "path": "docs/其它工具.md",
    "content": "<!--\nabbrlink: 292h2c5k\n-->\n\n## 其它工具\n\n### crd-leetcode-cli\n\n#### 背景\n\n当新增 LeetCode 题解时需要[手动更新表格](https://github.com/MuYunyun/blog/blob/main/LeetCode/README.md), 较为不便。[crd-leetcode-cli](https://github.com/MuYunyun/create-react-doc/tree/main/packages/leetcode-cli) 提供了更新 leetcode 站点中已 ac 题解的能力。\n\n#### 安装\n\n执行 `yarn add crd-leetcode-cli -g`, 国内用户可以执行 `cnpm install crd-leetcode-cli -g`\n\n#### 使用\n\n```bash\nleetcode download       // 增量拉取 AC 题目(若无登录, 则会先执行登录逻辑)\nleetcode download -a    // 全量拉取 AC 题目\nleetcode login          // 登录\nleetcode logout         // 登出\n```\n\n#### 自定义渲染表格\n\n插件提供了自定义渲染 markdown table 的能力。\n\n在项目根目录创建 [config.js](https://github.com/MuYunyun/blog/blob/main/config.js) 文件。\n\n在 config.js 内自定义生成 markdown 的 [transform_markdown_table 函数](https://github.com/MuYunyun/blog/blob/main/config.js#L5-L22)。\n\n```js\nconst transform_markdown_table = (dataArr: QuestionProps[]): string => {}\nmodule.exports = { transform_markdown_table }\n```\n\nQuestionProps 接口定义如下:\n\n|    名称    |       含义       |  例子   |\n| :--------: | :--------------: | :-----: |\n| questionId |       题号       |         |\n|   title    |       标题       | Two Sum |\n| titleSlug  | 标题的另一种模式 | two-sum |\n| difficulty |       难度       |         |\n| topicTags  |   题目所属标签   |         |\n\n通过自定义 transform_markdown_table 函数, 便可得到如下 markdown table:\n\n![](http://with.muyunyun.cn/1938e43a45410090e8486e495e6d9fee.jpg)\n\n#### 技术细节\n\n* 使用 puppeteer 登录 leetcode 获取 cookie 信息。\n* 获取 cookie 后, 使用 graphql-request 调用 graphql 接口获取题目详情信息。\n* 自定义生成 markdown table。"
  },
  {
    "path": "docs/快速上手.md",
    "content": "<!--\ntitle: 快速上手\nabbrlink: 290a4219\ndate: 2019-05-12 13:23:44\n-->\n\n## 快速上手\n\n**create-react-doc** 非常容易上手。开发者不需要额外安装或配置 webpack 或者 Babel 等工具，它们被内置隐藏在脚手架中，因此开发者可以专心于文档的书写。\n\n如果你想在当前文件下建立站点文件 `doc`, 这里提供如下三种方式快速建站:\n\n### npx\n\n```bash\nnpx create-react-doc doc\n```\n\n### npm\n\n```bash\nnpm init create-react-doc doc\n```\n\n### yarn\n\n```bash\nyarn create react-doc doc\n```\n\n![](http://with.muyunyun.cn/0f0cf6e8cb68b18399eac2927f74b063.jpg)\n\n> 如果想把模板内容内容拉取到当前文件夹, 则可以将如上命令的 `doc` 替换为 `.`, 比如执行 `npx create-react-doc .`。\n\n接着执行 `cd doc && yarn && yarn start`, 可以在 `localhost: 3000` 预览站点, 如果站点文档发生改变, 站点将自动重新加载。\n\n<img src=\"http://with.muyunyun.cn/2bbd4d8da3165e1a09a88f5e6a114009.jpg\" width=\"900\" />\n"
  },
  {
    "path": "docs/数学公式.md",
    "content": "<!--\nabbrlink: slkczvi1\n-->\n\n## 数学公式\n\n支持在 `$$` 与 `$$` 之间书写 latex 数学公式即能显示在网页上。\n\n```js\n$$\nz = \\frac{x}{y}\n$$\n```\n\n被转化为:\n\n$$\nz = \\frac{x}{y}\n$$\n\n```js\n$$\nC_1 \\quad= \\quad c_2 + c_4^3\n$$\n```\n\n被转化为:\n\n$$\nC_1 \\quad= \\quad c_2 + c_4^3\n$$\n\n```js\n$$\ny = \\sqrt {x_1^2 + x_2^2 + x_3^2 + x_4^2}\n$$\n```\n\n被转化为:\n\n$$\ny = \\sqrt {x_1^2 + x_2^2 + x_3^2 + x_4^2}\n$$\n\n## 参考链接\n\n* [latex 数学公式示例汇总](https://zhuanlan.zhihu.com/p/34799800)\n"
  },
  {
    "path": "docs/更新日志.md",
    "content": "<!--\nabbrlink: 179nqpxt\n-->\n\n# CHANGELOG\n\n`create-react-doc` 严格遵循 [Semantic Versioning 2.0.0](http://semver.org/lang/zh-CN/) 语义化版本规范。\n\n### 1.10.3\n\n`2022-11-26`\n\n- **Enhancement**\n\n  - 🎈 更新主题字体样式为手写体风格。\n\n### 1.10.2\n\n`2022-11-19`\n\n- **Fix**\n\n  - 🐞 修复 @giscus/react 包结构变更导致站点崩溃的问题。[issue](https://github.com/giscus/giscus-component/issues/783)\n\n- **Enhancement**\n\n  - 🎈 使用 esbuild 代替 babel-loader 进行打包构建。[issue](https://github.com/MuYunyun/create-react-doc/issues/337)\n\n### 1.10.0\n\n`2022-11-10`\n\n- **Feature**\n\n  - 🚀 主题内置评论模块，支持在 [config.yml](https://muyunyun.cn/create-react-doc/85li8wdd) 配置开启评论模块。\n\n### 1.9.2\n\n`2022-04-09`\n\n- **Fix**\n\n  - 🐞 修复标签页包含重复标签归档的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/286)\n\n### 1.9.1\n\n`2022-04-05`\n\n- **Enhancement**\n\n  - 🎈 升级基础包版本。[issue](https://github.com/MuYunyun/create-react-doc/issues/278)\n    - 更新 react 版本从 v17 至 v18\n    - 更新 react-router-dom 版本从 v4 至 v6。\n\n### 1.9.0\n\n`2022-04-01`\n\n- **Feature**\n\n  - 🚀 支持配置展示标签页以自定义聚合文章内容。[issue](https://github.com/MuYunyun/create-react-doc/issues/264)\n\n### 1.8.2\n\n`2022-02-02`\n\n- **Enhancement**\n\n  - 🎈 支持在本地环境调试项目源代码。[mr](https://github.com/MuYunyun/create-react-doc/pull/249)\n\n### 1.8.1\n\n`2022-01-17`\n\n- **Fix**\n\n  - 🐞 修复 crd-scripts、crd-seed 遗漏指定安装 crd-client-utils 的问题。\n\n### 1.8.0\n\n`2022-01-16`\n\n- **Feature**\n\n  - 🚀 支持 SSR 首屏直出方案(基于 gp-pages 服务)以避免预渲染带来的二次刷新产生页面抖动的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/103)\n  - 🚀 新增 crd-client-utils 包以收录公用方法。\n\n### 1.7.0\n\n`2022-01-02`\n\n- **Feature**\n\n  - 🚀 访问内容页路由时，收起菜单侧边栏以提高首屏加载体验。[issue](https://github.com/MuYunyun/create-react-doc/issues/219)\n    - 优势一: 用户可以聚焦访问内容区，提升阅读体验。\n    - 优势二: 菜单区域渲染内容复杂，隐藏其加载过程，提升首屏体验。\n  - 🚀 菜单侧边栏展开后，选中项自动滚动到视口内。\n\n### 1.6.1\n\n`2021-12-27`\n\n- **Fix**\n\n  - 🐞 修复访问多层级子菜单目录对应的路由时，对应菜单未被展开的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/222)。\n\n### 1.6.0\n\n`2021-10-30`\n\n- **Feature**\n\n  - 🚀 SEO 搜索标题优化，优化 document.title 与 meta 标签。[issue](https://github.com/MuYunyun/create-react-doc/issues/203)\n\n### 1.5.3\n\n`2021-10-25`\n\n- **Fix**\n\n  - 🐞 修复在使用短链时，站点 sitemap.xml 文件生成丢失的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/206)。\n\n### 1.5.2\n\n`2021-10-19`\n\n- **Fix**\n\n  - 🐞 修复点击右上角 `Edit in GitHub` 链接跳转错误的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/205)。\n\n### 1.5.1\n\n`2021-10-19`\n\n- **Fix**\n\n  - 🐞 修复页面首屏菜单栏未高亮选中的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/195)。\n\n### 1.5.0\n\n`2021-10-13`\n\n- **Feature**\n\n  - 🚀 支持 react-doc generate 命令，给 md 文件自动补全短链。[issue](https://github.com/MuYunyun/create-react-doc/issues/87)、[mr](https://github.com/MuYunyun/create-react-doc/pull/194)\n\n### 1.4.0\n\n`2021-10-08`\n\n- **Feature**\n\n  - 🚀 支持展示短链以让文章链接持久化。[issue](https://github.com/MuYunyun/create-react-doc/issues/87)、[mr](https://github.com/MuYunyun/create-react-doc/pull/193)\n    - 🚀 支持在 Front-matter 区域中书写个别文件的变量。\n\n### 1.3.5\n\n`2021-09-24`\n\n- **Fix**\n\n  - 🐞 修复路由过多时导致预渲染编译超时的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/182)\n  - 🐞 修复初始化模板 menu 参数类型错误的问题。[mr](https://github.com/MuYunyun/create-react-doc/pull/181)\n\n### 1.3.4\n\n`2021-06-27`\n\n- **Fix**\n\n  - 🐞 修复 npx create-react-doc doc 初始化生成文档项目报错的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/157)。\n\n### 1.3.3\n\n`2021-06-24`\n\n- **Fix**\n\n  - 🐞 修复编译预渲染时, 缺少多层级目录文件生成的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/147)。\n\n### 1.3.0\n\n`2021-06-09`\n\n- **Feature**\n\n  - 🚀 create-react-doc 集成 MDX。[issue](https://github.com/MuYunyun/create-react-doc/issues/138)、[mr](https://github.com/MuYunyun/create-react-doc/pull/143)\n    - 🚀 支持在 markdown 文件中`书写 React 组件`。\n    - 🚀 支持在 markdown 文件中`书写数学公式`。\n\n- **Enhancement**\n\n  - 🎈 支持 yarn up、yarn up:dev 在 lerna 项目中快速安装包。[mr](https://github.com/MuYunyun/create-react-doc/pull/143/files?file-filters%5B%5D=.html&file-filters%5B%5D=.js&file-filters%5B%5D=.json&file-filters%5B%5D=.less&file-filters%5B%5D=.lock&file-filters%5B%5D=.sh)\n\n### 1.2.0\n\n- **Fix**\n\n  - 🐞 修复路由数量过多, puppeteer 运行超时的问题。[issue](https://github.com/MuYunyun/blog/issues/115)。\n\n### 1.1.4\n\n- **Fix**\n\n  - 🐞 修复点击 Edit In Github 失效的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/86)。\n\n### 1.1.0\n\n- **Feature**\n\n  - 🚀 新增 crd-generator-sitemap 包, 用于生成 sitemap。\n  - 🚀 配置文件中新增 domain 字段用于生成 sitemap。\n\n### 1.0.0\n\n- **Feature**\n\n  - 🚀 文档支持预渲染。[pr](https://github.com/MuYunyun/create-react-doc/pull/95/files)\n    - 🚀 路由由 hash 路由调整为 browser 路由。\n    🎈 站点 SEO 优化。[doc](https://github.com/MuYunyun/blog/issues/84#issuecomment-786418891)\n  - 🚀 配置文件中 menu 字段类型从 string 调整为 array。\n\n### 0.3.30\n\n- **Feature**\n\n  - 🚀 支持显示展示 pv、uv。[pr](https://github.com/MuYunyun/create-react-doc/pull/85)\n\n### 0.2.29\n\n- **Fix**\n\n  - 🐞 修复首次进入菜单未高亮的问题。[issue](https://github.com/MuYunyun/create-react-doc/issues/78)。\n### 0.2.28\n\n- **Feature**\n\n  - 🚀 支持自定义主题 ci。[pr](https://github.com/MuYunyun/create-react-doc/pull/80)\n\n### 0.2.27\n\n- **Feature**\n\n  - 🚀 支持自定义主题。[pr](https://github.com/MuYunyun/create-react-doc/pull/77)\n\n### 0.2.22\n\n- **Feature**\n\n  - 🚀 升级 React 16 至 17。[pr](https://github.com/MuYunyun/create-react-doc/pull/71)\n\n### 0.2.21\n\n- **Feature**\n\n  - 🚀 升级 webpack4 至 webpack5。[pr](https://github.com/MuYunyun/create-react-doc/pull/65)\n\n### 0.2.14\n\n- **Feature**\n\n  - 🚀 支持 inject 与 injectWithPathname 注入自定义逻辑。[pr](https://github.com/MuYunyun/create-react-doc/pull/65)\n\n### 0.2.14\n\n- **Feature**\n\n  - 🚀 集成 Github action, 支持自动化打包、发布站点。\n\n### 0.2.7\n\n`2020-09-25`\n\n- **Feature**\n\n  - 🚀 提供 @crd/leetcode-cli 提供将 leetcode 已 AC 的题目转化为 markdown table 的能力。[pr](https://github.com/MuYunyun/create-react-doc/pull/22)\n\n### 0.2.0\n\n`2020-08-02`\n\n- **Feature**\n\n  - 🚀 站点支持全局搜索菜单标题与文件内容。[pr](https://github.com/MuYunyun/create-react-doc/pull/22)\n\n### 0.1.20\n\n`2020-07-13`\n\n- **Fix**\n\n  - 🐞 fix [20](https://github.com/MuYunyun/create-react-doc/issues/20)。\n  - 🐞 fix [17](https://github.com/MuYunyun/create-react-doc/issues/17)。\n\n- **Enhancement**\n\n  - 🎈 项目结构重构为 monorepo。[pr](https://github.com/MuYunyun/create-react-doc/pull/16)\n\n### 0.1.0\n\n- **Feature**\n\n  - 🚀 详细内容见 [issue](https://github.com/MuYunyun/create-react-doc/issues/2)"
  },
  {
    "path": "docs/测试/测试标签.md",
    "content": "<!--\nabbrlink: a80c431d\ntags: ['自定义标签1', '自定义标签2', '自定义标签1']\n-->\n\n该页面用来测试自定义标签。\n"
  },
  {
    "path": "docs/测试/测试路由.md",
    "content": "<!--\ntags: ['自定义标签1']\n-->\n\n* 该页面用来测试未使用 abbrlink 的中文路径。\n"
  },
  {
    "path": "docs/站点发布.md",
    "content": "<!--\nabbrlink: ude9296y\n-->\n\n## 站点发布\n\n在 [快速上手](http://muyunyun.cn/create-react-doc/%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B) 一节中介绍了如何快速搭建站点, 本节将介绍如何将搭建好的站点打包、发布到 gh-pages。\n\n### 自动打包发布到 gh-pages (推荐)\n\n初始化的模板项目集成了 `Github action` 的 [ci 配置](https://github.com/MuYunyun/create-react-doc/blob/main/packages/templates/default/.github/workflows/gh-pages.yml), 使用方只需在 main 分支执行 `git push` 即可以完成站点的自动部署。\n\n![](http://with.muyunyun.cn/ea24d511f76efe5ba5d13bb6b1609aac.jpg)\n\n如果是第一次部署, 在执行以下操作后, 需要在项目的 setting 选项卡中将 Github Pages 选择为 gh-pages。(详情见 [First Deployment with GITHUB_TOKEN](https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-first-deployment-with-github_token))\n\n```bash\ngit init\ngit add .\ngit commit -m \"first commit\"\ngit branch -M main\ngit remote add origin https://github.com/用户或组织名/项目名.git\ngit push -u origin main\n```\n\n### 手动打包发布\n\n如果需要发布到自定义服务器, 可以执行 `npm run build` 或者 `yarn build` 对将要发布的文档站点进行打包构建, 此时的文档网站已准备好进行部署。\n\n接着将打包出的 `.crd-dist` 的文件资源同步到目标服务器即可。"
  },
  {
    "path": "docs/高阶用法.md",
    "content": "<!--\nabbrlink: 9v9ug9h8\n-->\n\n## 高阶用法\n\n与 git 文件结构类似, 如果在展示的文件夹中有私有文件不方便展示在文档站点, 可以在 `.gitignore` 文件中设置过滤文件, 这样它们就不会展示在文档站点中了。eg: [.gitignore](https://github.com/MuYunyun/blog/blob/main/.gitignore)\n\n### 插入自定义脚本\n\n在 `config.yml` 文件中加入 `inject` 字段。\n\n```diff\n+ inject: injectLogic/index.js\n```\n\n然后在根目录新建与 `inject` 字段相对应的文件, 声明 `injectWithPathname` 函数, 写入[自定义逻辑](https://github.com/MuYunyun/create-react-doc/injectLogic/index.js)。\n\n```js\n// perf injectWithPathname logic every pathname changes\nconst injectWithPathname = (pathname) => {}\n\nmodule.exports = { injectWithPathname }\n```"
  },
  {
    "path": "gh-pages.js",
    "content": "const ghPages = require('gh-pages')\n\nghPages.publish(\n  '.crd-dist',\n  {\n    branch: 'gh-pages',\n    repo: 'https://github.com/MuYunyun/create-react-doc.git',\n  },\n  (error) => {\n    if (error) {\n      console.error(error)\n    } else {\n      console.log('docs sync success')\n    }\n  }\n)\n"
  },
  {
    "path": "injectLogic/index.js",
    "content": "/* eslint-disable no-empty */\n// seo: perf inject logic only once\nconst inject = () => {\n  // SEO for Google through https://search.google.com/search-console/welcome\n  const meta = document.createElement('meta')\n  meta.name = 'google-site-verification'\n  meta.content = '7fyp1NuvXSRLM9KpMq5_YNE_0zFZkPnuV-SbVVFgWbI'\n  document.head.appendChild(meta)\n}\n\n// perf injectWithPathname logic every pathname changes\nconst injectWithPathname = (pathname) => {}\n\nmodule.exports = { inject, injectWithPathname }\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"version\": \"1.10.3\",\n  \"command\": {\n    \"bootstrap\": {\n      \"npmClientArgs\": [\n        \"--no-package-lock\"\n      ]\n    },\n    \"publish\": {\n      \"allowBranch\": [\n        \"main\",\n        \"qa/latest\"\n      ],\n      \"message\": \"chore: publish\"\n    }\n  },\n  \"//\": \"set yarn workspaces in root\",\n  \"useWorkspaces\": true,\n  \"npmClient\": \"yarn\"\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"create-react-doc\",\n  \"private\": true,\n  \"workspaces\": [\n    \"packages/*\"\n  ],\n  \"description\": \"Fast static generated site. Just write markdown file.\",\n  \"homepage\": \"http://muyunyun.cn/create-react-doc\",\n  \"bin\": {\n    \"react-doc\": \"bin/react-doc.js\"\n  },\n  \"scripts\": {\n    \"bootstrap\": \"lerna bootstrap\",\n    \"bootstrap --hoist\": \"lerna bootstrap --hoist\",\n    \"clean\": \"lerna clean\",\n    \"start\": \"yarn bootstrap && node packages/create-react-doc/index.js start\",\n    \"build\": \"node packages/create-react-doc/index.js build\",\n    \"deploy\": \"node packages/create-react-doc/index.js deploy\",\n    \"release\": \"lerna publish\",\n    \"release-qa\": \"lerna publish --npm-tag=beta\",\n    \"cleanup\": \"rm -rf node_modules/gh-pages/.cache\",\n    \"deploy:site\": \"npm run cleanup && node gh-pages\",\n    \"up:dev\": \"sh utils/uppackage-dev.sh\",\n    \"up\": \"sh utils/uppackage.sh\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\"\n  },\n  \"keywords\": [\n    \"react\",\n    \"create-react-doc\",\n    \"blog\",\n    \"markdown\"\n  ],\n  \"author\": \"muyunyun\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"eslint\": \"^4.19.1\",\n    \"eslint-config-airbnb\": \"^16.1.0\",\n    \"eslint-plugin-import\": \"^2.11.0\",\n    \"eslint-plugin-jsx-a11y\": \"^6.0.3\",\n    \"eslint-plugin-react\": \"^7.7.0\",\n    \"gh-pages\": \"^3.1.0\",\n    \"lerna\": \"^3.22.1\"\n  }\n}\n"
  },
  {
    "path": "packages/crd-client-utils/.npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n\n# https://github.com/sass/node-sass#binary-configuration-parameters\nsass_binary_site=https://npm.taobao.org/mirrors/node-sass/\n\n# https://github.com/Medium/phantomjs#deciding-where-to-get-phantomjs\n# phantomjs_cdnurl=http://cnpmjs.org/downloads\nphantomjs_cdnurl=https://npm.taobao.org/dist/phantomjs\n"
  },
  {
    "path": "packages/crd-client-utils/README.md",
    "content": "### crd-client-utils\n\n[create-react-doc](https://github.com/MuYunyun/create-react-doc) 的工具包。"
  },
  {
    "path": "packages/crd-client-utils/index.js",
    "content": "import { useLayoutEffect, useEffect } from 'react'\n\nconst ifDev = env === 'dev'\nconst ifProd = env === 'prod'\nconst ifPrerender = window.__PRERENDER_INJECTED && window.__PRERENDER_INJECTED.prerender\n\n// Not only Prod env but also [some part of Dev env](https://github.com/MuYunyun/create-react-doc/blob/main/packages/crd-scripts/src/web/index.js#L10-L13)\n// need using useLayoutEffect. If meeting this case in the future, thinking about passing extra tag from <RouterRoot />.\nconst useEnhancedEffect = ifProd\n  ? useLayoutEffect\n  : useEffect\n\nexport {\n  ifDev,\n  ifProd,\n  ifPrerender,\n  useEnhancedEffect\n}\n"
  },
  {
    "path": "packages/crd-client-utils/package.json",
    "content": "{\n  \"name\": \"crd-client-utils\",\n  \"version\": \"1.8.2\",\n  \"description\": \"Utils with create react doc\",\n  \"main\": \"index.js\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\",\n    \"directory\": \"packages/utils\"\n  },\n  \"keywords\": [],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"author\": \"muyunyun\",\n  \"license\": \"MIT\",\n  \"gitHead\": \"ffc5e4cbc94a7356da558c2dbf46e2f39bb8b199\"\n}\n"
  },
  {
    "path": "packages/crd-generator-sitemap/.npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n\n# https://github.com/sass/node-sass#binary-configuration-parameters\nsass_binary_site=https://npm.taobao.org/mirrors/node-sass/\n\n# https://github.com/Medium/phantomjs#deciding-where-to-get-phantomjs\n# phantomjs_cdnurl=http://cnpmjs.org/downloads\nphantomjs_cdnurl=https://npm.taobao.org/dist/phantomjs\n"
  },
  {
    "path": "packages/crd-generator-sitemap/README.md",
    "content": "### crd-generator-sitemap\n\n[create-react-doc](https://github.com/MuYunyun/create-react-doc) SEO 插件, 用于生成站点地图。"
  },
  {
    "path": "packages/crd-generator-sitemap/generate.js",
    "content": "const { getDocsConfig } = require('crd-utils')\n\n// template for google SEO\n// <url>\n//   <loc>muyunyun.cn/blog/xxx</loc>\n//   <lastmod>{{ sNow | formatDate }}</lastmod>\n//   <changefreq>daily</changefreq>\n//   <priority>1.0</priority>\n// </url>\n\nconst docsConfig = getDocsConfig()\n\nconst template = content =>\n  `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n  ${content}\n</urlset>\n`\n\n/**\n * generate sitemap for google.\n */\nconst generateSiteMap = (routes) => {\n  const domain = docsConfig && docsConfig.domain\n  const repo = docsConfig && docsConfig.repo\n  let content = ''\n  for (let i = 0; i < routes.length; i++) {\n    if (i === routes.length - 1) {\n      content +=\n`  <url>\n    <loc>${domain}/${repo}${routes[i]}</loc>\n  </url>`\n    } else {\n      content +=\n`  <url>\n    <loc>${domain}/${repo}${routes[i]}</loc>\n  </url>\\n`\n    }\n  }\n  return template(content)\n}\n\nmodule.exports = {\n  generateSiteMap,\n}\n"
  },
  {
    "path": "packages/crd-generator-sitemap/index.js",
    "content": "const { generateSiteMap } = require('./generate')\n\nmodule.exports = {\n  generateSiteMap,\n}\n"
  },
  {
    "path": "packages/crd-generator-sitemap/package.json",
    "content": "{\n  \"name\": \"crd-generator-sitemap\",\n  \"version\": \"1.3.4\",\n  \"description\": \"generator sitemap for create-react-doc\",\n  \"main\": \"index.js\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\",\n    \"directory\": \"packages/crd-generator-sitemap\"\n  },\n  \"keywords\": [],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"author\": \"muyunyun\",\n  \"license\": \"MIT\",\n  \"gitHead\": \"ffc5e4cbc94a7356da558c2dbf46e2f39bb8b199\"\n}\n"
  },
  {
    "path": "packages/crd-scripts/.npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n\n# https://github.com/sass/node-sass#binary-configuration-parameters\nsass_binary_site=https://npm.taobao.org/mirrors/node-sass/\n\n# https://github.com/Medium/phantomjs#deciding-where-to-get-phantomjs\n# phantomjs_cdnurl=http://cnpmjs.org/downloads\nphantomjs_cdnurl=https://npm.taobao.org/dist/phantomjs\n"
  },
  {
    "path": "packages/crd-scripts/README.md",
    "content": "                                                     _.-\"\\\n                                                _.-\"      \\\n                                              ,-\"          \\\n                                              \\    create    \\\n                                              \\ \\    react    \\\n                                              \\ \\      doc     \\\n                                                \\ \\         _.-;\n                                                \\ \\    _.-\"   :\n                                                  \\ \\,-\"    _.-\"\n                                                  \\(   _.-\"\n                                                    `--\"\n\n# crd-scripts\n\ncrd-scripts 封装提供了一系列构建、发布脚本。\n"
  },
  {
    "path": "packages/crd-scripts/index.js",
    "content": "const initProject = require('./src/commands/initProject')\nconst initTheme = require('./src/commands/initTheme')\nconst initCache = require('./src/utils/initCache')\nconst Servers = require('./src/server')\nconst Build = require('./src/build')\nconst Deploy = require('./src/deploy')\nconst Generate = require('./src/generate')\nconst paths = require('./src/conf/path')\n\nmodule.exports = {\n  initProject,\n  initTheme,\n  initCache,\n  Servers,\n  Build,\n  Deploy,\n  Generate,\n  paths,\n}\n"
  },
  {
    "path": "packages/crd-scripts/package.json",
    "content": "{\n  \"name\": \"crd-scripts\",\n  \"version\": \"1.10.3\",\n  \"description\": \"Scripts using with Create React Doc\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"@mdx-js/loader\": \"^1.6.22\",\n    \"@nuxtjs/friendly-errors-webpack-plugin\": \"^2.0.2\",\n    \"babel-eslint\": \"^8.0.1\",\n    \"chalk\": \"^4.1.0\",\n    \"colors-cli\": \"^1.0.13\",\n    \"copy-markdown-image-webpack-plugin\": \"^2.0.0\",\n    \"copy-template-dir\": \"^1.3.0\",\n    \"crd-client-utils\": \"^1.8.2\",\n    \"crd-generator-sitemap\": \"^1.3.4\",\n    \"crd-prerender-spa-plugin\": \"^0.2.0\",\n    \"crd-theme\": \"^1.10.3\",\n    \"crd-utils\": \"^1.5.0\",\n    \"css-loader\": \"^0.28.7\",\n    \"css-minimizer-webpack-plugin\": \"^1.2.0\",\n    \"detect-port\": \"^1.2.2\",\n    \"esbuild-loader\": \"^2.20.0\",\n    \"eslint\": \"^7.11.0\",\n    \"eslint-loader\": \"^4.0.2\",\n    \"file-loader\": \"^1.1.11\",\n    \"fs-extra\": \"^5.0.0\",\n    \"gh-pages\": \"^1.2.0\",\n    \"html-webpack-plugin\": \"^4.5.1\",\n    \"less-loader\": \"^7.2.1\",\n    \"loading-cli\": \"^1.0.6\",\n    \"local-ip-url\": \"^1.0.1\",\n    \"mini-css-extract-plugin\": \"^0.4.0\",\n    \"open-browsers\": \"^1.1.1\",\n    \"path-browserify\": \"^1.0.1\",\n    \"postcss-flexbugs-fixes\": \"^3.3.1\",\n    \"postcss-loader\": \"^2.0.9\",\n    \"process\": \"^0.11.10\",\n    \"rehype-katex\": \"^5.0.0\",\n    \"remark-math\": \"^3.0.1\",\n    \"rimraf\": \"^2.6.2\",\n    \"string-replace-loader\": \"^3.0.1\",\n    \"style-loader\": \"^0.19.1\",\n    \"upath\": \"^1.0.2\",\n    \"url-replace-loader\": \"^1.0.0\",\n    \"webpack\": \"^5.12.2\",\n    \"webpack-dev-middleware\": \"^3.7.1\",\n    \"webpack-dev-server\": \"^3.8.1\",\n    \"webpack-hot-dev-clients\": \"^1.0.4\",\n    \"webpackbar\": \"^4.0.0\",\n    \"write\": \"^1.0.3\",\n    \"yamljs\": \"^0.3.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\",\n    \"directory\": \"packages/scripts\"\n  },\n  \"keywords\": [],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"author\": \"muyunyun\",\n  \"license\": \"MIT\",\n  \"gitHead\": \"ffc5e4cbc94a7356da558c2dbf46e2f39bb8b199\"\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/build.js",
    "content": "const webpack = require('webpack')\nconst fs = require('fs')\nconst { docsConfig } = require('crd-utils')\nconst conf = require('./conf/webpack.config.prod')\nrequire('colors-cli/toxic')\n\nmodule.exports = function serve(program) {\n  if (!fs.existsSync(docsConfig)) {\n    console.log('please check config.yml in root dir!\\n')\n    return\n  }\n  const webpackConf = conf(program)\n  const compiler = webpack(webpackConf)\n  compiler.run((err, stats) => {\n    if (err) { throw err }\n    // 官方输出参数\n    // https://webpack.js.org/configuration/stats/\n    // https://github.com/webpack/webpack/issues/538#issuecomment-59586196\n    /* eslint-disable */\n    console.log(stats.toString({\n      colors: true,\n      children: false,\n      chunks: false,\n      modules: false,\n      errors: true,\n      errorDetails: true,\n      errorStack: true,\n      warningsFilter: (warning) => {\n        return true\n      }\n    }))\n  })\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/commands/initProject.js",
    "content": "const path = require('path')\nconst { execSync } = require('child_process')\nconst fs = require('fs-extra')\nconst { templatePath, resolveApp } = require('crd-utils')\nconst copyTemplate = require('copy-template-dir')\nconst paths = require('../conf/path')\n\nconst log = console.log; // eslint-disable-line\n\n// eslint-disable-next-line no-unused-vars\nmodule.exports = function (params) {\n  // process.argv[2] means the first argument after react-doc, eg react doc abc, process.argv[2] is abc\n  const outDir = path.join(paths.projectPath, process.argv[2])\n  const projectName = path.basename(outDir)\n\n  const crdpkg = require(paths.crdPackage); // eslint-disable-line\n  // replace the last vertion with x, so it'll install autoly when the last vertion changes.\n  const CRD_VERSION = crdpkg.version.split('.').slice(0, 2).concat('x').join('.')\n\n  // clear output dir\n  if (!fs.pathExistsSync(outDir)) {\n    fs.ensureDirSync(outDir)\n  }\n\n  const defaultTemplatePath = `${templatePath}/default`\n\n  // copy template, see https://github.com/MuYunyun/create-react-doc/issues/50\n  if (!fs.pathExistsSync(defaultTemplatePath)) {\n    execSync('mkdir temp && cd temp && yarn add crd-templates -D')\n  }\n  const templatePathInTemp = resolveApp('temp/node_modules/crd-templates/default')\n  if (fs.pathExistsSync(templatePathInTemp)) {\n    copyTemplate(templatePathInTemp, outDir, {\n      name: projectName,\n      crdVersion: CRD_VERSION,\n    }, (err, createdFiles) => {\n      if (err) return log(`Copy Tamplate Error: ${err} !!!`.red)\n      createdFiles.sort().forEach((createdFile) => {\n        log(`  ${'create'.green} ${createdFile.replace(paths.projectPath, '')}`)\n      })\n      // to hack https://github.com/yoshuawuyts/copy-template-dir/issues/16\n      execSync(`cp -r ${templatePathInTemp}/.github ${outDir}`)\n      execSync('rm -rf temp')\n      log('\\n  initialization finished!\\n'.green)\n      const cmdstr = `cd ${projectName} && yarn && yarn start`.cyan\n      log(`  Run the ${cmdstr} to start the website.\\n\\n`)\n    })\n  } else {\n    log(` ❎ crd-templates install fail.\\n\\n`)\n  }\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/commands/initTheme.js",
    "content": "/**\n * This file is to init theme quickly.\n */\nconst path = require('path')\nconst { execSync } = require('child_process')\nconst fs = require('fs-extra')\nconst { templatePath } = require('crd-utils')\nconst copyTemplate = require('copy-template-dir')\nconst paths = require('../conf/path')\n\nconst log = console.log; // eslint-disable-line\n\n// eslint-disable-next-line no-unused-vars\nmodule.exports = function (themeName) {\n  const outDir = path.join(paths.projectPath, themeName)\n\n  const crdpkg = require(paths.crdPackage); // eslint-disable-line\n  // replace the last vertion with x, so it'll install autoly when the last vertion changes.\n  const CRD_VERSION = crdpkg.version.split('.').slice(0, 2).concat('x').join('.')\n\n  // clear output dir\n  if (!fs.pathExistsSync(outDir)) {\n    fs.ensureDirSync(outDir)\n  }\n\n  const defaultTemplatePath = `${templatePath}/theme/default`\n\n  if (!fs.pathExistsSync(defaultTemplatePath)) {\n    execSync('mkdir temp && cd temp && yarn add crd-templates -D')\n  }\n  copyTemplate(defaultTemplatePath, outDir, {\n    name: themeName,\n    crdVersion: CRD_VERSION,\n  }, (err, createdFiles) => {\n    if (err) return log(`Copy Tamplate Error: ${err} !!!`.red)\n    createdFiles.sort().forEach((createdFile) => {\n      log(`  ${'create'.green} ${createdFile.replace(paths.projectPath, '')}`)\n    })\n    execSync('rm -rf temp')\n    log('\\n  initialization finished!\\n'.green)\n    const cmdstr = `cd ${themeName} && yarn && yarn start`.cyan\n    log(`  Run the ${cmdstr} to start the website.\\n\\n`)\n  })\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/conf/getDirTree.js",
    "content": "const { directoryTree } = require('./node-directory-tree')\n\nconst getDirTree = (cmd) => {\n  const dir = cmd.markdownPaths\n  const dirs = Array.isArray(dir) ? dir : [dir]\n  const otherProps = {\n    mdconf: true,\n    extensions: /\\.md/,\n    prerender: true,\n  }\n  const mapTagsWithArticle = []\n  const dirTree = dirs.map(path => directoryTree({\n    path,\n    options: otherProps,\n    mapTagsWithArticle\n  }))\n  return {\n    dirTree,\n    // map tags with path. [{ tagName: 'custom Tag 1', mapArticle: [{ path, name }]}]\n    mapTagsWithArticle\n  }\n}\n\nmodule.exports = {\n  getDirTree,\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/conf/getPrerenderRoutes.js",
    "content": "// eg: ['docs/quick_start.md', 'a']\n// output: ['/quick_start', '/a/b', '/a/b/c']\nconst getPrerenderRoutes = (dirTree) => {\n  const dpCloneDirTree = JSON.parse(JSON.stringify(dirTree))\n  const result = recursiveDirTree(dpCloneDirTree)\n  result.push('/404')\n  result.push('/tags')\n  return result\n}\n\nfunction recursiveDirTree(data) {\n  return recursive(\n    data,\n    '',\n    []\n  )\n}\n\nfunction recursive(\n  data,\n  routePath,\n  prerenderRouteArr,\n) {\n  data.forEach((item) => {\n    const { mdconf } = item || {}\n    const { abbrlink, tags } = mdconf || {}\n    const composeRouteName = `${routePath}/${item.name}`.replace(/.md$/, '')\n\n    if (item.type === 'directory') {\n      if (item.children && item.children.length > 0) {\n        item.children = recursive(\n          item.children,\n          composeRouteName,\n          prerenderRouteArr,\n        )\n      } else {\n        item.children = []\n      }\n    } else if (item.type === 'file') {\n      const prerenderRouteName = abbrlink\n        ? `/${abbrlink}`\n        : composeRouteName\n      prerenderRouteArr.push(prerenderRouteName)\n    }\n  })\n  return prerenderRouteArr\n}\n\nmodule.exports = {\n  getPrerenderRoutes\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/conf/node-directory-tree.js",
    "content": "/* eslint-disable no-undef */\nconst fs = require('fs')\nconst PATH = require('path')\nconst YAML = require('yamljs')\nconst { execSync } = require('child_process')\nconst {\n  replaceForFrontMatter,\n  generateRandomId,\n} = require('crd-utils')\nconst { getDigitFromDir, timeFormat } = require('../utils')\n\nconst constants = {\n  DIRECTORY: 'directory',\n  FILE: 'file',\n}\n\nfunction safeReadDirSync(path) {\n  let dirData = {}\n  try {\n    /**\n     * to make sure it's ordered like such rules, link issue: https://github.com/nodejs/node/issues/3232\n     * 1.x                  1.x\n     * 2.x    instead of   10.x\n     * 10.x                 2.x\n     */\n    dirData = fs.readdirSync(path).sort((dir1, dir2) => {\n      const dir1Digit = getDigitFromDir(dir1)\n      const dir2Digit = getDigitFromDir(dir2)\n      if (dir1Digit && dir2Digit) {\n        return dir1Digit - dir2Digit\n      }\n      return 0\n    })\n  } catch (ex) {\n    if (ex.code === 'EACCES')\n    // User does not have permissions, ignore directory\n    // eslint-disable-next-line brace-style\n    { return null }\n    throw ex\n  }\n  return dirData\n}\n\n// collect unique tags from all articles.\nconst tagsArr = []\n\n/** build directory Tree, fork from https://github.com/mihneadb/node-directory-tree\n * path: path for file\n * options: {\n *   exclude: RegExp|RegExp[] - A RegExp or an array of RegExp to test for exclusion of directories.\n *   extensions : RegExp - A RegExp to test for exclusion of files with the matching extension.\n *   mdconf: Boolean.\n *   prerender: Boolean. Used for prerender.\n *   generate: Boolean. Used for generating info in front-matter.\n * }\n * mapTagsWithArticle: [{\n *  tagName: 'customTag1',    // tag type name\n *  mapArticle: [{\n *    path,                   // click tag to jump route such as /tags/customTag1\n *    title                   // the name of article\n *  }]\n * }]\n */\nfunction directoryTree({\n  path,\n  options,\n  routePath = '',\n  mapTagsWithArticle\n}) {\n  const name = PATH.basename(path, '.md')\n  const item = { name }\n  const routePropsCurrent = `${routePath}/${name}`\n  if (!options.prerender) {\n    item.path = path\n  }\n  let stats\n  try {\n    stats = fs.statSync(path)\n  } catch (e) {\n    return null\n  }\n\n  // Skip if it matches the exclude regex\n  if (options && options.exclude && options.exclude.test(path)) return null\n\n  if (stats.isFile()) {\n    const ext = PATH.extname(path).toLowerCase()\n\n    // Skip if it does not match the extension regex\n    if (options && options.extensions && !options.extensions.test(ext)) { return null }\n\n    if (options && options.mdconf) {\n      item.type = constants.FILE\n      const contentStr = fs.readFileSync(path).toString()\n      if (!contentStr) return\n      const contentMatch = contentStr.match(/^<!--([^>]*)-->/)\n      /** generate abbrlink in FrontMatter */\n      if (options.generate) {\n        const randomId = generateRandomId(8)\n        if (!contentMatch) {\n          replaceForFrontMatter({\n            path,\n            target: `<!--\\nabbrlink: ${randomId}\\n-->\\n`\n          })\n        }\n        if (contentMatch && contentMatch[1].indexOf('abbrlink') === -1) {\n          replaceForFrontMatter({\n            path,\n            source: contentMatch[1],\n            target: `\\nabbrlink: ${randomId}${contentMatch[1]}`\n          })\n          console.log('✅ replaceForFrontMatter success')\n        }\n      }\n\n      const yamlParse = contentMatch ? YAML.parse(contentMatch[1]) : {}\n      const { tags: articleTags, abbrlink } = yamlParse\n      if (Array.isArray(articleTags) && Array.isArray(mapTagsWithArticle)) {\n        const cpArticleTags = Array.from(new Set(articleTags))\n        for (let i = 0; i < cpArticleTags.length; i++) {\n          const articleTag = cpArticleTags[i]\n          const articleTagIndex = tagsArr.indexOf(articleTag)\n          if (articleTagIndex > -1) {\n            mapTagsWithArticle[articleTagIndex]['mapArticle'].push({\n              path: abbrlink ? `/${abbrlink}` : routePropsCurrent,\n              title: name\n            })\n          } else {\n            tagsArr.push(cpArticleTags[i])\n            mapTagsWithArticle.push({\n              tagName: cpArticleTags[i],\n              mapArticle: [{\n                path: abbrlink ? `/${abbrlink}` : routePropsCurrent,\n                title: name\n              }]\n            })\n          }\n        }\n      }\n\n      item.mdconf = yamlParse\n      try {\n        // see https://stackoverflow.com/questions/2390199/finding-the-date-time-a-file-was-first-added-to-a-git-repository/2390382#2390382\n        const result = execSync(`git log --format=%aD ${path} | tail -1`)\n        item.birthtime =\n          Buffer.isBuffer(result) && timeFormat(new Date(result))\n      } catch (error) {\n        console.log(`❎ error: ${error.message}`)\n      }\n      try {\n        // see https://stackoverflow.com/questions/22497597/get-the-last-modification-data-of-a-file-in-git-repo\n        const result = execSync(`git log -1 --pretty=\"format:%ci\" ${path}`)\n        item.mtime = Buffer.isBuffer(result) && timeFormat(new Date(result))\n      } catch (error) {\n        console.log(`❎ error: ${error.message}`)\n      }\n      item.size = stats.size // File size in bytes\n      item.extension = ext\n      if (!options.prerender) {\n        item.relative = item.path.replace(process.cwd(), '')\n        item.isEmpty = contentMatch\n          ? !String.prototype.trim.call(contentStr.replace(contentMatch[0], ''))\n          : true\n        const uglifyContent = contentStr.replace(/\\s/g, '')\n        item.content = uglifyContent\n      }\n    }\n  } else if (stats.isDirectory()) {\n    const dirData = safeReadDirSync(path)\n    if (dirData === null) return null\n    item.children = dirData\n      .map(child =>\n        directoryTree({\n          path: PATH.join(path, child),\n          options,\n          routePath: routePropsCurrent,\n          mapTagsWithArticle\n        }),\n      )\n      .filter(e => !!e)\n    item.type = constants.DIRECTORY\n    if (!options.prerender) {\n      item.size = item.children.reduce((prev, cur) => prev + cur.size, 0)\n    }\n  } else {\n    return null // Or set item.size = 0 for devices, FIFO and sockets ?\n  }\n  return item\n}\n\nmodule.exports = {\n  directoryTree\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/conf/path.js",
    "content": "const path = require('path')\nconst fs = require('fs')\nconst { execSync } = require('child_process')\nconst { resolveApp, docsConfig, getDocsConfig } = require('crd-utils')\nconst chalk = require('chalk')\n\n// handle the problem of symbol in any platform\nconst appDirectory = fs.realpathSync(process.cwd())\n\nconst modPath = resolveApp('node_modules')\n// get config crd from package.json\nfunction getCrdConf() {\n  const packagePath = resolveApp('./package.json')\n  let conf = {}\n  if (fs.existsSync(packagePath)) {\n    const confPkg = require(packagePath); // eslint-disable-line\n    conf = confPkg.crd\n  }\n  return conf\n}\n\nfunction getConfigFilePath(fileName, type) {\n  const conf = getCrdConf()\n  // read config\n  if (conf && conf[type]) {\n    // load theme dir\n    if (type === 'theme') {\n      if (!conf[type]) conf[type] = fileName\n      const _path = path.resolve(appDirectory, 'theme', conf[type])\n      const _NodeModulesPath = path.resolve(\n        appDirectory,\n        'node_modules',\n        conf[type],\n      )\n      if (fs.existsSync(_path)) {\n        return fs.realpathSync(_path)\n      } else if (fs.existsSync(_NodeModulesPath)) {\n        return fs.realpathSync(_NodeModulesPath)\n      }\n      return false\n    }\n    if (/^(favicon|logo)$/.test(type)) {\n      return path.resolve(appDirectory, conf[type])\n    }\n  }\n  const _filepath = path.resolve(appDirectory, fileName)\n  if (fs.existsSync(_filepath)) {\n    // favicon|logo in default root dir.\n    return _filepath\n  }\n  return false\n}\n\n// Get favicon path\nconst faviconPath = () => {\n  const _path = getConfigFilePath('./favicon.ico', 'favicon')\n  if (_path) return _path\n  // the path'll be writen dynamiclly in the future\n  return resolveApp('node_modules/crd-theme/favicon.ico')\n}\n\n// Get logo path\nconst logoPath = () => {\n  const _path = getConfigFilePath('./logo.svg', 'logo')\n  if (_path) return _path\n  return false\n}\n\nlet theme = ''\n// theme in develop mode.\nlet devTheme = false\n\nconst getTheme = () => {\n  if (docsConfig) {\n    const docsConfigObj = getDocsConfig()\n    if (!docsConfigObj) return\n    if (docsConfigObj.devTheme) {\n      devTheme = docsConfigObj.devTheme\n      theme = docsConfigObj.devTheme\n    } else {\n      theme = docsConfigObj.theme\n\n      // install custom theme\n      if (!fs.existsSync(resolveApp(`node_modules/${theme}`))) {\n      // todo: chalkblue(xxx) not show in the terminal\n        chalk.blue(`Install theme ${theme}`)\n        // -W means ignore-workspace-root-check\n        execSync(`yarn add ${theme} -D -W`)\n        chalk.blue(`Install theme ${theme} done`)\n      } else {\n        chalk.blue(`Upgrade theme ${theme}`)\n        // -W means ignore-workspace-root-check\n        execSync(`yarn upgrade ${theme}`)\n        chalk.blue(`Upgrade theme ${theme} done`)\n      }\n    }\n  }\n}\n\ngetTheme()\n\n// get exclude folders\nfunction getExcludeFoldersRegExp() {\n  if (!fs.existsSync(modPath)) return []\n  let regexp = fs.readdirSync(modPath)\n  /** whitelist to include */\n  const whiteListRegExp = new RegExp(`create-react-doc(.*)|crd-scripts|crd-theme|${theme}`)\n  regexp = regexp.filter(\n    item => !whiteListRegExp.test(item),\n    // item => !/create-react-doc(.*)|crd-scripts|crd-theme/.test(item),\n  )\n  regexp = regexp.map((item) => {\n    let rgxPath = `node_modules${path.sep}${item}`\n    if (path.sep === '\\\\') {\n      // to watch: is '\\\\' needful?\n      rgxPath = `node_modules\\\\${path.sep}${item}`\n    }\n    return new RegExp(rgxPath)\n  })\n  return regexp\n}\n\n// crd tool dir\nconst toolDirectory = fs.realpathSync(__dirname)\nconst resolveTool = relativePath => path.resolve(toolDirectory, relativePath)\n\nmodule.exports = {\n  // markdown dir\n  crdConf: getCrdConf(),\n  defaultTheme: devTheme\n    ? resolveApp(`${devTheme}`)\n    : resolveApp(`node_modules/${theme}`),\n  defaultNodeModules: modPath,\n  projectPath: appDirectory,\n  publicPath: '',\n  logoPath: logoPath(),\n  // crd tool dir\n  getExcludeFoldersRegExp: getExcludeFoldersRegExp(),\n  crdPackage: resolveTool('../../package.json'),\n  defaultFaviconPath: faviconPath(),\n  appIndexJs: resolveTool('../web/index.js'),\n  appDir: resolveTool('../web'),\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/conf/rawTreeReplaceLoader.js",
    "content": "// A variation of https://github.com/react-doc/node-directory-tree-md/blob/master/lib/directory-tree-md.js\nconst { directoryTree } = require('./node-directory-tree')\nconst PATH = require('path')\nconst { ifInGitIgnore } = require('../utils/index')\n\nfunction getAllWatchPath(arr, pathArr = []) {\n  arr.forEach((item) => {\n    const mdfilePathInProject = item.path.replace(\n      process.cwd() + PATH.sep,\n      '',\n    )\n    if (!ifInGitIgnore(mdfilePathInProject) && item.type === 'file') {\n      pathArr.push(item.path)\n    }\n    if (item.children && item.children.length > 0) {\n      pathArr.concat(getAllWatchPath(item.children, pathArr))\n    }\n  })\n  return pathArr\n}\n\nfunction replacePath(dirs, path) {\n  for (let i = 0; i < dirs.length; i += 1) {\n    const element = PATH.dirname(dirs[i])\n    const reg = new RegExp(`^${element}`, 'gi')\n    if (reg.test(path)) {\n      path = path.replace(reg, '')\n      break\n    }\n  }\n  return path\n}\n\nfunction getRelativePath(arr, relativePath, dirs) {\n  const pathArr = []\n  arr.forEach((item) => {\n    if (relativePath && item.path) {\n      item.path = replacePath(dirs, item.path)\n    }\n    if (item.children && item.children.length > 0) {\n      item.children = getRelativePath(item.children, relativePath, dirs)\n    }\n    const notInGitIgnore = !ifInGitIgnore(item.path.replace(PATH.sep, ''))\n    if (notInGitIgnore) {\n      pathArr.push(item)\n    }\n  })\n  return pathArr\n}\n\nmodule.exports = function (source) {\n  // get option config from webpack loader, here is https://github.com/MuYunyun/create-react-doc/blob/main/packages/scripts/src/conf/webpack.config.prod.js#L61-L70\n  const options = this.getOptions() || {}\n  const { include, directoryTrees } = options\n  const { dir, relativePath, ...otherProps } = directoryTrees\n  let content = typeof source === 'string' ? JSON.parse(source) : source\n  // It's said loader resuls are flagged as cacheable. See https://webpack.js.org/api/loaders/#thiscacheable.\n  // if (this.cacheable) this.cacheable()\n  if (directoryTrees && (!include || include.test(this.resourcePath))) {\n    const dirs = Array.isArray(dir) ? dir : [dir]\n    const dirTree = dirs.map(path => directoryTree({\n      path,\n      options: otherProps,\n    }))\n\n    const filemd = getAllWatchPath(dirTree)\n    filemd.forEach((fileItem) => {\n      this.addDependency(fileItem)\n    })\n    // replace full file path with relative path\n    content = getRelativePath(\n      dirTree,\n      relativePath,\n      dirs,\n    )\n  }\n  content = JSON.stringify(content)\n    .replace(/\\u2028/g, '\\\\u2028')\n    .replace(/\\u2029/g, '\\\\u2029')\n\n  return `module.exports = ${content}`\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/conf/webpack.config.dev.js",
    "content": "const autoprefixer = require('autoprefixer')\nconst webpack = require('webpack')\nconst path = require('path')\nconst upath = require('upath')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst { defaultHTMLPath } = require('crd-utils')\nconst FriendlyErrorsWebpackPlugin = require('@nuxtjs/friendly-errors-webpack-plugin')\nconst { getDocsConfig } = require('crd-utils')\nconst { getDirTree } = require('./getDirTree')\nconst config = require('./webpack.config')\nconst paths = require('./path')\n\nmodule.exports = function (cmd) {\n  const docsConfig = getDocsConfig()\n  const { mapTagsWithArticle } = getDirTree(cmd)\n  config.mode = 'development'\n  config.devtool = 'eval-source-map'\n  config.entry = [\n    require.resolve('react-hot-loader/patch'),\n    require.resolve('webpack-hot-dev-clients/webpackHotDevClient'),\n    paths.appIndexJs,\n  ]\n  config.output.publicPath = '/'\n  config.module.rules = config.module.rules.map((item) => {\n    if (item.oneOf) {\n      const loaders = []\n      loaders.push({\n        // Process JS with Babel.\n        test: /\\.(js|jsx)$/,\n        exclude: paths.getExcludeFoldersRegExp.concat(/\\.(cache)/),\n        use: [\n          {\n            loader: require.resolve('string-replace-loader'),\n            options: {\n              multiple: [\n                { search: '__project_root__', replace: upath.normalizeSafe(paths.projectPath), flags: 'ig' },\n                { search: '__project_theme__', replace: upath.normalizeSafe(paths.defaultTheme), flags: 'ig' },\n              ],\n            },\n          },\n          {\n            loader: 'esbuild-loader',\n            options: {\n              loader: 'jsx',\n              target: 'es2015',\n              // This will make esbuild automatically generate import statements,\n              // making the ProviderPlugin unnecesary if used only for \"react\".\n              // Note that this option makes sense only when used in conjuction\n              // with React >16.40.0 || >17\n              // https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html\n              jsx: 'automatic',\n            }\n          },\n        ],\n      })\n      // https://ilikekillnerds.com/2018/03/disable-webpack-4-native-json-loader/\n      loaders.push({\n        test: /crd\\.json$/,\n        // 禁用 Webpack 4 本身的 JSON 加载程序\n        type: 'javascript/auto',\n        use: [\n          {\n            loader: `${path.join(__dirname, './rawTreeReplaceLoader.js')}`,\n            options: {\n              include: /crd\\.json$/,\n              directoryTrees: {\n                dir: cmd.markdownPaths,\n                mdconf: true,\n                extensions: /\\.md/,\n                relativePath: true,\n              },\n            },\n          },\n        ],\n      })\n\n      loaders.push({\n        test: /\\.(css|less)$/,\n        use: [\n          require.resolve('style-loader'),\n          {\n            loader: require.resolve('css-loader'),\n            options: {\n              modules: true,\n              localIdentName: '[local]--[hash:base64:5]',\n              importLoaders: 1,\n            },\n          },\n          {\n            loader: require.resolve('postcss-loader'),\n            options: {\n              // Necessary for external CSS imports to work\n              // https://github.com/facebookincubator/create-react-app/issues/2677\n              ident: 'postcss',\n              plugins: () => [\n                require(\"postcss-flexbugs-fixes\"), // eslint-disable-line\n                autoprefixer({\n                  browsers: [\n                    '>1%',\n                    'last 4 versions',\n                    'Firefox ESR',\n                    'not ie < 9', // React doesn't support IE8 anyway\n                  ],\n                  flexbox: 'no-2009',\n                }),\n              ],\n            },\n          },\n          require.resolve('less-loader'),\n        ],\n      })\n\n      item.oneOf = loaders.concat(item.oneOf)\n    }\n    return item\n  })\n\n  config.optimization = {\n    // 将模块名称添加到工厂功能，以便它们显示在浏览器分析器中。\n    // 当接收到热更新信号时，在浏览器 console 控制台打印更多可读性高的模块名称等信息\n    moduleIds: 'named',\n  }\n\n  config.plugins = config.plugins.concat([\n    new webpack.DefinePlugin({\n      env: JSON.stringify('dev'),\n      mapTagsWithArticle: JSON.stringify(mapTagsWithArticle)\n    }),\n    new webpack.HotModuleReplacementPlugin(),\n    new HtmlWebpackPlugin({\n      inject: true,\n      favicon: paths.defaultFaviconPath,\n      template: defaultHTMLPath,\n      title: docsConfig && docsConfig.title ? docsConfig.title : 'Create React Doc',\n    }),\n    new FriendlyErrorsWebpackPlugin({\n      clearConsole: true,\n    }),\n  ])\n  return config\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/conf/webpack.config.js",
    "content": "/* eslint-disable global-require */\n/* eslint-disable import/no-dynamic-require */\nconst webpack = require('webpack')\nconst webpackbar = require('webpackbar')\nconst fs = require('fs')\nconst { resolveApp, docsConfig, docsBuildDist } = require('crd-utils')\nconst { getDocsConfig } = require('crd-utils')\n// const { getSearchContent } = require('../utils');\nconst remarkMath = require('remark-math')\nconst rehypeKatex = require('rehype-katex')\nconst paths = require('./path')\nconst pkg = require('../../package.json')\n\nconst define = {\n  FOOTER: null,\n  DOCSCONFIG: null,\n  INJECT: null,\n}\nif (paths.crdConf && paths.crdConf.footer && typeof paths.crdConf.footer === 'string') {\n  define.FOOTER = JSON.stringify(paths.crdConf.footer)\n}\n/* custom define docs config */\nif (docsConfig) {\n  // const searchContent = getSearchContent();\n  const docsConfigObj = getDocsConfig()\n  define.DOCSCONFIG = JSON.stringify(docsConfigObj)\n  // todo: searchContent affects the performance, so take annotation here templately.\n  // define.SEARCHCONTENT = searchContent && searchContent.toString();\n\n  // if there is inject logic in docsConfigObj\n  if (docsConfigObj && docsConfigObj.inject && fs.existsSync(resolveApp(docsConfigObj.inject))) {\n    define.INJECT = require(resolveApp(docsConfigObj.inject))\n  }\n}\n\nmodule.exports = {\n  entry: {},\n  output: {\n    path: docsBuildDist,\n    publicPath: paths.publicPath,\n    filename: 'js/[name].[hash:8].js',\n    chunkFilename: 'js/[name].[hash:8].js',\n  },\n  module: {\n    rules: [\n      {\n        // “oneOf”将遍历所有以下加载程序，直到一个符合要求。\n        // 当没有加载器匹配时，它将返回到加载程序列表末尾的“file”加载器。\n        oneOf: [\n          {\n            test: /\\.(svg|png|bmp|jpg|jpeg|gif)$/,\n            loader: require.resolve('url-replace-loader'),\n            options: {\n              limit: 10000,\n              name: 'img/[name].[hash:8].[ext]',\n              replace: [\n                {\n                  test: /crd\\.logo\\.svg$/,\n                  path: paths.logoPath,\n                },\n              ],\n            },\n          },\n          {\n            test: /\\.md$/,\n            use: [\n              {\n                loader: 'esbuild-loader',\n                options: {\n                  loader: 'jsx',\n                  target: 'es2015',\n                  // This will make esbuild automatically generate import statements,\n                  // making the ProviderPlugin unnecesary if used only for \"react\".\n                  // Note that this option makes sense only when used in conjuction\n                  // with React >16.40.0 || >17\n                  // https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html\n                  jsx: 'automatic',\n                }\n              },\n              {\n                loader: require.resolve('@mdx-js/loader'),\n                options: {\n                  remarkPlugins: [\n                    [\n                      remarkMath,\n                      {\n                        /* options */\n                      },\n                    ],\n                  ],\n                  rehypePlugins: [\n                    [\n                      rehypeKatex,\n                      {\n                        /* options */\n                      },\n                    ],\n                  ],\n                },\n              },\n            ],\n            exclude: /(node_modules)/,\n          },\n          // “file-loader”确保这些资源由WebpackDevServer服务。\n          // 当您导入资源时，您将获得（虚拟）文件名。\n          // 在生产中，它们将被复制到`build`文件夹。\n          // 此加载程序不使用“test”，因此它将捕获所有模块\n          {\n            // 排除`js`文件以保持“css”加载器工作，因为它注入它的运行时，否则将通过“文件”加载器处理。\n            // 还可以排除“html”和“json”扩展名，以便它们被webpacks内部加载器处理。\n            exclude: [/\\.js$/, /\\.html$/, /\\.json$/],\n            loader: require.resolve('file-loader'),\n            options: {\n              name: 'static/[name].[hash:8].[ext]',\n            },\n          },\n        ],\n      },\n    ],\n  },\n  plugins: [\n    // eslint-disable-next-line new-cap\n    new webpackbar({ name: pkg.name }),\n    new webpack.DefinePlugin({\n      VERSION: JSON.stringify(pkg.version),\n      ...define,\n    }),\n    // fix \"process is not defined\" error:\n    new webpack.ProvidePlugin({\n      process: 'process/browser',\n    }),\n  ],\n  resolve: {\n    fallback: {\n      path: require.resolve('path-browserify'),\n    },\n  },\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/conf/webpack.config.prod.js",
    "content": "const autoprefixer = require('autoprefixer')\nconst path = require('path')\nconst upath = require('upath')\nconst webpack = require('webpack')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst CopyMarkdownImageWebpackPlugin = require('copy-markdown-image-webpack-plugin')\nconst MiniCssExtractPlugin = require('mini-css-extract-plugin')\nconst PrerenderSPAPlugin = require('crd-prerender-spa-plugin')\nconst { generateSiteMap } = require('crd-generator-sitemap')\nconst fs = require('fs-extra')\nconst { defaultHTMLPath, docsBuildDist } = require('crd-utils')\nconst { getDocsConfig } = require('crd-utils')\nconst config = require('./webpack.config')\nconst paths = require('./path')\nconst { getPrerenderRoutes } = require('./getPrerenderRoutes')\nconst { getDirTree } = require('./getDirTree')\n\nconst Renderer = PrerenderSPAPlugin.PuppeteerRenderer\n\nmodule.exports = function (cmd) {\n  const docsConfig = getDocsConfig()\n  const { dirTree, mapTagsWithArticle } = getDirTree(cmd)\n  const routes = getPrerenderRoutes(dirTree)\n\n  config.mode = 'production'\n  config.entry = [paths.appIndexJs]\n  // config.output.filename = 'js/[hash:8].js'\n  config.output.chunkFilename = 'js/[name].[hash:8].js'\n  config.output.publicPath = docsConfig.repo ? `/${docsConfig.repo}/` : '/'\n  config.output.path = docsConfig.repo ? `${docsBuildDist}/${docsConfig.repo}` : docsBuildDist\n  config.module.rules = config.module.rules.map((item) => {\n    if (item.oneOf) {\n      const loaders = []\n      loaders.push({\n        // Process JS with Babel.\n        test: /\\.(js|jsx)$/,\n        exclude: paths.getExcludeFoldersRegExp.concat(/\\.(cache)/),\n        use: [\n          {\n            loader: require.resolve('string-replace-loader'),\n            options: {\n              multiple: [\n                { search: '__project_root__', replace: upath.normalizeSafe(paths.projectPath), flags: 'ig' },\n                { search: '__project_theme__', replace: upath.normalizeSafe(paths.defaultTheme), flags: 'ig' },\n              ],\n            },\n          },\n          {\n            loader: 'esbuild-loader',\n            options: {\n              loader: 'jsx',\n              target: 'es2015',\n              // This will make esbuild automatically generate import statements,\n              // making the ProviderPlugin unnecesary if used only for \"react\".\n              // Note that this option makes sense only when used in conjuction\n              // with React >16.40.0 || >17\n              // https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html\n              jsx: 'automatic',\n            }\n          },\n        ],\n      })\n      // https://ilikekillnerds.com/2018/03/disable-webpack-4-native-json-loader/\n      loaders.push({\n        test: /crd\\.json$/,\n        // 禁用 Webpack 4 本身的 JSON 加载程序\n        type: 'javascript/auto',\n        use: [\n          {\n            loader: `${path.join(__dirname, './rawTreeReplaceLoader.js')}`,\n            options: {\n              include: /crd\\.json$/, // 检查包含的文件名字\n              directoryTrees: {\n                // 指定目录生成目录树，json\n                dir: cmd.markdownPaths,\n                mdconf: true,\n                extensions: /\\.md/,\n                relativePath: true,\n              },\n            },\n          },\n        ],\n      })\n\n      loaders.push({\n        test: /\\.(css|less)$/,\n        use: [\n          MiniCssExtractPlugin.loader,\n          {\n            loader: require.resolve('css-loader'),\n            options: {\n              modules: true,\n              localIdentName: '[local]-[hash:base64:5]',\n              importLoaders: 1,\n            },\n          },\n          {\n            loader: require.resolve('postcss-loader'),\n            options: {\n              // Necessary for external CSS imports to work\n              // https://github.com/facebookincubator/create-react-app/issues/2677\n              ident: 'postcss',\n              plugins: () => [\n                require('postcss-flexbugs-fixes'), // eslint-disable-line\n                autoprefixer({\n                  browsers: [\n                    '>1%',\n                    'last 4 versions',\n                    'Firefox ESR',\n                    'not ie < 9', // React doesn't support IE8 anyway\n                  ],\n                  flexbox: 'no-2009',\n                }),\n              ],\n            },\n          },\n          require.resolve('less-loader'),\n        ],\n      })\n\n      item.oneOf = loaders.concat(item.oneOf)\n    }\n    return item\n  })\n  config.optimization = {\n    // minimize: true,\n    // minimizer: [\n    //   // For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line\n    //   // `...`,\n    //   new CssMinimizerPlugin(),\n    // ],\n  }\n\n  config.plugins = config.plugins.concat([\n    new webpack.DefinePlugin({\n      env: JSON.stringify('prod'),\n      mapTagsWithArticle: JSON.stringify(mapTagsWithArticle)\n    }),\n    new HtmlWebpackPlugin({\n      inject: true,\n      favicon: paths.defaultFaviconPath,\n      template: defaultHTMLPath,\n      title:\n        docsConfig && docsConfig.title ? docsConfig.title : 'Create React Doc',\n      minify: {\n        removeAttributeQuotes: true,\n        collapseWhitespace: true,\n        html5: true,\n        minifyCSS: true,\n        removeComments: true,\n        removeEmptyAttributes: true,\n      },\n    }),\n    new CopyMarkdownImageWebpackPlugin({\n      dir: cmd.markdownPaths,\n      toDir: config.output.path,\n    }),\n    // new webpack.optimize.DedupePlugin(),\n    new MiniCssExtractPlugin({\n      // Options similar to the same options in webpackOptions.output\n      // both options are optional\n      filename: 'css/[contenthash].css',\n      chunkFilename: 'css/[id].css',\n    }),\n    new PrerenderSPAPlugin({\n      // Required - The path to the webpack-outputted app to prerender.\n      staticDir: docsBuildDist,\n      outputDir: docsConfig.repo\n        ? `${docsBuildDist}/${docsConfig.repo}`\n        : docsBuildDist,\n      indexPath: docsConfig.repo\n        ? `${docsBuildDist}/${docsConfig.repo}/index.html`\n        : `${docsBuildDist}/index.html`,\n      // Required - Routes to render.\n      routes,\n      successCb: async () => {\n        if (docsConfig.repo) {\n          // not use fs.move here or it'll throw error in github action\n          await fs.copy(`${docsBuildDist}/${docsConfig.repo}`, docsBuildDist)\n          await fs.remove(`${docsBuildDist}/${docsConfig.repo}`)\n          const defaultPath = (dirTree.find(data => data.name === 'README.md')\n            && dirTree.find(data => data.name === 'README.md').mdconf\n            && dirTree.find(data => data.name === 'README.md').mdconf.abbrlink) || 'README'\n          // move README as root index.html\n          await fs.copy(`${docsBuildDist}/${defaultPath}/index.html`, `${docsBuildDist}/index.html`)\n          console.log('✅ generate prerender file success!')\n          if (docsConfig.seo) {\n            if (docsConfig.seo.google) {\n              fs.writeFileSync(`${docsBuildDist}/sitemap.xml`, generateSiteMap(routes))\n            }\n          }\n          console.log('✅ generate sitemap file success!')\n        }\n      },\n      // The actual renderer to use. (Feel free to write your own)\n      // Available renderers: https://github.com/Tribex/prerenderer/tree/master/renderers\n      renderer: new Renderer({\n        // Optional - The name of the property to add to the window object with the contents of `inject`.\n        injectProperty: '__PRERENDER_INJECTED',\n        // Optional - Any values you'd like your app to have access to via `window.injectProperty`.\n        inject: {\n          prerender: true,\n        },\n        // Optional - defaults to 0, no limit.\n        // Routes are rendered asynchronously.\n        // Use this to limit the number of routes rendered in parallel.\n        maxConcurrentRoutes: 4,\n        // https://pptr.dev/#?product=Puppeteer&version=v5.5.0&show=api-pagegotourl-options\n        navigationOptions: {\n          timeout: 0\n        }\n      }),\n    }),\n  ])\n  return config\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/conf/webpack.config.server.js",
    "content": "const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'\n\nmodule.exports = (cmd, webpackConf) => {\n  return {\n    // 启用生成文件的gzip压缩。\n    compress: true,\n    // 沉默WebpackDevServer自己的日志，因为它们通常没有用处。\n    // 这个设置仍然会显示编译警告和错误。\n    clientLogLevel: 'none',\n    // contentBase: conf.output.appPublic,\n    publicPath: webpackConf.output.publicPath,\n    hot: true,\n    historyApiFallback: {\n      // 带点的路径仍应使用历史回退。\n      // See https://github.com/facebookincubator/create-react-app/issues/387.\n      disableDotRule: true,\n    },\n    // historyApiFallback: true,\n    // WebpackDevServer默认是嘈杂的，所以我们发出自定义消息\n    // 通过上面的`compiler.plugin`调用来监听编译器事件。\n    quiet: true,\n    // 如果HTTPS环境变量设置为“true”，则启用HTTPS\n    https: protocol === 'https',\n    // 告诉服务器从哪里提供内容。提供静态文件，这只是必要的。\n    contentBase: cmd.markdownPaths,\n    // 通知服务器观察由devServer.contentBase选项提供的文件。\n    // it'll reload page when file change.\n    watchContentBase: true,\n    // avoid cpu overload in some case\n    watchOptions: {\n      ignored: /node_modules/,\n    },\n  }\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/deploy.js",
    "content": "const ghpages = require('gh-pages')\nconst loading = require('loading-cli')\n\nconst log = console.log; // eslint-disable-line\n\nmodule.exports = function server(cmd, docsConfig) {\n  if (!docsConfig) {\n    console.log('please check config.yml in root dir!\\n')\n    return\n  }\n  if (!docsConfig.user || !docsConfig.repo) {\n    console.log('please check user and repo in config.yml!\\n')\n    return\n  }\n  const { user, repo, publish } = docsConfig\n  log('  Start deploy to your git repo'.green)\n  const load = loading({\n    text: 'Please wait ...'.blue,\n    color: 'blue',\n    interval: 100,\n    stream: process.stdout,\n  }).start()\n\n  ghpages.publish(\n    cmd.output,\n    {\n      branch: cmd.branch,\n      repo: publish || `https://github.com/${user}/${repo}.git`,\n      message: `Update website, ${new Date()}!`,\n    },\n    (err) => {\n      load.stop()\n      if (err) {\n        return log(err)\n      }\n      log(`\\n  Push to ${cmd.branch} success!\\n`.green.bold)\n    },\n  )\n}\n\n"
  },
  {
    "path": "packages/crd-scripts/src/generate.js",
    "content": "const fs = require('fs')\nconst { docsConfig } = require('crd-utils')\nconst { directoryTree } = require('./conf/node-directory-tree')\n\nmodule.exports = function generate(program) {\n  if (!fs.existsSync(docsConfig)) {\n    console.log('❎ please check config.yml in root dir!\\n')\n    return\n  }\n\n  const dir = program.markdownPaths\n  const dirs = Array.isArray(dir) ? dir : [dir]\n  const otherProps = {\n    mdconf: true,\n    extensions: /\\.md/,\n    generate: true\n  }\n  dirs.map(path => directoryTree({\n    path,\n    options: otherProps,\n  }))\n  console.log('✅ generate success!')\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/server.js",
    "content": "const webpack = require('webpack')\nconst WebpackDevServer = require('webpack-dev-server')\nconst openBrowsers = require('open-browsers')\nconst detect = require('detect-port')\nconst fs = require('fs')\nconst { docsConfig } = require('crd-utils')\nconst prepareUrls = require('local-ip-url/prepareUrls')\nconst conf = require('./conf/webpack.config.dev')\nconst createDevServerConfig = require('./conf/webpack.config.server')\nrequire('colors-cli/toxic')\n\nfunction clearConsole() {\n  // process.stdout.write(process.platform === 'win32' ? '\\x1B[2J\\x1B[0f' : '\\x1B[2J\\x1B[3J\\x1B[H');\n}\n\nmodule.exports = function server(cmd) {\n  if (!fs.existsSync(docsConfig)) {\n    console.log('please check config.yml in root dir!\\n')\n    return\n  }\n  const HOST = cmd.host\n  let DEFAULT_PORT = cmd.port\n  const webpackConf = conf(cmd)\n  const compiler = webpack(webpackConf)\n\n  detect(DEFAULT_PORT).then((_port) => {\n    if (DEFAULT_PORT !== _port) DEFAULT_PORT = _port\n\n    const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'\n    const urls = prepareUrls({ protocol, host: HOST, port: DEFAULT_PORT })\n    // https://webpack.js.org/api/compiler-hooks/#aftercompile\n    // print log after being compiled\n    compiler.hooks.done.tap('done', () => {\n      /* eslint-disable */\n      console.log(`Dev Server Listening at Local: ${urls.localUrl.green}`);\n      console.log(`              On Your Network: ${urls.lanUrl.green}`);\n      console.log(`\\nTo create a production build, use ${'npm run build'.blue_bt}.`);\n      /* eslint-enable */\n    })\n\n    new WebpackDevServer(compiler, createDevServerConfig(cmd, webpackConf)).listen(DEFAULT_PORT, HOST, (err) => {\n      if (err) {\n        return console.log(err); // eslint-disable-line\n      }\n      clearConsole()\n      // open browser\n      openBrowsers(urls.localUrl)\n    })\n  }).catch((err) => {\n    console.log(err); // eslint-disable-line\n  })\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/utils/index.js",
    "content": "const fs = require('fs')\nconst { docsGitIgnore, searchFilePath } = require('crd-utils')\n\n/**\n * judege cur file if in git ignore.\n */\nexports.ifInGitIgnore = (mdfilePathInProject) => {\n  let gitIgnoreContentArr = []\n  if (fs.existsSync(docsGitIgnore)) {\n    const gitIgnoreContent = fs.readFileSync(docsGitIgnore)\n    gitIgnoreContentArr = gitIgnoreContent.toString().split('\\n')\n  }\n  return gitIgnoreContentArr.indexOf(mdfilePathInProject) > -1\n}\n\n/**\n * to get dight from cur dir.\n * If there are order && unorder file in one same folder, the unorder file'll be in front of order file.\n * eg:\n *  '1.xx' => 1\n *  'xx' => 0\n */\nexports.getDigitFromDir = (dir) => {\n  const matchedResult = dir.match(/^((\\d)*)\\.(\\s|\\S)*$/)\n  if (matchedResult && matchedResult[1]) {\n    return parseInt(matchedResult[1], 10)\n  }\n  return 0\n}\n\nfunction paddingTwoDigits(digit) {\n  return digit < 10 ? `0${digit}` : digit\n}\n\n/**\n * format time\n */\nexports.timeFormat = (date) => {\n  if (isNaN(date.getFullYear()) || isNaN(date.getMonth()) || isNaN(date.getDate())) return null\n  return `${date.getFullYear()}-${paddingTwoDigits(\n    date.getMonth() + 1,\n  )}-${paddingTwoDigits(date.getDate())}`\n}\n\nexports.getSearchContent = () => {\n  if (!fs.existsSync(searchFilePath)) {\n    console.log('there is no find .cache/search.js in root dir!\\n')\n    return null\n  }\n  return fs.readFileSync(searchFilePath)\n}\n\n"
  },
  {
    "path": "packages/crd-scripts/src/utils/initCache.js",
    "content": "const write = require('write')\nconst path = require('path')\nconst { cacheDirPath, getDocsConfig } = require('crd-utils')\nconst { directoryTree } = require('../conf/node-directory-tree')\n\nmodule.exports = function (program, cb) {\n  const treeData = program.markdownPaths.map((markdownPath) => {\n    return directoryTree({\n      path: markdownPath,\n      options: {\n        mdconf: true, // Markdown config for exsiting file.\n        extensions: /\\.md/,\n      },\n    })\n  })\n  // to collect search data\n  const searchData = []\n  const docsConfig = getDocsConfig()\n  const useSearchPlugin = docsConfig.search && docsConfig.host\n\n  function dfsMap(data) {\n    // eslint-disable-next-line no-plusplus\n    for (let i = 0; i < data.length; i++) {\n      if (data[i].children) {\n        dfsMap(data[i].children)\n      } else {\n        const searchMapKeys = docsConfig.search_map ? Object.keys(docsConfig.search_map) : []\n        // eslint-disable-next-line no-plusplus\n        for (let x = 0; x < searchMapKeys.length; x++) {\n          if (data[i].relative) {\n            const searchMapIndex = data[i].relative.indexOf(searchMapKeys[x])\n            if (searchMapIndex !== -1 && typeof searchMapIndex === 'number') {\n              const effectedPath = data[i].relative.replace(\n                searchMapKeys[x],\n                docsConfig.search_map[searchMapKeys[x]],\n              )\n              searchData.push({\n                title: data[i].name,\n                url: `${effectedPath.replace(/.md/g, '')}`,\n                content: data[i].content,\n              })\n              break\n            }\n          }\n        }\n      }\n    }\n  }\n  if (useSearchPlugin) {\n    // README\n    searchData.push({\n      title: 'README',\n      url: 'README',\n      content: treeData[0].content,\n    })\n    // map treeData to generate search data source\n    dfsMap(treeData)\n    const writeSearchPath = path.resolve(\n      process.cwd(),\n      cacheDirPath,\n      'search.js',\n    )\n    write.sync(\n      writeSearchPath,\n      `${JSON.stringify(\n        searchData,\n      )}`,\n    )\n  }\n  cb()\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/web/Router.js",
    "content": "import { BrowserRouter, Route, Routes } from 'react-router-dom'\nimport theme from 'crd-theme'\nimport menuSource from './crd.json'\n\n/**\n * serialize router data\n */\nfunction routeData(data, arrayRoute = [], routePath = '/', article) {\n  data.forEach((item) => {\n    const routePropsCurrent = `${routePath}${item.name}`.replace(/.md$/, '')\n    const { mdconf, ...otherItem } = item\n    arrayRoute.push({\n      path: routePropsCurrent,\n      mdconf: mdconf || { title: item.name },\n      props: { ...otherItem },\n      article: article || item.name,\n    })\n    if (item.children && item.children.length > 0) {\n      arrayRoute.concat(routeData(item.children, arrayRoute, `${routePropsCurrent}/`, article || item.name))\n    }\n  })\n  return arrayRoute\n}\n\nfunction menuSourceFormat(data, routePath, article) {\n  const arr = []\n  data.forEach((item) => {\n    const routePropsCurrent = `${routePath || ''}/${item.name}`.replace(/.md$/, '')\n    if (item.type === 'directory') {\n      if (item.children && item.children.length > 0) {\n        item.title = item.name.replace(item.extension, '')\n        item.mdconf = {}\n        item.props = { isEmpty: true }\n        item.children = menuSourceFormat(item.children, routePropsCurrent, article || item.name)\n      } else {\n        item.title = item.name.replace(item.extension, '')\n        item.mdconf = { title: item.name }\n        item.props = { isEmpty: true }\n        item.children = []\n      }\n    } else {\n      item.title = item.mdconf && item.mdconf.title ? item.mdconf.title : item.name.replace(item.extension, '')\n      if (!item.mdconf) {\n        item.props = { isEmpty: true }\n      }\n    }\n    item.routePath = routePropsCurrent\n    item.article = article || item.name\n    arr.push(item)\n  })\n  return arr\n}\n\nconst RoutersContainer = ({ ...props }) => {\n  return (\n    <Routes>\n      <Route\n        path=\"/*\"\n        element={theme({\n          routeData: routeData(menuSource),\n          menuSource: menuSourceFormat(menuSource),\n          ...props,\n        })}\n      />\n    </Routes>\n  )\n}\n\nexport default function RouterRoot() {\n  return (\n    <BrowserRouter>\n      <RoutersContainer />\n    </BrowserRouter>\n  )\n}\n"
  },
  {
    "path": "packages/crd-scripts/src/web/crd.json",
    "content": "[]\n"
  },
  {
    "path": "packages/crd-scripts/src/web/index.js",
    "content": "import { hydrate } from 'react-dom'\nimport { renderToString } from 'react-dom/server';\n// import { hydrateRoot } from 'react-dom/client'\nimport { ifDev, ifPrerender } from 'crd-client-utils'\nimport RouterRoot from './Router'\n\nif (ifDev) {\n  // dev render\n  document.getElementById('root').innerHTML = renderToString(<RouterRoot />)\n  hydrate(\n    <RouterRoot />,\n    document.getElementById('root'),\n  )\n  // hydrateRoot(\n  //   document.getElementById('root'),\n  //   <RouterRoot />,\n  // )\n} else if (ifPrerender) {\n  // prerender\n  document.getElementById('root').innerHTML = renderToString(<RouterRoot />)\n} else {\n  // prod render:\n  // It'll cause some [unkown error](https://github.com/MuYunyun/create-react-doc/issues/278) using hydrateRoot here.\n  // So still using hydrate temporarily.\n  hydrate(\n    <RouterRoot />,\n    document.getElementById('root'),\n  )\n  // hydrateRoot(\n  //   document.getElementById('root'),\n  //   <RouterRoot />,\n  // )\n}\n"
  },
  {
    "path": "packages/crd-seed/.npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n\n# https://github.com/sass/node-sass#binary-configuration-parameters\nsass_binary_site=https://npm.taobao.org/mirrors/node-sass/\n\n# https://github.com/Medium/phantomjs#deciding-where-to-get-phantomjs\n# phantomjs_cdnurl=http://cnpmjs.org/downloads\nphantomjs_cdnurl=https://npm.taobao.org/dist/phantomjs\n"
  },
  {
    "path": "packages/crd-seed/README.md",
    "content": "## 主题\n\ncreate-react-doc 提供了官方默认主题 [crd-seed](https://github.com/MuYunyun/create-react-doc/tree/main/packages/crd-seed)。该主题支持以下特性:\n\n* 适配移动、PC 多端展示。\n* 支持暗黑模式。\n* 文档支持内嵌 codepen、codesandbox。\n* GitHub 联动。\n\n使用该主题搭建的项目有:\n\n* [blog](https://github.com/MuYunyun/blog), [站点](http://muyunyun.cn/blog)\n  * ![](http://with.muyunyun.cn/90d3e357a31649b9466a828a92b6d88d.jpg)\n  * ![](http://with.muyunyun.cn/2e7440e4256debda2d73a4e6392c7146.jpg-300)\n* [diana](https://github.com/MuYunyun/diana), [站点](https://muyunyun.cn/diana/)\n\n如果您想定制化或者分享个人主题, 可以参考[自定义主题](http://muyunyun.cn/create-react-doc/自定义主题)章节。"
  },
  {
    "path": "packages/crd-seed/component/Affix/affix.js",
    "content": "import { useState, useEffect, useRef } from 'react'\nimport { throttle } from './utils'\n\nconst Affix = ({\n  offsetTop,\n  offsetBottom,\n  children,\n  target,\n  onChange,\n  className,\n  wrapperClassName,\n  style,\n  width,\n  affixStyle,\n}) => {\n  const placeholderRef = useRef(null)\n  const wrapperRef = useRef(null)\n  const widthRef = useRef(width)\n  const [positionStyle, setPositionStyle] = useState({})\n  // 滚动元素\n  let scrollElm = window\n  // 是否是绝对布局模式\n  const fixedRef = useRef(false)\n  const [fixed, setFixed] = useState(fixedRef.current)\n\n  useEffect(() => {\n    widthRef.current = width\n  }, [width])\n\n  useEffect(() => {\n    // 在子节点移开父节点后保持原来占位\n    setWrapperDimension()\n  }, [fixed, width])\n\n  useEffect(() => {\n    if (target) scrollElm = target()\n    scrollElm.addEventListener('scroll', scroll)\n    return () => {\n      if (target) scrollElm = target()\n      scrollElm.removeEventListener('scroll', scroll)\n    }\n  }, [offsetTop, offsetBottom])\n\n  const validValue = (value) => {\n    return typeof value === 'number'\n  }\n  const setWrapperDimension = () => {\n    const { width: wrapperRefWidth, height: wrapperRefHeight } = wrapperRef.current\n      ? wrapperRef.current.getBoundingClientRect()\n      : {}\n    placeholderRef.current &&\n      (placeholderRef.current.style.height = `${wrapperRefHeight}px`)\n    placeholderRef.current &&\n      (placeholderRef.current.style.width =\n        typeof width === 'number' ? `${width}px` : `${wrapperRefWidth}px`)\n    wrapperRef.current &&\n      (wrapperRef.current.style.width =\n        typeof width === 'number' ? `${width}px` : `${wrapperRefWidth}px`)\n  }\n  const updateFixed = () => {\n    fixedRef.current = !fixedRef.current\n    setFixed(fixedRef.current)\n  }\n  const handleScroll = () => {\n    const rect =\n      placeholderRef.current && placeholderRef.current.getBoundingClientRect()\n    if (!rect) return\n    let { top, bottom } = rect\n    const updatePositionStyle = {\n      width:\n        typeof widthRef.current === 'number'\n          ? widthRef.current\n          : placeholderRef.current &&\n            placeholderRef.current.getBoundingClientRect().width,\n      zIndex: 999,\n    }\n    let containerTop = 0 // 容器距离视口上侧的距离\n    let containerBottom = 0 // 容器距离视口下侧的距离\n\n    if (scrollElm === window) {\n      bottom = window.innerHeight - bottom\n    } else {\n      const containerRect = scrollElm && scrollElm.getBoundingClientRect()\n      containerTop = containerRect && containerRect.top\n      containerBottom = containerRect && containerRect.bottom\n      top -= containerTop // 距离容器顶部的距离\n      bottom = containerBottom - bottom // 距离容器底部的距离\n    }\n\n    if (\n      (validValue(offsetTop) && top <= offsetTop) ||\n      (validValue(offsetBottom) && bottom <= offsetBottom)\n    ) {\n      if (!fixedRef.current) {\n        updatePositionStyle.position = 'fixed'\n        validValue(offsetTop) && (updatePositionStyle.top = offsetTop + containerTop)\n        validValue(offsetBottom) &&\n          (updatePositionStyle.bottom =\n            scrollElm === window\n              ? bottom\n              : window.innerHeight - (containerBottom - offsetBottom))\n        onChange && onChange(true)\n        updateFixed()\n        setPositionStyle(updatePositionStyle)\n      }\n    } else if (fixedRef.current) {\n      updatePositionStyle.position = 'relative'\n      onChange && onChange(false)\n      updateFixed()\n      setPositionStyle(updatePositionStyle)\n    }\n  }\n\n  const scroll = throttle(handleScroll, 20)\n\n  return (\n    <div ref={placeholderRef} style={style} className={className}>\n      <div\n        ref={wrapperRef}\n        className={wrapperClassName}\n        style={{ ...{ position: 'relative' }, ...positionStyle, ...affixStyle }}\n      >\n        {children}\n      </div>\n    </div>\n  )\n}\n\nexport default Affix\n"
  },
  {
    "path": "packages/crd-seed/component/Affix/index.js",
    "content": "import Affix from './affix'\n\nexport default Affix\n"
  },
  {
    "path": "packages/crd-seed/component/Affix/utils/index.js",
    "content": "const throttle = (fn, wait) => {\n  let inThrottle\n  let lastFn\n  let lastTime\n  return function () {\n    const context = this\n    // eslint-disable-next-line prefer-rest-params\n    const args = arguments\n    if (!inThrottle) {\n      fn.apply(context, args)\n      lastTime = Date.now()\n      inThrottle = true\n    } else {\n      clearTimeout(lastFn)\n      lastFn = setTimeout(() => {\n        if (wait - (Date.now() - lastTime) <= 0) {\n          fn.apply(context, args)\n          lastTime = Date.now()\n        }\n      }, Math.max(wait - (Date.now() - lastTime), 0))\n    }\n  }\n}\n\nexport { throttle }\n"
  },
  {
    "path": "packages/crd-seed/component/Footer/index.js",
    "content": "import cx from 'classnames'\nimport styles from './index.less'\n\nconst version = VERSION; // eslint-disable-line\nconst footer = FOOTER; // eslint-disable-line\n\nconst FooterView = ({ inlineCollapsed }) => {\n  return (\n    <div\n      className={cx(styles.footer, {\n        [`${styles['footer-inlineCollapsed']}`]: inlineCollapsed,\n      })}\n    >\n      {footer ? (\n        <div dangerouslySetInnerHTML={{ __html: footer }} />\n      ) : (\n        <>\n          <div className={styles.powered_by}>\n            {`Powered by${' '}`}\n            <a\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              href=\"https://github.com/MuYunyun/create-react-doc\"\n            >\n              Create React Doc\n            </a>\n            .\n          </div>\n          <div>\n            <i className=\"fa fa-user\" /><span className={styles.uv_count} id=\"busuanzi_value_site_uv\" />\n            <span className={styles.split}>|</span>\n            <i className=\"fa fa-eye\" /><span className={styles.pv_count} id=\"busuanzi_value_site_pv\" />\n          </div>\n        </>\n\n      )}\n    </div>\n  )\n}\n\nexport default FooterView\n"
  },
  {
    "path": "packages/crd-seed/component/Footer/index.less",
    "content": ".footer {\n  font-size: 14px;\n  text-align: center;\n  border-top: 1px solid #e9e9e9;\n  margin: 50px 0 0 240px;\n  padding: 20px 0 50px 0;\n  clear: both;\n  color: #999;\n  transition: margin .2s ease-in-out;\n\n  a {\n    color: #758AC5;\n\n    &:hover {\n      color: #0800ff;\n    }\n  }\n\n  .powered_by {\n    margin-bottom: 8px;\n  }\n\n  &-inlineCollapsed {\n    margin: 50px 0 0 0;\n  }\n\n  .uv_count, .pv_count {\n    margin-left: 5px;\n  }\n\n  .split {\n    margin: 0 5px;\n  }\n}"
  },
  {
    "path": "packages/crd-seed/component/Header/index.js",
    "content": "import { useState } from 'react'\nimport cx from 'classnames'\nimport { Link } from 'react-router-dom'\nimport Switch from 'react-switch'\nimport { ifProd } from 'crd-client-utils'\nimport { isMobile } from '../../utils'\nimport Search from '../Search'\nimport styles from './index.less'\n\nconst Header = ({\n  className,\n  logo,\n}) => {\n  // eslint-disable-next-line no-undef\n  const { user, repo, tags } = DOCSCONFIG || {}\n  const [checked, setChecked] = useState(false)\n  const handleChange = (value) => {\n    value\n      ? document.body.classList.add(styles.darkMode)\n      : document.body.classList.remove(styles.darkMode)\n    setChecked(value)\n  }\n  return (\n    <div className={cx(styles.header, className)}>\n      <div className={styles.wrapper}>\n        <Link to=\"/\" replace className={styles.titleLink}>\n          <div className={styles.logo}>\n            {logo && <img alt=\"logo\" src={logo} />}\n            {!isMobile && (\n              <span>\n                {(DOCSCONFIG && DOCSCONFIG.title) || 'Create React Doc'}\n              </span>\n            )}\n          </div>\n        </Link>\n        {DOCSCONFIG && DOCSCONFIG.search ? <Search className={styles.search} /> : null}\n      </div>\n      <div className={styles.rightArea}>\n        {\n          tags\n            ? <Link\n              className={styles['tags']}\n              to={ifProd ? `/${repo}/tags` : '/tags'}\n            >\n              标签\n            </Link>\n            : null\n        }\n        <Switch\n          className={styles['no-dark-mode']}\n          onChange={handleChange}\n          checked={checked}\n          width={50}\n          height={24}\n          offColor=\"#0f1114\"\n          onColor=\"#0f1114\"\n          uncheckedIcon={\n            <img\n              className={styles.sun}\n              src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAABwNJREFUWAmtV1tsFFUY/s6Z2d22zLYlZakUCRVaQcqlWIiCiS1gTEB9UAO+GR9En3iQGI0xJiSiRB98MjEq8cEQTSBeHhQM0V7whtEGDWC90BYitxahtNtu25058/v/ZzvLbilawJNM5+yZ89+//1LgJhYRNLW1uDfBAvpGiIk2O5auvfFxqIH3ZJ8/u06GN6Z9+wVl5SjcD1IbZa/UPkPyYl2uR4dreoD2bnbYxTlBBRytkHXtAREphP5KuH4lddx9h70yxX05t7yYXwGb6W8nx1jibpl2rFlGBxcG9M18okOrn7Bnk/BAO/4bI0UeEE1zjBp3UmvjOxJXJdaKN/ZiIu4tOZrAb4aTdZAZArKmWeiiJZ6jt5tiagdCS9+6cgO1Ne6Mvhe+ixTIfyDVhipnK9p+P0Edqx9RW/YZtQVGmOLChRxNNlyPsTEgPQKMB3dbEHa0h1awYmQ83enTd2vmUtvKd1Glv2RkzBb+kZGRrKtjzG60Wguhd/lJZBingbcfWWe72vjT75bJDrhYtvA0hrurETDr5HyF2Knb1MM4ab//xIoOqueA0edRnkkinTyJdYvqLFDZO4zUPFCvVoDjJq4T7TE61IWh4x5KqxX5KVKkX8WZ/t2ov2cb3MHt4dhIyOxIJxJOOF6xRx/99BksXLoecWcXytILMNBDqKpnGZWPquYfPxY8iXGR9fK+SgFrgcRPXPjVqhehL+3EmZ5RGJQi1QBU8TPThQnOQzm+5UXGIcetUeEAfP13VwzpI+w1jGJWdSliNfvVhiMPiOsllJag4M/UGHiqM6dlBb2OTLKHHV6KkvogrJ4XhBWniWK/Gp1MQyf93FOeUXKmKk/FzJxbQtKLjFXYT4USupy8fQVir2ynVEBiZMG0qtOHMS/AW4Gwrk7BG3C1F0B5nqNKE0CME4MfVRLPnXkBKe+ipvoFhNQywOhdghvLi0F8ReyVXV4BKTBRbbe5f64zR/DHsdZw1hJfeWlHl/GNRJzDxrd5m192z78TMaVnKELZoINZS4BzQ7vtnZljSnha/pPCbkuxzXcupYwI5tIeCpGc0Yp9tWHZQy/rmYhRfNgg4bHJBYLzGkxsRJF4XKlE2jBOHNSv3kY7Tj6vthzPFl61BrYwqFlmEQhtSVXmLiksxLmtRgYXI1ULU61JJ4eVKmG3/5sCVgpbMT6OMJ2E08/29Xf3w6v4FnHdCjfWgXu/O8Z5mLdCkeRs2khHe1DqOtQwbHWTAnM5S2HNmhALYo5KjkPFrMMKjZl6HxhWIAb0BqE+/73GrBRQUsKYiBu4JX8ycI6wtw+i5ef3NZpsrKVSHYCP37jwGDgeE1SA0S/xtl5SU2fs1ApEp0qTLVRjgyycDSsLHMSwmFltZMStR3uLLg6BdLhDa5dC6ryU2pHBe1BVO9tUcwfitJt2CLJZUHoG6T7Op75u0IyK31TCPcwFqgPk/KCaD3dFOuZBCO7xvCT/j048b3I3c7F2+WuOW7qdgkucFYlcQ4qop3yzTX7WaKfOCccye3Ts1Etq0+a/BHCF1yPgF3tAUkR6OrtGmo6gl94qqcXKh3rDyrOkPa58URoWcov2Mo6M+0QjrqKB+b7++oMa9Sz+ZkM0mie6aAtnGUvhmxaI+TogPOSQedgWioGSHFLn3v4kLh4HRspNmOGv41k+55siLFp2z6xYeJjhljFcbmxJlr4ga06TbevSByz/glQq4BJx46/c+237PbBqEYKxX3HpmKZEnQnr65X20hqJYaNcLoFOLiJk2LuBbyg7Q0OEn+hm0P3honxFD6rdxYorKpeIoi4YSSvyQHQIbM5t4+YNxLj/OxhVOOE4585qGpjnq+wSx6Q9CtNxTjd5klB+g6Mv36r0+b9cZFi44WYkHdG2ZWb3TtOUOXyVAlKlpGvJIAJ3eBMyfYS5C0qRZGtC85j+4sOasDe9xznPYezhhO/2Q6eP2fSOvYHOjtuQ1a9Q1VKynVDaMc8E0tptdxUsTFpFIYjcZKcbnoaQTNdiqCwNlL4G7oziSqGnT1ALf34vhk4R5zU3qYV9ONp9K88RtouShE68JwaU8dFw5W617shWa9ykeaBIn2hcsvPgL00k45QdTCZuSVcTRNs+8fnyLvooQfR5iujAnR9bxfY2xOVOxFS8SK3Le0l48VyYu1M8HRe5JD8wKPTjYnifaK3Wfn/GChYQ8ZAi6WRzWgqLV5YrsVLnZaVSoXU1g9gOIDwFySiGi+Zdrnzr7J3r+SMuszlcQCRn8lNGcTuSy2jOI7o9mxjZo+vR3ej3tN+ifRSOyUTS0+VMOid93cCubeiy/6TImS0QxRSCq2vxKr45zV+FQnjWH6D2xg+E9EatLcLAdHTgtGGD80D6jM0+aOl4wJgO/f96R2aJKCQ3yvgftRhdFMOpd6oAAAAASUVORK5CYII=\"\n              width=\"16\"\n              height=\"16\"\n              role=\"presentation\"\n              alt=\"sun\"\n            />\n          }\n          checkedIcon={\n            <img\n              className={styles.moon}\n              src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAABlJJREFUWAm1V3tsFEUcntnXvXu0tBWo1ZZHihBjCEWqkHiNaMLDRKOtQSKaiCFKQtS/SbxiFCHGCIkmkBSMwZhQNTFoQZD0DFiwtCDFAkdDqBBBKFj63rvdnfH7zfVo5aFBj0l2Z/dm5vd98/0es8dYjlpr62azufnDQNZcU1PciMfjWvb9rvZSMk4Ayfb36pLH13189GC8LAtIRLLPt+pzwrCuLq4ISEv/gHmitrAwfPbEkXc/ad4dL6iujrvyX0jcitgd/yZlZqftP6995Mr5TVLa22Tn8XVX2g/XLSRjUu7Q79jonS7I7hS7/0oOb5VyqF52n98oj7esXX07EjlxwXWisRmSnm3b29TTM8iYrjmFBWExubxwY/uhNas4r/WySl1fc5cetDMd7ydl+lMJJRw5WC8ud62Xx5rfepzwxgZmbhUYNS5Stvsj4yo2GXJEFBVHWDBkfdbR9HpYBaaUajDnBLKKpl1xRKYcgGtMCqEzTaSnThk/SQT0uJqTqFNBmXMCsZE48DzRZRMBRjv1GHNdk3HBImF9ZUvTyxM40pMKVc4JZBXQOLOFoDeKSxdp6HIQcO4rjYT9fn0pjbz9GLt7BAAODmjSVReXUMFzNW5x5vfxp2mIxZjIuQKJxAmFa+is2DQJJQ0JyBVExNOYcJnPxx/6/utnijmP555ALEagKAGGnGn64QORBjARcIA/yJk7JMJBLRrNtybTvH88KGjCf2jK86bhzmMcwDKFZEQvbIhxFYhChoMWMzU2iWznlIBEVJOsP+1bdX/ALx9l7jApADeDAEcMkE90JnUmmGl4USKQ0xhoW3JB5XY0YrxYWhLwMZZypUyjDGH35AbNwgUGiFBPpuGbHCpAOV1ZGXf2f/taftAv31DyeymN2d1IhAFAwTOmnzF/kKcdh3me7CYCOVNgycju84u8DeVlwfFq9/ZlTfldYrMUjOlrkjkD+rU+WzCROkcEchIDHR011syZW9JHD7y07N6JvhWMpz3pugaTkB6lWFVCKkhck0zzeMp2utq+uHrmfxOgoCO/Z8CXPlEQ1bdH8wgvhSIkEG0ICcQeExIFGdimjvKka7btJFZuaXOammIGKUCFQ53j9EN1dYKWqHf0t2w407W2tgs6h89ZnImjB55flh81tt9XirjjDuSl+oIPRQ0iWPgNZ5GqTqbBe3vSzEl5n5PhWKwocyR2HlqYN61qV18WjYjE8JLARZPQsUSim8foIRYTlGr02Ly7piASFRtKJ4VfieYhxdS2JcDVMN6xVOKZyrCGm8b108lrLRVzvptLH7IoEFLFANes6KnDi+uxfmvFnF17oALq5u1agu3/YfHkcSFzeSggV5eXRfIB7CHNcO5SUI+Ih5Ir7f4MAV9IqdFzdZgNpZw1Gcs1mNvgGbTbqQ9/cz7ZuuhgyYRQ49ljTyWHhr2DwpNHHFf+5gnWZ3Bharo+0TD5dNMw5vv9RlVpSRDHK4TlnoukhtYApuOHejSZQuo5g/A9BysdKRCyLl6062fN37OXMDlvUJtUrtmxo0avrW3wTrYs3jJ9RvRVChrmSmanPMpX2OXMsmDGh6AiEIwBAlvkOqIdBy+8JyAz8pz7QxiDth4KDy5uAlwzrWTnwC8Vc4KVAMZ3YUZ+IqoIjP3h5KFFX1ZMy3uW+7RhEDHgTi0zC9rS7uhPCDiNrGFyqBeERtKN/B0YlyFCkw0NJ5C0Ojv7zvT1a1WV1TuvZDdL4NTgB7CASYpsen6gqvG5jmTf5qHedADgkBl3D0nkSgNhZACDyi0FUKZRr3IdRjgN4WPPoFMIIegIK3mqd38fS80mcJKelM4szNyzZtQbkchGePuBRS8Eg9pHU8ojRQpSqs+ajAIwTjjUMQ/nvTNM0kicwYxZIYMh/891DYi+fvedB+c1xsm4lDU6ya+Axtz+RiAzEVYbajQOpq17F0R9QevNcEhfcU+xvyQQUalGJBSesqOkgPQ4YNyUZL9fSvUPDjoNAwN8/dwFjaczNkc3ptaMud1EIDtGcmXTcefO2cGSvKIFfp/2JIJxlq7xEl3nVPM4fDeIbPkD16/ptNc0bDu7qxbsu0R2JGywWMIjF2ft3tjfloAyQAGXiOn8hrqwbVvMXzaO+QeHXP6nF0wvX74Hf4NGG5GPjSlYoyM3P/0FbCT6zvM/yYoAAAAASUVORK5CYII=\"\n              width=\"16\"\n              height=\"16\"\n              role=\"presentation\"\n              alt=\"moon\"\n            />\n          }\n        />\n        <a href={`https://github.com/${user}/${repo}`} className={styles['github-corner']} title=\"Star me on GitHub\" aria-label=\"Follow me on GitHub\" rel=\"noopener\" target=\"_blank\">\n          <svg width=\"60\" height=\"60\" viewBox=\"0 0 250 250\" aria-hidden=\"true\">\n            <path d=\"M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z\" />\n            <path d=\"M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2\" fill=\"white\" style={{ transformOrigin: '130px 106px' }} className={styles['octo-arm']} />\n            <path d=\"M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z\" fill=\"white\" />\n          </svg>\n        </a>\n      </div>\n    </div>\n  )\n}\n\nexport default Header\n"
  },
  {
    "path": "packages/crd-seed/component/Header/index.less",
    "content": "@import '../../style/base.less';\n\n.logo {\n  float: left;\n  padding: 0 0 0 15px;\n\n  img {\n    height: 28px;\n    vertical-align: middle;\n  }\n\n  span {\n    vertical-align: middle;\n  }\n\n  img+span {\n    margin-left: 10px;\n  }\n}\n\n.header {\n  box-shadow: 0 2px 8px #f0f1f2;\n  line-height: 60px;\n  height: 60px;\n  position: relative;\n  width: 100%;\n  top: 0;\n  z-index: @header-zIndex;\n  display: flex;\n\n  .wrapper {\n    flex: 1;\n    display: flex;\n    align-items: center;\n\n    .titleLink {\n      display: inline-block;\n    }\n\n    .search {\n      margin-left: 40px;\n      max-width: 200px;\n      display: flex;\n      align-items: center;\n    }\n\n    .select {\n      width: 200px;\n    }\n  }\n\n  .rightArea {\n    display: flex;\n    align-items: center;\n\n    .sun {\n      position: absolute;\n      left: 5px;\n      top: 4px;\n    }\n\n    .moon {\n      position: absolute;\n      right: 5px;\n      top: 4px;\n    }\n\n    .github-corner {\n      display: block;\n\n      &:hover {\n        .octo-arm {\n          animation: octocat-wave 560ms ease-in-out;\n        }\n      }\n    }\n\n    svg {\n      vertical-align: bottom;\n    }\n  }\n}\n\n.tags {\n  font-size: 15px;\n  margin-right: 16px;\n}\n\n@keyframes octocat-wave {\n  0%, 100% {\n    transform: rotate(0);\n  }\n  20%, 60% {\n    transform: rotate(-25deg);\n  }\n  40%, 80% {\n    transform: rotate(100deg);\n  }\n}\n\n.pageTitle {\n  font-size: 30px;\n  line-height: 38px;\n  color: #0d1a26;\n  font-weight: 500;\n  margin-bottom: 20px;\n  margin-top: 8px;\n  padding-left: 20px;\n}\n\n.darkMode {\n  filter: invert(100%) hue-rotate(180deg);\n\n  .no-dark-mode {\n    filter: invert(100%) hue-rotate(180deg);\n  }\n}"
  },
  {
    "path": "packages/crd-seed/component/Icon/Icon.js",
    "content": "import { useEffect } from 'react'\nimport cx from 'classnames'\nimport loadSprite from './loadSprite'\nimport styles from './style/index.less'\n\n/* omit some props depends on arr */\nconst omit = (props, arr) =>\n  Object.keys(props)\n    .filter(k => arr.indexOf(k) === -1)\n    // eslint-disable-next-line no-sequences\n    .reduce((acc, key) => ((acc[key] = props[key]), acc), {})\n\nfunction Icon(props) {\n  const { type, color, prefixCls = 'icon', size, style, className, ...rest } = props\n\n  useEffect(() => {\n    loadSprite(props)\n  }, [type])\n\n  const newClassName = cx(styles[prefixCls], className)\n  const cloneStyle = { ...style }\n  if (color) {\n    cloneStyle.color = color\n  }\n  if (size) {\n    cloneStyle.fontSize = size\n  }\n\n  const restProps = omit(rest, ['svgContent'])\n\n  return (\n    <svg className={newClassName} style={cloneStyle} {...restProps}>\n      <use xlinkHref={`#${type}`} />\n    </svg>\n  )\n}\n\nexport default Icon\n"
  },
  {
    "path": "packages/crd-seed/component/Icon/iconsInfo.js",
    "content": "export const IconsInfo = {\n  folder:\n    '<svg viewBox=\"0 0 1024 1024\"><defs/><path d=\"M838 151H450a94 94 0 00-94-91H184c-52 0-94 42-94 94v595c0 51 42 93 94 93h654c52 0 94-42 94-93V244c0-51-42-93-94-93zm-654-31h172c19 0 35 15 35 34v26c0 17 13 30 29 30h418c19 0 34 15 34 34v27H150V154c0-19 15-34 34-34zm654 663H184a34 34 0 01-34-34V330h722v419c0 19-15 34-34 34z\"/></svg>',\n  file:\n    '<svg viewBox=\"0 0 1024 1024\"><defs/><path d=\"M512 320H256v-64h256v64zM256 512h448v-64H256v64zm0 128h448v-64H256v64zm0 128h448v-64H256v64zm640-480v608c0 35-29 64-64 64H192c-35 0-64-29-64-64V128c0-35 29-64 64-64h480l224 224zm-64 32L640 128H192v768h640V320z\"/></svg>',\n  edit:\n    '<svg viewBox=\"0 0 1026 1024\"><defs/><path d=\"M308 709l56-122 70 68-126 54zm96-171l366-353 82 80-366 352-82-79zm550-371l-51 48-82-80 50-48c8-8 24-6 32 2l49 47c5 5 8 11 8 18 0 5-3 9-6 13zM314 530l-2 3-52 184c-3 11 0 23 8 31 6 5 14 9 23 9l8-2 190-49h1a8 8 0 006-3l508-489c15-14 23-34 23-55 0-25-11-49-29-67l-49-47c-19-18-43-28-69-28-23 0-43 8-58 23L315 528l-1 2zM101 0C45 0 0 45 0 100v824c0 54 45 99 101 99h806c56 0 101-45 101-99V398h-86v451c0 49-41 88-90 88H176c-49 0-90-39-90-88V173c0-48 41-88 90-88h457V0H101z\"/></svg>',\n  'update-time':\n    '<svg viewBox=\"0 0 1024 1024\"><defs/><path d=\"M649 649c-4 0-7 0-11-4L502 543c-4-4-7-7-7-14V222c0-10 7-17 17-17s17 7 17 17v300l130 96c7 7 10 17 3 24-3 3-7 7-13 7z\"/><path d=\"M512 922a409 409 0 01-382-270c-4-10 0-17 10-21 10-3 17 0 20 11a376 376 0 00352 245c205 0 375-167 375-375 0-10 7-17 18-17s17 7 17 17c0 225-185 410-410 410zM119 529c-6 0-17-7-17-17a409 409 0 01792-140c4 10 0 17-10 21-10 3-17 0-20-11a376 376 0 00-352-245 377 377 0 00-375 375c0 10-7 17-18 17z\"/><path d=\"M119 563c-3 0-10 0-13-3l-86-86c-6-6-6-17 0-23s18-7 24 0l72 71 72-71c7-7 17-7 24 0s6 17 0 23l-86 86c4 3-3 3-7 3zM990 580c-4 0-10 0-14-3l-71-72-72 72c-7 7-17 7-24 0s-7-17 0-24l85-85c7-7 17-7 24 0l86 85c6 7 6 17 0 24-4 3-11 3-14 3z\"/></svg>',\n  'create-time':\n    '<svg viewBox=\"0 0 1024 1024\"><defs/><path d=\"M512 67a445 445 0 100 890 445 445 0 000-890zm0 849a404 404 0 110-808 404 404 0 010 808zm222-404H532V249a20 20 0 00-40 0v283c0 11 9 20 20 20h222a20 20 0 000-40z\"/></svg>',\n  search:\n    '<svg viewBox=\"0 0 1024 1024\"><defs/><path d=\"M401 801a401 401 0 110-801 401 401 0 010 801zm0-89a312 312 0 100-623 312 312 0 000 623z\"/><path d=\"M668 602l315 315-63 63-315-315z\"/></svg>',\n}\n"
  },
  {
    "path": "packages/crd-seed/component/Icon/index.js",
    "content": "import Icon from './Icon'\n\nexport default Icon\n"
  },
  {
    "path": "packages/crd-seed/component/Icon/loadSprite.js",
    "content": "import { IconsInfo } from './iconsInfo'\n\n/* tslint:disable:max-line-length */\n// inspried by https://github.com/kisenka/svg-sprite-loader/blob/master/runtime/browser-sprite.js\n// Much simplified, do make sure run this after document ready\nconst svgSprite = contents => `\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n    id=\"__CRD_SVG_SPRITE_NODE__\"\n    style=\"display:none;overflow:hidden;width:0;height:0\"\n  >\n    <defs>\n      ${contents}\n    </defs>\n  </svg>\n`\n/**\n * '<svg viewBox=\"0 0 1024 1024\"><path ...\"/></svg>' =>\n * ' viewBox=\"0 0 1024 1024\"><path ...\"/></'\n */\nconst handleSvgContent = (svgContent) => {\n  return svgContent.split('svg')[1]\n}\n\nconst renderSvgSprite = (props) => {\n  const { svgContent, type } = props\n  const customIconsInfo = svgContent\n    ? {\n      [`${type}`]: svgContent,\n    }\n    : {}\n  const mergeSvgInfo = { ...IconsInfo, ...customIconsInfo }\n  const symbols = Object.keys(mergeSvgInfo)\n    .map((iconName) => {\n      const getContent = handleSvgContent(mergeSvgInfo[iconName])\n      return `<symbol id=${iconName}${getContent}symbol>`\n    })\n    .join('')\n  return svgSprite(symbols)\n}\n\nconst loadSprite = (props) => {\n  const { type, svgContent } = props\n  if (!document) {\n    return\n  }\n  const existing = document.getElementById('__CRD_SVG_SPRITE_NODE__')\n  const mountNode = document.body\n\n  if (!existing) {\n    mountNode &&\n      typeof mountNode.insertAdjacentHTML === 'function' &&\n      mountNode.insertAdjacentHTML('afterbegin', renderSvgSprite(props))\n  } else if (svgContent) {\n    const defs = existing.children[0]\n    const svgChildren = defs.children\n    const svgChildrenIds = svgChildren ? [].slice.call(svgChildren).map(r => (r).id) : []\n    if (svgChildrenIds.indexOf(type) !== -1) return\n    defs.innerHTML += `<symbol id=${type}${handleSvgContent(svgContent)}symbol>`\n  }\n}\n\nexport default loadSprite\n"
  },
  {
    "path": "packages/crd-seed/component/Icon/style/index.less",
    "content": ".icon {\n  font-size: 24px;\n  vertical-align: middle;\n  fill: currentColor;\n  background-size: cover;\n  width: 1em;\n  height: 1em;\n}\n"
  },
  {
    "path": "packages/crd-seed/component/Menu/Menu.js",
    "content": "import { useState } from 'react'\nimport cx from 'classnames'\nimport MenuItem from './MenuItem'\nimport { SubMenu } from './SubMenu'\nimport { MenuProvider } from './context'\nimport styles from './style/index.less'\n\nconst Menu = ({\n  theme = 'light',\n  children,\n  selectedKey,\n  onSelect = () => {},\n  inlineCollapsed = false,\n  defaultOpenKeys = [],\n  menuStyle,\n  toggle,\n}) => {\n  /* 存储 hover 状态的 key 值, 在垂直模式中需要根据 hover 的 key 值高亮父节点 */\n  const [hoverKey, setHoverKey] = useState('')\n  const MenuContext = {\n    theme,\n    mode: 'inline',\n    inlineCollapsed,\n    defaultOpenKeys,\n    selectedKey,\n    onSelect,\n    hoverKey,\n    onHoverKey: setHoverKey,\n  }\n  const renderToggle = () => {\n    return (\n      <div\n        className={cx(styles.toggle, {\n          [`${styles['toggle-collapsed']}`]: inlineCollapsed,\n        })}\n        onClick={toggle}\n      >\n        <i\n          className={cx(styles['toggle-icon'], {\n            [`${styles['toggle-icon-close']}`]: inlineCollapsed,\n          })}\n        />\n      </div>\n    )\n  }\n  const renderMenu = () => {\n    return (\n      <ul\n        className={cx(\n          styles.menu,\n          styles[`menu-${theme}`],\n          styles['menu-inline'],\n          {\n            [styles['menu-inline-collapsed']]: inlineCollapsed,\n          },\n        )}\n        style={menuStyle}\n      >\n        {children}\n      </ul>\n    )\n  }\n\n  return (\n    <MenuProvider value={MenuContext}>\n      {renderToggle()}\n      {renderMenu()}\n    </MenuProvider>\n  )\n}\n\nMenu.Item = MenuItem\nMenu.SubMenu = SubMenu\n\nexport default Menu\n"
  },
  {
    "path": "packages/crd-seed/component/Menu/MenuItem.js",
    "content": "import { useEffect, useRef } from 'react'\nimport cx from 'classnames'\nimport { getMenuStyle } from './util'\nimport { useMenuContext } from './context'\nimport styles from './style/index.less'\n\nfunction MenuItem({\n  title = '',\n  icon,\n  keyValue = '',\n  level = 0,\n}) {\n  const {\n    theme,\n    selectedKey,\n    onSelect,\n    onHoverKey,\n    inlineCollapsed\n  } = useMenuContext()\n  const menuItemRef = useRef(null)\n  const menuItemselected = keyValue.indexOf(selectedKey) > -1\n  const menuUnFoldDelayTime = 300\n\n  useEffect(() => {\n    if (menuItemselected && (inlineCollapsed === false)) {\n      setTimeout(() => {\n        menuItemRef.current.scrollIntoView({\n          block: 'center',\n          behavior: 'smooth'\n        })\n      }, menuUnFoldDelayTime)\n    }\n  }, [keyValue, selectedKey, inlineCollapsed])\n\n  const handleOnClick = () => {\n    onSelect(keyValue)\n  }\n\n  const renderMenuItem = () => {\n    return (\n      <li\n        className={cx(styles['menu-item'], styles[`menu-${theme}`], {\n          [styles['menu-item-selected']]: menuItemselected,\n        })}\n        onMouseEnter={() => {\n          onHoverKey(keyValue)\n        }}\n        onMouseLeave={() => onHoverKey('')}\n        onClick={handleOnClick}\n        style={getMenuStyle(level, 'menuItem')}\n        ref={menuItemRef}\n      >\n        {icon ? <span className={cx(styles['menu-icon'])}>{icon}</span> : null}\n        <span className={cx(styles['menu-item-title'])}>{title}</span>\n      </li>\n    )\n  }\n\n  return renderMenuItem()\n}\n\nexport default MenuItem\n"
  },
  {
    "path": "packages/crd-seed/component/Menu/SubMenu.js",
    "content": "import { useState, useRef, Fragment, Children, cloneElement } from 'react'\nimport cx from 'classnames'\nimport { useEnhancedEffect } from 'crd-client-utils'\nimport Transition from './transition'\nimport { getMenuStyle } from './util'\nimport { useMenuContext } from './context'\nimport styles from './style/index.less'\n\nfunction useCurrent(\n  initialValue\n) {\n  const currentRef = useRef(initialValue)\n  const [state, setState] = useState(initialValue)\n  currentRef.current = state\n  const set = (value) => {\n    currentRef.current = value\n    setState(value)\n  }\n  const get = () => currentRef.current\n  return [get, set]\n}\n\nfunction SubMenu({\n  children,\n  title,\n  icon,\n  level = 0,\n  keyValue = '',\n  onTitleClick = () => {},\n}) {\n  const {\n    selectedKey,\n    mode,\n    hoverKey,\n    onHoverKey,\n    defaultOpenKeys = [],\n  } = useMenuContext()\n  const [menuOpen, setMenuOpen] = useState(defaultOpenKeys.indexOf(keyValue) !== -1)\n  const curSubmenu = useRef(null)\n  const popupSubMenu = useRef(null)\n\n  const [getParentMenuHover, setParentMenuHover] = useCurrent(false)\n\n  const gapDistance = 4\n\n  useEnhancedEffect(() => {\n    if (popupSubMenu.current && curSubmenu.current) {\n      popupSubMenu.current.style.left = `${curSubmenu.current.getBoundingClientRect().right +\n        gapDistance}px`\n      popupSubMenu.current.style.top = `${curSubmenu.current.getBoundingClientRect().top}px`\n    }\n  }, [getParentMenuHover()])\n\n  /**\n   * judege if is React Fragment.\n   */\n  function isReactFragment(variableToInspect) {\n    if (variableToInspect.type) {\n      return variableToInspect.type === Fragment\n    }\n    return variableToInspect === Fragment\n  }\n\n  /* 行内模式下, 渲染子节点 */\n  const renderChild = (child) => {\n    return (\n      // eslint-disable-next-line quotes\n      <>\n        {Children.map(child || children, (reactNode) => {\n          if (!reactNode || typeof reactNode !== 'object') {\n            return null\n          }\n          const childElement = reactNode\n          if (\n            isReactFragment(childElement) &&\n                  childElement.props.children\n          ) {\n            return renderChild(childElement.props.children)\n          }\n          return cloneElement(childElement, {\n            level: level + 1,\n            ...childElement.props,\n          })\n        // eslint-disable-next-line quotes\n        })}\n      </>\n    )\n  }\n\n  const handleParentMouseEnter = () => {\n    setParentMenuHover(true)\n    onHoverKey(keyValue)\n  }\n\n  const handleParentMouseLeave = () => {\n    onHoverKey('')\n  }\n\n  /* 处理 menu 开闭状态 */\n  const handleMenuStatus = () => {\n    onTitleClick(keyValue)\n    mode === 'inline' && setMenuOpen(!menuOpen)\n  }\n\n  /* 判断 subMenu 是否被选中, 当子节点被选中时, 父节点也会被高亮;\n    同时在 vertical 模式时, 当子节点被 hover 时, 父节点也会被高亮; */\n  const judgeSubmenuSelect = (reactChildren) => {\n    const result = Children.toArray(reactChildren).some((reactNode) => {\n      if (!reactNode || typeof reactNode !== 'object') {\n        return false\n      }\n\n      const childElement = reactNode\n      // eslint-disable-next-line no-shadow\n      const { keyValue } = childElement.props\n      const originKey = keyValue ? String(keyValue) : ''\n      if (childElement.type.name === 'MenuItem') {\n        return selectedKey.split('').indexOf(originKey) !== -1 || hoverKey === originKey\n      }\n      if (childElement.type.name === 'SubMenu') {\n        return judgeSubmenuSelect(childElement.props.children) || hoverKey === originKey\n      }\n      return false\n    })\n    return result\n  }\n\n  return (\n    <li\n      className={cx(styles.menu, styles.submenu, styles[`submenu-${mode}`], {\n        [styles['submenu-selected']]: judgeSubmenuSelect(children),\n      })}\n      onMouseEnter={() => onHoverKey(keyValue)}\n      ref={curSubmenu}\n    >\n      <div\n        className={cx(styles['submenu-title'])}\n        style={getMenuStyle(level, 'subMenu')}\n        onClick={handleMenuStatus}\n        onMouseEnter={handleParentMouseEnter}\n        onMouseLeave={handleParentMouseLeave}\n      >\n        <i\n          className={cx(styles['submenu-arrow'], {\n            [styles['submenu-arrow-open']]: mode === 'inline' && menuOpen,\n          })}\n        />\n        {icon ? <span className={cx(styles['menu-icon'])}>{icon}</span> : null}\n        <span className={cx(styles['submenu-title-field'])}>{title}</span>\n      </div>\n      {mode === 'inline' ? (\n        <Transition isShow={menuOpen}>\n          <ul className={cx(styles.menu, styles.submenu)}>{renderChild()}</ul>\n        </Transition>\n      ) : null}\n    </li>\n  )\n}\n\nexport { SubMenu }\n"
  },
  {
    "path": "packages/crd-seed/component/Menu/context.js",
    "content": "import { createContext, useContext } from 'react'\n\nconst MenuContext = createContext(undefined)\n\nexport const MenuProvider = ({ children, value }) => (\n  <MenuContext.Provider value={value}>{children}</MenuContext.Provider>\n)\n\nexport const useMenuContext = () => useContext(MenuContext)\n"
  },
  {
    "path": "packages/crd-seed/component/Menu/index.js",
    "content": "import Menu from './Menu'\n\nexport default Menu\n"
  },
  {
    "path": "packages/crd-seed/component/Menu/style/index.less",
    "content": "@import './theme.less';\n\n.menu {\n  box-sizing: border-box;\n  list-style: none;\n  margin: 0;\n  padding: 0;\n  color: @menu-color;\n  background: @menu-background;\n  user-select: none;\n  transition: background .2s ease-in-out, width .2s ease-in-out;\n  overflow: auto;\n  user-select: none;\n  font-weight: 600;\n\n  &-item {\n    // margin: 0 16px 0 15px;\n    white-space: nowrap;\n    cursor: pointer;\n    height: 40px;\n    line-height: 40px;\n    padding: 0 16px;\n    color: @menu-color;\n    position: relative;\n    cursor: pointer;\n    // overflow: hidden;\n    // white-space: nowrap;\n    // text-overflow: ellipsis;\n\n    &-selected {\n      position: relative;\n      background: @menu-background-selected;\n      color: @menu-color-selected;\n\n      a {\n        color: @menu-color-selected!important;\n      }\n    }\n\n    /* icon */\n    i {\n      margin-right: 10px;\n    }\n\n    a {\n      color: rgba(0, 0, 0, 0.8);\n      cursor: pointer;\n      display: inline-block;\n      text-decoration: none;\n\n      &::before {\n        top: 0;\n        left: 0;\n        right: 0;\n        bottom: 0;\n        content: '';\n        position: absolute;\n        background-color: transparent;\n      }\n    }\n\n    &-title {\n      vertical-align: middle;\n    }\n  }\n\n  &-item:hover {\n    color: @menu-color-hover;\n\n    & .menu-icon {\n      color: @menu-color-hover;\n    }\n  }\n\n  .submenu {\n    line-height: 40px;\n    cursor: pointer;\n    overflow: hidden;\n\n    &-title {\n      position: relative;\n      padding: 0 28px 0 0;\n      font-size: 14px;\n      cursor: pointer;\n      margin-left: 20px;\n      // overflow: hidden;\n      // white-space: nowrap;\n      // text-overflow: ellipsis;\n    }\n\n    &-title:hover {\n      color: @menu-color-hover;\n\n      .submenu-arrow {\n\n        &::before,\n        &::after {\n          background: @menu-color-hover;\n        }\n      }\n    }\n\n    &-arrow {\n      display: inline-block;\n      width: 10px;\n      flex-shrink: 0;\n      // margin: 0 3px 0 1px;\n      margin: 0 3px 0 -12px;\n      position: relative;\n      top: -5px;\n\n      &::before,\n      &::after {\n        content: '';\n        position: absolute;\n        width: 6px;\n        height: 1.5px;\n        background: @arrow-background;\n        transition: background .2s cubic-bezier(0.645, 0.045, 0.355, 1),\n          transform .2s cubic-bezier(0.645, 0.045, 0.355, 1),\n          top .2s cubic-bezier(0.645, 0.045, 0.355, 1),\n          -webkit-transform .2s cubic-bezier(0.645, 0.045, 0.355, 1);\n      }\n\n      &::before {\n        transform: rotate(45deg) translateY(-2px);\n      }\n\n      &::after {\n        transform: rotate(-45deg) translateY(2px);\n      }\n\n      &-open {\n        &::before {\n          transform: rotate(-45deg) translateX(2px);\n        }\n\n        &::after {\n          transform: rotate(45deg) translateX(-2px);\n        }\n      }\n    }\n\n    &-selected {\n      color: @menu-color-selected;\n    }\n  }\n\n  &-inline {\n    width: 100%;\n\n    .menu-item {\n      &-selected {\n        &::after {\n          content: '';\n          position: absolute;\n          width: 3px;\n          background: @menu-inline-selected;\n          top: 0;\n          bottom: 0;\n          right: 0;\n        }\n      }\n    }\n\n    .submenu {\n      &-arrow {\n        &::before {\n          transform: rotate(45deg) translateY(-2px);\n        }\n\n        &::after {\n          transform: rotate(-45deg) translateY(2px);\n        }\n\n        &-open {\n          &::before {\n            transform: rotate(-45deg) translateX(2px);\n          }\n\n          &::after {\n            transform: rotate(45deg) translateX(-2px);\n          }\n        }\n      }\n    }\n\n    /* fold */\n    &-collapsed {\n      width: 0px;\n\n      .menu-item {\n        padding: 0 24px !important;\n\n        &-title {\n          opacity: 0;\n        }\n      }\n\n      .submenu {\n        &-title {\n          padding: 0 24px !important;\n\n          &-field {\n            opacity: 0;\n          }\n\n          .submenu-arrow {\n            display: none;\n          }\n        }\n      }\n    }\n  }\n\n  &-icon {\n    margin-right: 4px;\n  }\n}\n\n/* submenu fold/unfold animation */\n.collapse-transition {\n  overflow: hidden;\n  transition: height .2s ease-in-out;\n}\n\n.toggle {\n  position: absolute;\n  width: 30px;\n  height: 30px;\n  left: 240px;\n  top: 200px;\n  transition: left .2s linear;\n  box-shadow: 2px 0 8px rgba(0, 0, 0, .15);\n  border-radius: 0 4px 4px 0;\n  cursor: pointer;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  background: #fff;\n\n  &-icon {\n    position: relative;\n    background: 0 0;\n    width: 12px;\n    height: 2px;\n    background: #333;\n    transition: background .2s cubic-bezier(.78, .14, .15, .86);\n\n    &::before,\n    &::after {\n      content: '';\n      display: block;\n      position: absolute;\n      background: #333;\n      width: 50%;\n      height: 2px;\n    }\n\n    &::before {\n      transform: translateY(-2px) rotate(-45deg);\n    }\n\n    &::after {\n      transform: translateY(2px) rotate(45deg);\n    }\n\n    &-close {\n      background: #333;\n\n      &::before,\n      &::after {\n        content: '';\n        display: block;\n        position: absolute;\n        background: #333;\n        width: 100%;\n        height: 2px;\n        transform: rotate(0deg);\n      }\n\n      &::before {\n        top: -4px;\n      }\n\n      &::after {\n        top: 4px;\n      }\n    }\n  }\n\n  &-collapsed {\n    left: 0px;\n  }\n}"
  },
  {
    "path": "packages/crd-seed/component/Menu/style/theme.less",
    "content": "/* light */\n@menu-color: rgba(0, 0, 0, 0.65);\n@menu-background: #fff;\n@menu-color-hover: #1890ff;\n@menu-color-selected: #1890ff;\n@menu-inline-selected: #1199ee;\n@menu-background-selected: #e6f7ff;\n@arrow-background: #333;"
  },
  {
    "path": "packages/crd-seed/component/Menu/transition.js",
    "content": "import { useEffect, useRef, useCallback } from 'react'\nimport styles from './style/index.less'\n\nconst ANIMATION_DURATION = 200\n\nexport default function Transition({\n  isShow,\n  children,\n}) {\n  const mounted = useRef(false)\n  const collapseRef = useRef(null)\n  const timer = useRef({})\n\n  // prepare\n  const beforeEnter = () => {\n    const el = collapseRef.current\n    el.style.height = '0px'\n  }\n\n  const afterEnter = useCallback(() => {\n    const el = collapseRef.current\n    el.style.display = 'block'\n    el.style.height = ''\n  }, [])\n\n  // start\n  const enter = useCallback(() => {\n    const el = collapseRef.current\n    el.style.display = 'block'\n    if (el.scrollHeight !== 0) {\n      el.style.height = `${el.scrollHeight}px`\n    }\n\n    timer.current.enterTimer = setTimeout(() => afterEnter(), ANIMATION_DURATION)\n  }, [afterEnter])\n\n  const beforeLeave = useCallback(() => {\n    const el = collapseRef.current\n\n    el.style.display = 'block'\n    if (el.scrollHeight !== 0) {\n      el.style.height = `${el.scrollHeight}px`\n    }\n  }, [])\n\n  const afterLeave = useCallback(() => {\n    const el = collapseRef.current\n\n    el.style.display = 'none'\n    el.style.height = ''\n  }, [])\n\n  const leave = useCallback(() => {\n    const el = collapseRef.current\n    if (el.scrollHeight !== 0) {\n      el.style.height = '0px'\n    }\n    timer.current.leaveTimer = setTimeout(() => afterLeave(), ANIMATION_DURATION)\n  }, [afterLeave])\n\n  const triggerChange = useCallback(\n    (isShow) => {\n      clearTimeout(timer.current.enterTimer)\n      clearTimeout(timer.current.leaveTimer)\n      if (isShow) {\n        beforeEnter()\n        enter()\n      } else {\n        beforeLeave()\n        leave()\n      }\n    },\n    [beforeLeave, enter, leave]\n  )\n\n  useEffect(() => {\n    if (!mounted.current) {\n      mounted.current = true\n      beforeEnter()\n      if (isShow) {\n        enter()\n      }\n    } else {\n      triggerChange(isShow)\n    }\n  }, [enter, isShow, triggerChange])\n\n  return (\n    <div className={styles['collapse-transition']} ref={collapseRef}>\n      {children}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/crd-seed/component/Menu/util.js",
    "content": "/* 获取 menu 样式\n  level: 层级\n*/\nconst getMenuStyle = (level, type) => {\n  const basicStyle = {\n    fontSize: level === 0 ? '14px' : '12px',\n  }\n  if (type === 'menuItem') {\n    return {\n      ...basicStyle,\n      paddingLeft: `${21 + (level * 16)}px`,\n    }\n  }\n  return {\n    ...basicStyle,\n    paddingLeft: `${level * 16}px`,\n  }\n}\n\nexport { getMenuStyle }\n"
  },
  {
    "path": "packages/crd-seed/component/NoMatch/index.js",
    "content": "import styles from './index.less'\n\nconst NoMatch = () => {\n  // eslint-disable-next-line no-undef\n  const { user, repo } = DOCSCONFIG || {}\n  return (\n    <table className={styles.noMatch}>\n      <tbody>\n        <tr>\n          <td>\n            <h1>404</h1>\n            <div>你似乎来到了没有知识存在的荒原...</div>\n            <section>在 github 访问<a href={`https://github.com/${user}/${repo}`}>该项目</a></section>\n          </td>\n        </tr>\n      </tbody>\n    </table>\n  )\n}\n\nexport default NoMatch\n"
  },
  {
    "path": "packages/crd-seed/component/NoMatch/index.less",
    "content": ".noMatch {\n  position: relative;\n  width: 100%;\n  height: 80%;\n  text-align: center;\n  border-spacing: 0;\n  border-collapse: collapse;\n  color: #a2a2a2;\n\n  h1 {\n    color: #717171;\n    font-size: 68px;\n    line-height: 54px;\n    font-weight: 500;\n  }\n}"
  },
  {
    "path": "packages/crd-seed/component/Search/README.md",
    "content": "### API\n\n|    props    | description |  type  | default  |\n| :---------: | :---------: | :----: | :------: |\n| placeholder | placeholder | string | 'Search' |\n|  className  |     css     | string |    --    |\n"
  },
  {
    "path": "packages/crd-seed/component/Search/index.js",
    "content": "import { useState, useEffect } from 'react'\nimport cx from 'classnames'\nimport Icon from '../Icon'\nimport styles from './index.less'\n\nconst Search = ({\n  placeholder = 'Search',\n  className,\n}) => {\n  const [value, setValue] = useState('')\n  // const [searchContent, setSearchContent] = useState([]);\n  // const showSearchContent = value.length > 0 && searchContent.length > 0;\n  useEffect(() => {\n    /* eslint-disable-next-line no-undef */\n    // if (SEARCHCONTENT) {\n    //   /* eslint-disable-next-line no-undef */\n    //   const filterSearch = SEARCHCONTENT.filter((r) => {\n    //     return r.title.includes(value) || r.content.includes(value);\n    //   });\n    //   setSearchContent(filterSearch);\n    // }\n  }, [value])\n  return (\n    <div className={cx(styles.search, className)}>\n      <Icon type=\"search\" size=\"14\" />\n      <input\n        placeholder={placeholder}\n        value={value}\n        onChange={(e) => {\n          setValue(e.target.value)\n        }}\n      />\n      {/* {showSearchContent ? (\n        <ul className={styles.panel}>\n          {searchContent.map((search) => {\n            return (\n              <li\n                className={styles.searchItem}\n                onClick={() => {\n                  location.hash = search.url;\n                }}\n                key={search.url}\n              >\n                <span className={styles.title}>{search.title}</span>\n                <span className={styles.content}>{search.content}</span>\n              </li>\n            );\n          })}\n        </ul>\n      ) : null} */}\n    </div>\n  )\n}\n\nexport default Search\n"
  },
  {
    "path": "packages/crd-seed/component/Search/index.less",
    "content": ".search {\n  position: relative;\n\n  input {\n    line-height: 1.5;\n    font-size: 14px;\n    color: #999;\n    outline: 0;\n    border-radius: 4px;\n    border: 0;\n    width: 200px;\n  }\n\n  .panel {\n    position: absolute;\n    width: 350px;\n    top: 50px;\n    left: 0;\n    background: rgba(255, 255, 255);\n    max-height: 400px;\n    box-shadow: rgba(101, 119, 134, 0.2) 0px 0px 15px, rgba(101, 119, 134, 0.15) 0px 0px 3px 1px;\n    overflow-y: auto;\n\n    li {\n      padding: 0 5px;\n      list-style: none;\n      border: 1px solid rgb(230, 236, 240);\n    }\n  }\n\n  .searchItem {\n    display: flex;\n  }\n\n  .title {\n    display: inline-block;\n    width: 90px;\n    overflow: hidden;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n  }\n\n  .content {\n    display: inline-block;\n    width: 245px;\n    overflow: hidden;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n  }\n}"
  },
  {
    "path": "packages/crd-seed/component/Tags/index.js",
    "content": "import { Link, useMatch } from 'react-router-dom'\nimport { ifProd } from 'crd-client-utils'\nimport { ifAddPrefix } from '../../utils'\nimport styles from './index.less'\n\n/**\n * name: the name of tag category.\n */\nconst Tags = () => {\n  const { user, repo } = DOCSCONFIG || {}\n  const path = ifAddPrefix ? `/${repo}/tags/:name` : '/tags/:name'\n  const routeMatch = useMatch(path) || {}\n  const { name } = routeMatch.params || {}\n\n  return (\n    <div className={styles.tags}>\n      <div className={styles['tags-title']}>{name || 'Tags'}</div>\n      <div className={styles['tags-content']}>\n        {\n          name\n            ? mapTagsWithArticle.find(({ tagName }) => tagName === name)?.mapArticle.map(({ path, title }) => {\n              return <Link\n                className={styles['tags-text']}\n                to={ifProd ? `/${repo}${path}` : `${path}`}\n                key={path}\n              >\n                {title}\n              </Link>\n            })\n            : mapTagsWithArticle.map(({ tagName }) => {\n              return <Link\n                className={styles['tags-text']}\n                to={ifProd ? `/${repo}/tags/${tagName}` : `/tags/${tagName}`}\n                key={tagName}\n              >\n                {tagName}\n              </Link>\n            })\n        }\n      </div>\n    </div>\n  )\n}\n\nexport default Tags\n"
  },
  {
    "path": "packages/crd-seed/component/Tags/index.less",
    "content": ".tags {\n  width: 100%;\n  padding: 0 20px;\n  height: 100%;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  flex-direction: column;\n\n  &-title {\n    font-size: 24px;\n    font-weight: 400;\n    text-align: center;\n  }\n\n  &-content {\n    width: 100%;\n    margin-top: 20px;\n  }\n\n  &-text {\n    color: #6f6f6f;\n    padding: 10px;\n    display: inline-flex;\n  }\n}"
  },
  {
    "path": "packages/crd-seed/index.js",
    "content": "import { Routes, Route, Navigate } from 'react-router-dom'\nimport BasicLayout from './layout'\nimport NoMatch from './component/NoMatch'\nimport './index.less'\n\n// run in the Web/Router.js\nconst ThemeSeed = (props) => {\n  return (\n    <Routes>\n      <Route path=\"/*\" element={<BasicLayout {...props} />} />\n      <Route path=\"/404\" element={<NoMatch />} />\n    </Routes>\n  )\n}\n\nexport default ThemeSeed\n"
  },
  {
    "path": "packages/crd-seed/index.less",
    "content": "body {\n  font-family: cursive, sans-serif;\n}\n\nbody,\nhtml {\n  position: relative;\n}\n\nbody,\nhtml,\nul,\nli {\n  margin: 0;\n  padding: 0;\n}\n\na {\n  color: #314659;\n  text-decoration: none;\n  transition: color .3s;\n\n  &:hover {\n    color: #1890ff;\n  }\n}\n\n*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\n:global {\n  #root {\n    height: 100%;\n    background: white;\n  }\n}"
  },
  {
    "path": "packages/crd-seed/language/index.js",
    "content": "const languageMap = {\n  en: {\n    create_tm: 'create',\n    modify_tm: 'modify',\n  },\n  'zh-cn': {\n    create_tm: '创建',\n    modify_tm: '修改',\n  },\n}\n\nexport default languageMap\n"
  },
  {
    "path": "packages/crd-seed/layout/index.js",
    "content": "import * as React from 'react'\nimport { Routes, Link, Route, Navigate, useLocation } from 'react-router-dom'\nimport cx from 'classnames'\nimport { ifDev, ifProd, ifPrerender } from 'crd-client-utils'\nconst Giscus = require('@giscus/react')\nimport Menu from '../component/Menu'\nimport Icon from '../component/Icon'\nimport Affix from '../component/Affix'\nimport Header from '../component/Header'\nimport Footer from '../component/Footer'\nimport Tags from '../component/Tags'\nimport languageMap from '../language'\nimport { isMobile, ifAddPrefix } from '../utils'\nimport { getOpenSubMenuKeys } from './utils'\nimport logo from '../crd.logo.svg'\nimport styles from './index.less'\nimport '../style/mobile.less'\n\nconst { useState, useEffect, useMemo } = React\nconst SubMenu = Menu.SubMenu\n\nfunction BasicLayout({\n  routeData,\n  menuSource\n}) {\n  const location = useLocation()\n  const { pathname } = location\n  const {\n    user,\n    repo,\n    branch = 'main',\n    language = 'en',\n    menuOpenKeys,\n    tags,\n    comment\n  } = DOCSCONFIG || {}\n\n  const [inlineCollapsed, setInlineCollapsed] = useState(true)\n  const [selectedKey, setSelectedKey] = useState('')\n  const curOpenKeys = getOpenSubMenuKeys({\n    pathname,\n    menuSource,\n    menuOpenKeys\n  })\n  const defaultPath = (routeData.find(data => data.path === '/README')\n    && routeData.find(data => data.path === '/README').mdconf\n    && routeData.find(data => data.path === '/README').mdconf.abbrlink) || 'README'\n\n  useEffect(() => {\n    if (ifPrerender) {\n      scrollToTop()\n      INJECT?.inject?.()\n    }\n  }, [])\n\n  useEffect(() => {\n    INJECT?.injectWithPathname?.(pathname)\n  }, [pathname])\n\n  useEffect(() => {\n    const { pathname } = location\n    let newPathName = pathname\n    // fix https://github.com/MuYunyun/create-react-doc/issues/195\n    if (newPathName.endsWith('/')) {\n      newPathName = newPathName.slice(0, newPathName.length - 1)\n    }\n    if (newPathName.startsWith(`/${repo}`)) {\n      newPathName = newPathName.slice(`/${repo}`.length, newPathName.length)\n    }\n    setSelectedKey(newPathName || defaultPath)\n  }, location.pathname)\n\n  const scrollToTop = () => {\n    document.body.scrollTop = 0\n    document.documentElement.scrollTop = 0\n    window.scrollTo(0, 0)\n  }\n  const renderSubMenuItem = (menus) => {\n    return (\n      <>\n        {menus.map((item, index) => {\n          const { mdconf, routePath } = item || {}\n          const { abbrlink } = mdconf || {}\n          const path = abbrlink ? `/${abbrlink}` : routePath\n          // item.path carrys .md here.\n          return item.children && item.children.length > 0 ? (\n            <SubMenu\n              key={index}\n              keyValue={item.path}\n              title={item.name}\n              icon={<Icon type=\"folder\" size={16} />}\n            >\n              {renderSubMenuItem(item.children)}\n            </SubMenu>\n          ) : (\n            <Menu.Item\n              key={index}\n              icon={<Icon type=\"file\" size={16} />}\n              keyValue={abbrlink ? `/${abbrlink}` : item.path}\n              title={\n                item &&\n                item.type === \"directory\" &&\n                item.props &&\n                item.props.isEmpty ? (\n                  <span>\n                    {(item.mdconf && item.mdconf.title) || item.name}\n                  </span>\n                ) : (\n                  <Link\n                    to={ifProd ? `/${repo}${path}` : `${path}`}\n                    replace={pathname.indexOf(path) > -1}\n                  >\n                    {item && item.mdconf && item.mdconf.title\n                      ? item.mdconf.title\n                      : item.title}\n                  </Link>\n                )\n              }\n            />\n          )\n        })}\n      </>\n    )\n  }\n  const renderMenu = (menus) => {\n    if (menus.length < 1) return null\n\n    return (\n      <Affix\n        offsetTop={0}\n        className={styles.affixPlaceholder}\n        wrapperClassName={styles.affixWrapper}\n        width={inlineCollapsed ? 0 : 240}\n      >\n        <Menu\n          inlineCollapsed={inlineCollapsed}\n          toggle={() => {\n            setInlineCollapsed(!inlineCollapsed)\n          }}\n          menuStyle={{\n            height: \"100vh\",\n            overflow: \"auto\",\n          }}\n          selectedKey={selectedKey}\n          onSelect={(keyValue) => {\n            setSelectedKey(keyValue)\n          }}\n          defaultOpenKeys={curOpenKeys}\n        >\n          {renderSubMenuItem(menus || [])}\n        </Menu>\n      </Affix>\n    )\n  }\n  /**\n   * This section is to show article's relevant information\n   * such as edit in github and so on.\n   */\n  const renderPageHeader = () => {\n    const curMenuSource = routeData.filter(r => {\n      if (r.props.type === 'directory') return false\n      return pathname.indexOf(r.mdconf.abbrlink) > -1 || decodeURIComponent(pathname).indexOf(r.path) > -1\n    })\n    const editPathName = curMenuSource[0] && curMenuSource[0].props.path\n    const isNotTagPage = location.pathname.indexOf('/tags') === -1\n    return (\n      <div className={cx(styles.pageHeader)}>\n        {user && repo && isNotTagPage ? (\n          <a\n            href={`https://github.com/${user}/${\n              repo\n            }/edit/${branch}${editPathName}`}\n            target=\"_blank\"\n          >\n            <Icon className={cx(styles.icon)} type=\"edit\" size={13} />\n            <span>Edit in GitHub</span>\n          </a>\n        ) : null}\n      </div>\n    )\n  }\n\n  /**\n   * This section is to render comment area.\n   * Every pathname should has its own comment module.\n   */\n  const renderComment = useMemo(() => {\n    return <Giscus\n      key={pathname}\n      id=\"comments\"\n      repo={`${user}/${repo}`}\n      category=\"General\"\n      mapping=\"pathname\"\n      strict=\"0\"\n      reactionsEnabled=\"1\"\n      emitMetadata=\"0\"\n      inputPosition=\"top\"\n      theme=\"preferred_color_scheme\"\n      lang=\"en\"\n      loading=\"lazy\"\n      crossorigin=\"anonymous\"\n      async\n      {...comment?.GiscusConfig}\n    />\n  }, [pathname])\n\n  /**\n   * This section is to show article's relevant information\n   * such as edit in created time、edited time and so on.\n   */\n  const renderPageFooter = () => {\n    // in local env, data.path is to be /READEME, however pathname may be /Users/mac/.../.crd-dist/READEME/index.html\n    const matchData = routeData.find((data) => pathname.indexOf(data.path) > -1)\n    const matchProps = matchData && matchData.props\n    return (\n      <div className={cx(styles.pageFooter)}>\n        {matchProps && matchProps.birthtime ? (\n          <span className={cx(styles.position)}>\n            <Icon className={cx(styles.icon)} type=\"create-time\" size={13} />\n            {languageMap[language].create_tm}:\n            <span>{matchProps.birthtime}</span>\n          </span>\n        ) : null}\n        {matchProps && matchProps.mtime ? (\n          <span className={cx(styles.position)}>\n            <Icon className={cx(styles.icon)} type=\"update-time\" size={13} />\n            {languageMap[language].modify_tm}:\n            <span>\n              {routeData.find((data) => pathname.indexOf(data.path) > -1).props.mtime}\n            </span>\n          </span>\n        ): null}\n      </div>\n    )\n  }\n  const isCurentChildren = () => {\n    const getRoute = routeData.filter((data) => pathname.indexOf(data.path) > -1)\n    const article = getRoute.length > 0 ? getRoute[0].article : null\n    const childs = menuSource.filter(\n      (data) =>\n        article === data.article && data.children && data.children.length > 1\n    )\n    return childs.length > 0\n  }\n  const isChild = isCurentChildren()\n  const renderMenuContainer = () => {\n    return (\n      <>\n        <nav\n          className={cx(styles.menuWrapper, {\n            [`${styles['menuWrapper-inlineCollapsed']}`]: inlineCollapsed,\n          })}\n        >\n          {renderMenu(menuSource)}\n        </nav>\n        <div\n          className={cx({\n            [`${styles.menuMask}`]: isMobile && !inlineCollapsed,\n          })}\n          onClick={(e) => {\n            e.stopPropagation()\n            setInlineCollapsed(true)\n          }}\n        />\n      </>\n    )\n  }\n\n  const renderContent = () => {\n    return (\n      <div\n        className={cx(`${styles.content}`, {\n          [`${styles[\"content-fullpage\"]}`]: inlineCollapsed || isMobile,\n        })}\n      >\n        <Routes>\n          {/* see https://reacttraining.com/react-router/web/api/Redirect/exact-bool */}\n          <Route\n            path={ifAddPrefix ? `/${repo}` : `/`}\n            element={<Navigate to={ifAddPrefix ? `/${repo}/${defaultPath}` : `/${defaultPath}`} replace />}\n          />\n          {routeData.map((item) => {\n            const { path, mdconf, component } = item\n            const { abbrlink } = mdconf\n            const enhancePath = abbrlink ? `/${abbrlink}` : path\n            const Comp = component\n            return (\n              <Route\n                key={enhancePath}\n                path={ifAddPrefix ? `/${repo}${enhancePath}` : enhancePath}\n                element={<Comp {...item} />}\n              />\n            )\n          })}\n          {\n            tags\n              ? <>\n                <Route\n                  key='/tags'\n                  path={ifAddPrefix ? `/${repo}/tags` : '/tags'}\n                  element={<Tags />}\n                />\n                <Route\n                  key='/tags/:name'\n                  path={ifAddPrefix ? `/${repo}/tags/:name` : '/tags/:name'}\n                  element={<Tags />}\n                />\n              </>\n              : null\n          }\n          {/* Todo: follow up how to use Redirect to back up the rest of route. */}\n          {/* <Redirect path='/' to={ifAddPrefix ? `/${repo}/404` : `/404`} /> */}\n        </Routes>\n        {comment?.GiscusConfig ? renderComment : null}\n        {renderPageFooter()}\n      </div>\n    )\n  }\n\n  return (\n    <div className={styles.wrapper}>\n      <Header logo={logo} />\n      <div\n        className={cx(styles.wrapperContent, {\n          [styles.wrapperMobile]: isMobile,\n        })}\n      >\n        {renderPageHeader()}\n        {renderMenuContainer()}\n        {renderContent()}\n        <Footer inlineCollapsed={inlineCollapsed} />\n      </div>\n    </div>\n  )\n}\n\nexport default BasicLayout\n"
  },
  {
    "path": "packages/crd-seed/layout/index.less",
    "content": "@import '../style/base.less';\n\n.wrapper {\n  &::after {\n    content: '';\n    display: block;\n    clear: both;\n  }\n}\n\n.wrapperContent {\n  padding: 40px 0 0 0;\n  margin: 0px auto 0;\n  position: relative;\n  min-height: 100vh;\n\n  .pageHeader,\n  .pageFooter {\n    position: absolute;\n    right: 40px;\n    font-size: 13px;\n    display: flex;\n    align-items: center;\n  }\n\n  .pageHeader {\n    top: 20px;\n  }\n\n  .pageFooter {\n    bottom: -23px;\n\n    .position {\n      margin-right: 6px;\n      display: flex;\n      align-items: center;\n    }\n  }\n\n  .icon {\n    margin-right: 3px;\n  }\n}\n\n.wrapperMobile {\n  // padding-top: 0;\n}\n\n.menuWrapper {\n  width: 240px;\n  float: left;\n  position: absolute;\n  font-size: 14px;\n  color: #6d6d6d;\n  transition: width .2s linear;\n  z-index: @menu-zIndex;\n\n  ul li {\n    list-style: none;\n  }\n\n  ul ul {\n    padding: 0 0 0 0;\n  }\n\n  li {\n    // padding: 0 0 0 21px;\n    line-height: 40px;\n  }\n\n  li li {\n    padding: 0 0 0 0;\n  }\n\n  // :global {\n  //   .active a {\n  //     color: #1890ff;\n  //   }\n  // }\n\n  &-inlineCollapsed {\n    width: 0;\n  }\n\n  .affixPlaceholder {\n    transition: width .2s linear;\n  }\n\n  .affixWrapper {\n    border-right: 1px solid rgb(233, 233, 233);\n    transition: width .2s linear;\n    width: 0px;\n  }\n}\n\n.menuMask {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  background: rgba(0, 0, 0, .3);\n  z-index: @menu-mask-zIndex;\n  transition: opacity .3s cubic-bezier(.78, .14, .15, .86)\n}\n\n.content {\n  margin-left: 240px;\n  min-height: 300px;\n  transition: margin-left .2s ease-in-out;\n  position: relative;\n\n  &-fullpage {\n    margin-left: 0px;\n  }\n}\n\n.contentNoMenu {\n  min-height: 400px;\n}\n\ngiscus-widget {\n  display: flex;\n  margin: auto;\n  max-width: 940px;\n}\n"
  },
  {
    "path": "packages/crd-seed/layout/utils.js",
    "content": "/**\n * get keys of open sub menu from pathname\n *  {\n *    pathname: pathname of location,\n *      when pathname is /9f41fc98, the result is ['/docs/主题'].\n *      when pathname is /测试/测试路由, the result is ['/docs/测试']\n *    menuOpenKeys: means extra show open keys in config.yml\n *  }\n */\nfunction getOpenSubMenuKeys({\n  pathname,\n  menuSource,\n  menuOpenKeys\n}) {\n  const result = []\n  getOpenSubMenuKeysForAbbrLink(\n    menuSource,\n    decodeURI(pathname),\n    result\n  )\n\n  /** default open menu from config.yml */\n  if (menuOpenKeys) {\n    result.push(...menuOpenKeys.split(','))\n  }\n\n  return result\n}\n\nfunction getOpenSubMenuKeysForAbbrLink(source, pathname, result) {\n  for (let i = 0; i < source.length; i++) {\n    const { type, path, mdconf } = source[i]\n    if (type === 'directory') {\n      result.push(path)\n      const ifFind = getOpenSubMenuKeysForAbbrLink(source[i].children, pathname, result)\n      if (ifFind) return true\n      result.pop()\n    } else {\n      if (\n        pathname.indexOf(mdconf.abbrlink) > -1           // used with abbrlink\n        || (pathname.indexOf(source[i].routePath) > -1)  // used not with abbrlink\n      ) {\n        return true\n      }\n    }\n  }\n}\n\nexport { getOpenSubMenuKeys }\n"
  },
  {
    "path": "packages/crd-seed/package.json",
    "content": "{\n  \"name\": \"crd-seed\",\n  \"version\": \"1.10.3\",\n  \"description\": \"Default Theme with Create React Doc\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"@giscus/react\": \"2.2.2\",\n    \"crd-client-utils\": \"^1.8.2\",\n    \"react-router-dom\": \"^6.3.0\",\n    \"react-switch\": \"^5.0.1\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\",\n    \"directory\": \"packages/theme-seed\"\n  },\n  \"keywords\": [],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"author\": \"muyunyun\",\n  \"license\": \"MIT\",\n  \"gitHead\": \"ffc5e4cbc94a7356da558c2dbf46e2f39bb8b199\"\n}\n"
  },
  {
    "path": "packages/crd-seed/style/base.less",
    "content": "// z-index\n@menu-zIndex: 99;\n@menu-mask-zIndex: 90;\n@header-zIndex: 100;"
  },
  {
    "path": "packages/crd-seed/style/mobile.less",
    "content": "// remove the blue area in the mobile\n:global {\n  div,\n  input,\n  textarea,\n  button,\n  select,\n  a,\n  li {\n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n  }\n}"
  },
  {
    "path": "packages/crd-seed/utils/index.js",
    "content": "import isClient from 'diana/lib/isClient'\nimport { ifProd, ifPrerender } from 'crd-client-utils'\n\n/** judge if is in mobile */\nconst isMobile = isClient() ? 'ontouchend' in window : false\n\n// decide to if add prefix for path, eg: '/' or '/${repo}'\nconst ifAddPrefix = ifProd && !ifPrerender\n\nexport { isMobile, ifAddPrefix }\n"
  },
  {
    "path": "packages/crd-templates/.npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n"
  },
  {
    "path": "packages/crd-templates/README.md",
    "content": "                                                     _.-\"\\\n                                                _.-\"      \\\n                                              ,-\"          \\\n                                              \\    create    \\\n                                              \\ \\    react    \\\n                                              \\ \\      doc     \\\n                                                \\ \\         _.-;\n                                                \\ \\    _.-\"   :\n                                                  \\ \\,-\"    _.-\"\n                                                  \\(   _.-\"\n                                                    `--\"\n\n# crd-templates\n\ncrd-templates 集成了 create-react-doc 中相关模板文件。\n"
  },
  {
    "path": "packages/crd-templates/default/.github/workflows/gh-pages.yml",
    "content": "name: github pages\non:\n  push:\n    branches:\n      - main\n\njobs:\n  deploy:\n    runs-on: ubuntu-18.04\n    steps:\n      - uses: actions/checkout@v2\n\n      - name: Setup Node\n        uses: actions/setup-node@v2.1.3\n        with:\n          node-version: '12.x'\n\n      - name: Get yarn cache\n        id: yarn-cache\n        run: echo \"::set-output name=dir::$(yarn cache dir)\"\n\n      - name: Cache dependencies\n        uses: actions/cache@v2\n        with:\n          path: ${{ steps.yarn-cache.outputs.dir }}\n          key: ${{ runner.os }}-website-${{ hashFiles('**/yarn.lock') }}\n          restore-keys: |\n            ${{ runner.os }}-website-\n\n      - run: yarn install --frozen-lockfile\n      - run: yarn build\n\n      - name: Deploy\n        uses: peaceiris/actions-gh-pages@v3\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          publish_dir: .crd-dist"
  },
  {
    "path": "packages/crd-templates/default/.npmrc",
    "content": "# .npmrc\nregistry=https://registry.npmjs.org/\n"
  },
  {
    "path": "packages/crd-templates/default/Introduction/hello_world.md",
    "content": "Write docs happily now.\n\nIf there is any problem, welcome give issue [there](https://github.com/MuYunyun/create-react-doc/issues).\n"
  },
  {
    "path": "packages/crd-templates/default/README.md",
    "content": "                                                     _.-\"\\\n                                                _.-\"      \\\n                                              ,-\"          \\\n                                              \\    create    \\\n                                              \\ \\    react    \\\n                                              \\ \\      doc     \\\n                                                \\ \\         _.-;\n                                                \\ \\    _.-\"   :\n                                                  \\ \\,-\"    _.-\"\n                                                  \\(   _.-\"\n                                                    `--\"\n\n[![npm version](https://img.shields.io/npm/v/create-react-doc)](https://badge.fury.io/js/create-react-doc)\n[![week download](https://img.shields.io/npm/dw/create-react-doc.svg)](https://www.npmjs.com/package/create-react-doc)\n![views](https://raw.githubusercontent.com/MuYunyun/create-react-doc/traffic/traffic-create-react-doc/views.svg)\n![views](https://raw.githubusercontent.com/MuYunyun/create-react-doc/traffic/traffic-create-react-doc/views_per_week.svg)\n![clones](https://raw.githubusercontent.com/MuYunyun/create-react-doc/traffic/traffic-create-react-doc/clones_per_week.svg)\n![LICENSE MIT](https://img.shields.io/npm/l/create-react-doc.svg)\n\n# Create React Doc\n\nCreate React Doc 是一个使用 React 的 markdown 文档站点生成工具。就像 [create-react-app](https://github.com/facebook/create-react-app) 一样，开发者可以使用 Create React Doc 来开发、部署 markdown 站点或者博客而无需关心站点环境配置信息。\n\n## 特性\n\n* 建站理念: 文件即站点 (Files as a site)。\n* 开箱即用: 一键生成可运行文档站点, 无需关心站点环境配置信息。\n* 自定义展示目录: 天然适合搭建 monorepo 文档、博客等站点。\n* 性能: 文档支持懒加载提升站点加载速度。\n* 工作流: 集成 Github action, 自动化打包、发布站点。\n\n> [快速上手](http://muyunyun.cn/create-react-doc/%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B)\n\n## 主题\n\n当前默认使用的主题是 [crd-seed](https://github.com/MuYunyun/create-react-doc/tree/main/packages/crd-seed)。\n\n使用该主题搭建的站点\n\n* [blog](http://muyunyun.cn/blog)\n  * ![](http://with.muyunyun.cn/90d3e357a31649b9466a828a92b6d88d.jpg)\n  * ![](http://with.muyunyun.cn/2e7440e4256debda2d73a4e6392c7146.jpg-300)\n* [diana](https://muyunyun.cn/diana/)\n\n> 如果你的产品从中受益，欢迎<a href=\"https://github.com/MuYunyun/create-react-doc/issues/new\" target=\"_blank\">留言补充</a>\n\n## 快速上手\n\n**create-react-doc** 非常容易上手。开发者不需要额外安装或配置 webpack 或者 Babel 等工具，它们被内置隐藏在脚手架中，因此开发者可以专心于文档的书写。\n\n如果你想在当前文件下建立站点文件 `doc`, 这里提供如下三种方式快速建站:\n\n### npx\n\n```bash\nnpx create-react-doc doc\n```\n\n### npm\n\n```bash\nnpm init create-react-doc doc\n```\n\n### yarn\n\n```bash\nyarn create react-doc doc\n```\n\n![](http://with.muyunyun.cn/0f0cf6e8cb68b18399eac2927f74b063.jpg)\n\n> 如果想把模板内容内容拉取到当前文件夹, 则可以将如上命令的 `doc` 替换为 `.`, 比如执行 `npx create-react-doc .`。\n\n接着执行 `cd doc && yarn && yarn start`, 可以在 `localhost: 3000` 预览站点, 如果站点文档发生改变, 站点将自动重新加载。\n\n<img src=\"http://with.muyunyun.cn/2bbd4d8da3165e1a09a88f5e6a114009.jpg\" width=\"900\" />\n\n## 高阶用法\n\n与 git 文件结构类似, 如果在展示的文件夹中有私有文件不方便展示在文档站点, 可以在 `.gitignore` 文件中设置过滤文件, 这样它们就不会展示在文档站点中了。eg: [.gitignore](https://github.com/MuYunyun/blog/blob/main/.gitignore)\n\n## 其它工具\n\n* [crd-leetcode-cli](https://github.com/MuYunyun/create-react-doc/tree/main/packages/leetcode-cli): 提供将 [leetcode](https://leetcode-cn.com/) 中已 AC 的题目转化为 markdown 表格的能力。"
  },
  {
    "path": "packages/crd-templates/default/_.gitignore",
    "content": "node_modules\npackage-lock.json\n.DS_Store\n.cache\n.crd-dist\n"
  },
  {
    "path": "packages/crd-templates/default/_config.yml",
    "content": "# details see http://muyunyun.cn/create-react-doc/默认主题\n\n# Site\n# title:\n\n# Menu dir\n## you can also set detailed dir, such as BasicSkill/css\nmenu: ['Introduction']\n## set init open menu keys\n# menuOpenKeys:\n\n# site theme\ntheme: crd-seed\n\n# Github\n## if you want to editing pages on github, you should config these arguments.\n# user:\n# repo:\n\n# Available values: en | zh-cn\nlanguage: en"
  },
  {
    "path": "packages/crd-templates/default/_package.json",
    "content": "{\n  \"name\": \"{{name}}\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Describe {{name}} here\",\n  \"scripts\": {\n    \"start\": \"react-doc start\",\n    \"build\": \"react-doc build\",\n    \"deploy\": \"react-doc deploy\"\n  },\n  \"keywords\": [\n    \"{{name}}\",\n    \"react-doc\",\n    \"react\"\n  ],\n  \"devDependencies\": {\n    \"create-react-doc\": \"{{crdVersion}}\"\n  },\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "packages/crd-templates/package.json",
    "content": "{\n  \"name\": \"crd-templates\",\n  \"version\": \"1.10.0\",\n  \"description\": \"Default Templates with Create React Doc\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\",\n    \"directory\": \"packages/templates\"\n  },\n  \"keywords\": [],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"author\": \"muyunyun\",\n  \"license\": \"MIT\",\n  \"gitHead\": \"\"\n}\n"
  },
  {
    "path": "packages/crd-templates/theme/default/Introduction/hello_world.md",
    "content": "Write docs happily now.\n\nIf there is any problem, welcome give issue [here](https://github.com/MuYunyun/create-react-doc/issues).\n"
  },
  {
    "path": "packages/crd-templates/theme/default/README.md",
    "content": "                                                     _.-\"\\\n                                                _.-\"      \\\n                                              ,-\"          \\\n                                              \\    create    \\\n                                              \\ \\    react    \\\n                                              \\ \\      doc     \\\n                                                \\ \\         _.-;\n                                                \\ \\    _.-\"   :\n                                                  \\ \\,-\"    _.-\"\n                                                  \\(   _.-\"\n                                                    `--\"\n\n### {{name}}\n\nThis is {{name}} theme for [create-react-doc](https://github.com/MuYunyun/create-react-doc)."
  },
  {
    "path": "packages/crd-templates/theme/default/_.gitignore",
    "content": "node_modules\npackage-lock.json\n.DS_Store\n.cache\n.crd-dist\nconfig.yml\nIntroduction"
  },
  {
    "path": "packages/crd-templates/theme/default/_.npmrc",
    "content": "# .npmrc\nregistry=https://registry.npmjs.org/\n"
  },
  {
    "path": "packages/crd-templates/theme/default/_config.yml",
    "content": "# details see http://muyunyun.cn/create-react-doc/默认主题\n\n# Site\n# title:\n\n# Menu dir\n## you can also set detailed dir, such as BasicSkill/css\nmenu: ['Introduction']\n## set init open menu keys\n# menuOpenKeys:\n\n# site theme\ndevTheme: ./index\n\n# Github\n## if you want to editing pages on github, you should config these arguments.\n# user:\n# repo:\n\n# Available values: en | zh-cn\nlanguage: en"
  },
  {
    "path": "packages/crd-templates/theme/default/_index.js",
    "content": "// The position of current index.js should be kept.\nimport { Routes, Route, Navigate } from 'react-router-dom'\nimport styles from './index.less'\n\nconst {{name}} = ({routeData, menuSource}) => {\n  return (\n    <div className={styles.center}>\n      <Routes>\n        <Route\n          path='/'\n          element={<Navigate to=\"/Introduction/hello_world\" replace />}\n        />\n        {routeData.map((item) => {\n          const Comp = item.component\n          return (\n            <Route\n              key={item.path}\n              path={item.path}\n              element={<Comp {...item} />}\n            />\n          )\n        })}\n      </Routes>\n    </div>\n  )\n}\n\nexport default {{name}}\n"
  },
  {
    "path": "packages/crd-templates/theme/default/_index.less",
    "content": ".center {\n  height: 100vh;\n  width: 100vw;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}"
  },
  {
    "path": "packages/crd-templates/theme/default/_package.json",
    "content": "{\n  \"name\": \"{{name}}\",\n  \"version\": \"0.1.0\",\n  \"description\": \"{{name}} theme for create-react-doc\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"start\": \"react-doc start\"\n  },\n  \"keywords\": [\n    \"{{name}}\",\n    \"react-doc\",\n    \"react\",\n    \"create-react-doc\",\n    \"theme\"\n  ],\n  \"devDependencies\": {\n    \"create-react-doc\": \"{{crdVersion}}\"\n  },\n  \"dependencies\": {\n    \"react-router-dom\": \"^6.3.0\"\n  },\n  \"author\": \"\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "packages/crd-theme/.npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n\n# https://github.com/sass/node-sass#binary-configuration-parameters\nsass_binary_site=https://npm.taobao.org/mirrors/node-sass/\n\n# https://github.com/Medium/phantomjs#deciding-where-to-get-phantomjs\n# phantomjs_cdnurl=http://cnpmjs.org/downloads\nphantomjs_cdnurl=https://npm.taobao.org/dist/phantomjs\n"
  },
  {
    "path": "packages/crd-theme/README.md",
    "content": "### crd-theme\n\n[create-react-doc](https://github.com/MuYunyun/create-react-doc) 的主题加载包。提供了懒加载, 文件内容解析等能力。"
  },
  {
    "path": "packages/crd-theme/component/Loading/index.js",
    "content": "import styles from './index.less'\n\nconst Loading = () => {\n  return (\n    <div className={styles.loading}>\n      正在加载中....\n    </div>\n  )\n}\n\nexport default Loading\n"
  },
  {
    "path": "packages/crd-theme/component/Loading/index.less",
    "content": ".loading {\n  text-align: center;\n  min-height: 450px;\n  padding: 30px 0;\n}\n"
  },
  {
    "path": "packages/crd-theme/index.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n<head>\n  <title><%= htmlWebpackPlugin.options.title %></title>\n  <meta charset=\"utf-8\">\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <!-- todo: move them into injectLogic, and https://search.google.com/search-console/welcome -->\n  <script async src=\"//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js\">\n  </script>\n  <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/katex@0.11.0/dist/katex.min.css\"\n    integrity=\"sha384-BdGj8xC2eZkQaxoQ8nSLefg4AV4/AwB3Fj+8SUSo7pnKP6Eoy18liIKTPn9oBYNG\" crossOrigin=\"anonymous\" />\n</head>\n\n<body>\n  <div id=\"root\"></div>\n</body>\n\n</html>\n\n"
  },
  {
    "path": "packages/crd-theme/index.js",
    "content": "import * as React from 'react'\nimport Markdown from './markdown'\nimport './index.less'\n\nexport default function (props) {\n  // routing load component\n  if (props.routeData && props.routeData.length > 0) {\n    props.routeData.map((item) => {\n      item.component = Markdown\n      return item\n    })\n  }\n\n  // support for custom theme.\n  const CustomTheme = require('__project_theme__').default\n\n  // use custom theme here.\n  return (\n    <CustomTheme {...props} />\n  )\n}\n"
  },
  {
    "path": "packages/crd-theme/index.less",
    "content": "body,\nhtml {\n  position: relative;\n}\n\nbody,\nhtml,\nul,\nli {\n  margin: 0;\n  padding: 0;\n}\n\na {\n  color: #314659;\n  text-decoration: none;\n  transition: color .3s;\n\n  &:hover {\n    color: #1890ff;\n  }\n}\n\n*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\n:global {\n  #root {\n    height: 100%;\n    background: white;\n  }\n}"
  },
  {
    "path": "packages/crd-theme/markdown/Link.js",
    "content": "import styles from './Link.less'\n\nexport default ({ title, href, children }) => {\n  let link = href.replace(/(\\/|\\/show\\/|\\/show)$/g, '')\n  if (\n    /^(http(?:|s):)\\/\\/(jsfiddle.net|runjs.cn|codepen.io|codesandbox.io)/.test(link) &&\n    !/^(https|http):\\/\\/(jsfiddle.net|runjs.cn|codepen.io|codesandbox.io)(?:|\\/)$/.test(link)\n  ) {\n    const regexRunjs = /(https|http):\\/\\/runjs.cn\\/code\\/(.*)/gi\n    const regexCodepen = /(https|http):\\/\\/codepen.io\\/(.*)\\/pen\\/(.*)/gi\n    const regexCodesandbox = /(https|http):\\/\\/codesandbox.io\\/(s|embed)\\/(.*)/gi\n    const runjs = regexRunjs.exec(link)\n    const codepen = regexCodepen.exec(link)\n    const codesandbox = regexCodesandbox.exec(link)\n    if (runjs && runjs.length > 2) {\n      link = `http://sandbox.runjs.cn/show/${runjs[2]}`\n    } else if (codepen && codepen.length === 4) {\n      link = `https://codepen.io/${codepen[2]}/embed/${codepen[3]}?height=400`\n    } else if (codesandbox && codesandbox.length === 4) {\n      link = `https://codesandbox.io/embed/${codesandbox[3]}`\n    } else {\n      link = `${link}/show/`\n    }\n    return (\n      <iframe frameBorder={0} allowFullScreen=\"allowfullscreen\" className={styles.frame} src={link} title={link} />\n    )\n  }\n  return (\n    <a href={href} title={title}>\n      {children}\n    </a>\n  )\n}\n"
  },
  {
    "path": "packages/crd-theme/markdown/Link.less",
    "content": ".frame {\n  width: 100%;\n  min-height: 400px;\n  border: 1px solid #e9e9e9;\n  border-radius: 3px;\n  background: #fff;\n}\n"
  },
  {
    "path": "packages/crd-theme/markdown/codeBlock.js",
    "content": "/** @jsxRuntime classic /\n/* @jsx jsx */\nimport Highlight, { defaultProps } from 'prism-react-renderer'\nimport nightOwlLight from 'prism-react-renderer/themes/nightOwlLight'\nimport { mdx } from '@mdx-js/react'\n// import {LiveProvider, LiveEditor, LiveError, LivePreview} from 'react-live'\n\nexport default ({ children, className, live, render }) => {\n  // const language = className.replace(/language-/, '')\n\n  // if (live) {\n  //   return (\n  //     <div style={{marginTop: '40px', backgroundColor: 'black'}}>\n  //       <LiveProvider\n  //         code={children.trim()}\n  //         transformCode={code => '/** @jsx mdx */' + code}\n  //         scope={{mdx}}\n  //       >\n  //         <LivePreview />\n  //         <LiveEditor />\n  //         <LiveError />\n  //       </LiveProvider>\n  //     </div>\n  //   )\n  // }\n\n  // if (render) {\n  //   return (\n  //     <div style={{ marginTop: '40px' }}>\n  //       <LiveProvider code={children}>\n  //         <LivePreview />\n  //       </LiveProvider>\n  //     </div>\n  //   )\n  // }\n\n  return (\n    <Highlight {...defaultProps} theme={nightOwlLight} code={children.trim()} language=\"javascript\">\n      {({ className, style, tokens, getLineProps, getTokenProps }) => (\n        <pre className={className} style={{ ...style, padding: '0 15px' }}>\n          {tokens.map((line, i) => (\n            <div key={i} {...getLineProps({ line, key: i })}>\n              {line.map((token, key) => (\n                <span key={key} {...getTokenProps({ token, key })} />\n              ))}\n            </div>\n          ))}\n        </pre>\n      )}\n    </Highlight>\n  )\n}\n"
  },
  {
    "path": "packages/crd-theme/markdown/index.js",
    "content": "import * as React from 'react'\nimport cx from 'classnames'\nimport { MDXProvider } from '@mdx-js/react'\nimport { Helmet } from 'react-helmet'\nimport CodeBlock from './codeBlock'\nimport Link from './Link'\nimport styles from './style/index.less'\n\nconst { useState, useEffect, useRef } = React\n\nconst components = {\n  code: CodeBlock,\n  link: Link,\n}\n\nfunction Markdown(markdownProps) {\n  const { props } = markdownProps\n  const { relative, name } = props\n\n  const getRmFirstSlashMarkdownName = () => {\n    const relativeMd = relative\n    if (!relativeMd) return null\n    return relative.slice(1, relative.length - 3)\n  }\n\n  const getInitMarkdownCP = () => {\n    const markdownName = getRmFirstSlashMarkdownName()\n    if (!markdownName) return\n    return () => require(`__project_root__/${markdownName}.md`).default\n  }\n\n  const [MarkdownCP, setMarkdownCP] = useState(getInitMarkdownCP())\n  const markdownWrapperRef = useRef(null)\n\n  const renderMarkdown = () => {\n    const markdownName = getRmFirstSlashMarkdownName()\n    if (!markdownName) return\n    // it must be writen with / & .md in dynamic import\n    import(`__project_root__/${markdownName}.md`).then((data) => {\n      // data.default is a function, so we should write () => data.default in setState here.\n      setMarkdownCP(() => (data.default || data))\n    })\n  }\n\n  useEffect(() => {\n    renderMarkdown()\n  }, [getRmFirstSlashMarkdownName()])\n\n  const getName = () => {\n    return name ? name.replace('.md', '') : ''\n  }\n\n  return (\n    <>\n      <Helmet>\n        <title>{getName()}</title>\n        <meta name={getName()} content={getName()} />\n      </Helmet>\n      {\n        MarkdownCP\n          ? <div\n            className={cx('markdown', styles.markdown, styles.markdownwrapper)}\n            ref={markdownWrapperRef}\n          >\n            <MDXProvider\n              components={components}\n            >\n              <MarkdownCP />\n            </MDXProvider>\n          </div>\n          : null\n      }\n    </>\n  )\n}\n\nexport default Markdown\n"
  },
  {
    "path": "packages/crd-theme/markdown/style/css.less",
    "content": ".language-css, .language-scss, .language-stylus, .language-less {\n  .keyword, .selector-tag, .subst {\n    color: #d73a49;\n    font-weight: normal;\n  }\n  .tag, .name, .attribute {\n    color: #005cc5;\n    font-weight: normal;\n  }\n  .selector-pseudo {\n    color: #6f42c1;\n  }\n  .selector-attr {\n    color: #008c41;\n  }\n  .selector-class {\n    color: #6f42c1;\n  }\n  .selector-id {\n    font-weight: normal;\n  }\n}"
  },
  {
    "path": "packages/crd-theme/markdown/style/default.less",
    "content": "code {\n  word-wrap: normal;\n}\n\npre {\n  max-height: 35em;\n  position: relative;\n  overflow: auto;\n  background-color: rgb(251, 251, 251);\n  border-radius: 3px;\n}\n\npre code {\n  background: none;\n  font-size: 1em;\n  overflow-wrap: normal;\n  white-space: inherit;\n}\n\nul,\nol {\n  padding-left: 2em;\n}\n\ndl {\n  padding: 0;\n\n  dt {\n    padding: 0;\n    margin-top: 16px;\n    font-size: 14px;\n    font-style: italic;\n    font-weight: 600;\n  }\n}\n\nli+li {\n  margin-top: 3px;\n}\n\na {\n  color: #0366d6;\n}\n\np {\n  margin-bottom: 16px;\n}\n\nblockquote {\n  margin: 0;\n  padding: 0 1em;\n  margin: 16px 0 16px 0;\n  color: #6a737d;\n  border-left: 0.25em solid #dfe2e5;\n\n  &>:first-child {\n    margin-top: 0;\n  }\n\n  &>:last-child {\n    margin-bottom: 0;\n  }\n}\n\nhr {\n  height: 0.25em;\n  padding: 0;\n  margin: 24px 0;\n  background-color: #e1e4e8;\n  border: 0;\n}\n\nh1 tt,\nh1 code,\nh2 tt,\nh2 code,\nh3 tt,\nh3 code,\nh4 tt,\nh4 code,\nh5 tt,\nh5 code,\nh6 tt,\nh6 code {\n  font-size: inherit\n}\n\nh1 {\n  padding-bottom: 0.3em;\n  font-size: 2em;\n  border-bottom: 1px solid #eaecef\n}\n\nh2 {\n  padding-bottom: 0.3em;\n  font-size: 1.5em;\n  border-bottom: 1px solid #eaecef\n}\n\nh3 {\n  font-size: 1.25em\n}\n\nh4 {\n  font-size: 1em\n}\n\nh5 {\n  font-size: 0.875em\n}\n\nh6 {\n  font-size: 0.85em;\n  color: #6a737d\n}\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n  width: 100%;\n\n  &+table {\n    margin-top: 16px;\n  }\n}\n\ntable th {\n  font-weight: 600;\n  white-space: nowrap;\n  color: #5c6b77;\n  background: rgba(0, 0, 0, .02);\n}\n\ntable th,\ntable td {\n  padding: 8px 13px;\n  border: 1px solid #dfe2e5;\n}\n\ntable tr {\n  background-color: #fff;\n  border-top: 1px solid #c6cbd1;\n}\n\ntable tr:nth-child(2n) {\n  background-color: #f6f8fa;\n}\n\ntable img {\n  background-color: transparent;\n}\n\nimg {\n  max-width: 100%;\n  box-sizing: content-box;\n  background-color: #fff;\n  vertical-align: middle;\n}\n\nimg[align=right] {\n  padding-left: 20px;\n}\n\nimg[align=left] {\n  padding-right: 20px;\n}\n\n.comment,\n.quote {\n  color: #998;\n}\n\n.keyword,\n.selector-tag,\n.subst {\n  color: #333;\n  font-weight: bold;\n}\n\n.number,\n.literal,\n.variable,\n.template-variable,\n.tag .attr {\n  color: #008080;\n}\n\n.string,\n.doctag {\n  color: #d14;\n}\n\n.title,\n.section,\n.selector-id {\n  color: #900;\n  font-weight: bold;\n}\n\n.subst {\n  font-weight: normal;\n}\n\n.type,\n.class .title {\n  color: #458;\n  font-weight: bold;\n}\n\n.tag,\n.name,\n.attribute {\n  color: #000098;\n  font-weight: normal;\n}\n\n.regexp,\n.link {\n  color: #009926;\n}\n\n.symbol,\n.bullet {\n  color: #990073;\n}\n\n.built_in,\n.builtin-name {\n  color: #0086b3;\n}\n\n.meta {\n  color: #999;\n  font-weight: bold;\n}\n\n.deletion {\n  background: #fdd;\n}\n\n.addition {\n  background: #dfd;\n}\n\n.emphasis {\n  font-style: italic;\n}\n\n.strong {\n  font-weight: bold;\n}"
  },
  {
    "path": "packages/crd-theme/markdown/style/diff.less",
    "content": ".language-diff {\n\n}"
  },
  {
    "path": "packages/crd-theme/markdown/style/index.less",
    "content": ".markdown {\n  padding: 0 40px 20px 40px;\n  margin: 0 auto;\n  font-size: 14px;\n  line-height: 1.5;\n  word-wrap: break-word;\n  color: #314659;\n  & >*:first-child {\n    margin-top: 0 !important\n  }\n\n  & >*:last-child {\n    margin-bottom: 0 !important\n  }\n  :global {\n    @import \"./default.less\";\n    @import \"./xml.less\";\n    @import \"./swift.less\";\n    @import \"./diff.less\";\n    @import \"./css.less\";\n    @import \"./javascript.less\";\n  }\n}\n\n.pageTitle {\n  font-size: 30px;\n  line-height: 38px;\n  color: #0d1a26;\n  font-weight: 500;\n  margin-bottom: 20px;\n  margin-top: 8px;\n  padding-left: 20px;\n}\n"
  },
  {
    "path": "packages/crd-theme/markdown/style/javascript.less",
    "content": ".language-jsx, .language-js,.language-javascript{\n  .keyword, .selector-tag {\n    color: #b111bf;\n    font-weight: 600;\n  }\n  .subst {\n    color: #0000ca;\n  }\n  .title, .section {\n    color: #4e00dc;\n    font-weight: normal;\n  }\n  .string, .doctag {\n    color: #d73a49;\n  }\n  .attr {\n    color: #0000ca;\n  }\n  .class .keyword{\n    color: #008cd4;\n  }\n  .function {\n    color: #0000ca;\n    .params {\n      color: #008cd4;\n    }\n  }\n}\n.language-json {\n  color: #444;\n  .attr {\n    color: #0000ca;\n  }\n}"
  },
  {
    "path": "packages/crd-theme/markdown/style/swift.less",
    "content": ".language-swift {\n  .keyword, .selector-tag, .subst {\n    color: #C600AA;\n    font-weight: normal;\n  }\n  .meta {\n    color: #C526D0;\n    font-weight: normal;\n  }\n  .type, .class .title {\n    color: #7C10B2;\n    font-weight: normal;\n  }\n}"
  },
  {
    "path": "packages/crd-theme/markdown/style/xml.less",
    "content": ".language-html, .xml{\n\n}\n"
  },
  {
    "path": "packages/crd-theme/package.json",
    "content": "{\n  \"name\": \"crd-theme\",\n  \"version\": \"1.10.3\",\n  \"description\": \"Default Theme with Create React Doc\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"classnames\": \"^2.2.6\",\n    \"diana\": \"^1.0.2\",\n    \"less\": \"^3.0.2\",\n    \"prism-react-renderer\": \"^1.2.1\",\n    \"react\": \"^18.0.0\",\n    \"react-dom\": \"^18.0.0\",\n    \"react-helmet\": \"^6.1.0\",\n    \"react-hot-loader\": \"^4.1.1\",\n    \"react-markdown\": \"^3.3.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\",\n    \"directory\": \"packages/theme\"\n  },\n  \"keywords\": [],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"author\": \"muyunyun\",\n  \"license\": \"MIT\",\n  \"gitHead\": \"ffc5e4cbc94a7356da558c2dbf46e2f39bb8b199\",\n  \"devDependencies\": {\n    \"@types/react\": \"^17.0.43\",\n    \"@types/react-dom\": \"^17.0.14\"\n  }\n}\n"
  },
  {
    "path": "packages/crd-utils/.npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n\n# https://github.com/sass/node-sass#binary-configuration-parameters\nsass_binary_site=https://npm.taobao.org/mirrors/node-sass/\n\n# https://github.com/Medium/phantomjs#deciding-where-to-get-phantomjs\n# phantomjs_cdnurl=http://cnpmjs.org/downloads\nphantomjs_cdnurl=https://npm.taobao.org/dist/phantomjs\n"
  },
  {
    "path": "packages/crd-utils/README.md",
    "content": "### crd-utils\n\n[create-react-doc](https://github.com/MuYunyun/create-react-doc) 的工具包。"
  },
  {
    "path": "packages/crd-utils/index.js",
    "content": "const fs = require('fs')\nconst yaml = require('js-yaml')\nconst { resolveApp, resolveTool } = require('./path')\n\n/* avoid reference loop, so use resolveApp('config.yml') instead of refrence from paths. */\nconst docsConfig = resolveApp('config.yml')\n\n/**\n * get docs config, see https://github.com/nodeca/js-yaml/blob/2d1fbed8f3a76ff93cccb9a8a418b4c4a482d3d9/lib/js-yaml/loader.js#L1590-L1592\n */\nconst getDocsConfig = () => {\n  if (!fs.existsSync(docsConfig)) {\n    return null\n  }\n  return yaml.safeLoad(fs.readFileSync(docsConfig))\n}\n\n/**\n * replace file content for Front-matter\n * path: file path\n * source?: source content\n * target: target content\n */\nconst replaceForFrontMatter = ({\n  path,\n  source,\n  target\n}) => {\n  fs.readFile(path, (err, data) => {\n    if (err) {\n      console.log(`❎ readFileContent error in ${path}`)\n      return\n    }\n    console.log(`✅ readFileContent success in ${path}`)\n    const replaceResult = source\n      ? data.toString().replace(source, target)\n      : `${target}\\n${data.toString()}`\n    fs.writeFile(path, replaceResult, (err) => {\n      if (err) {\n        console.log(`❎ writeFileContent error in ${path}`)\n        return\n      }\n    })\n    console.log(`✅ writeFileContent success in ${path}`)\n  })\n}\n\n// generate a random string, length of it is n.\nconst generateRandomId = (n) => {\n  const str = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']\n  let res = \"\"\n  for (let i = 0; i < n; i++) {\n    const id = Math.ceil(Math.random() * 35)\n    res += str[id]\n  }\n  return res\n}\n\nmodule.exports = {\n  resolveApp,\n  resolveTool,\n  getDocsConfig,\n  replaceForFrontMatter,\n  generateRandomId,\n  // common paths\n  docsGitIgnore: resolveApp('.gitignore'),\n  docsBase: resolveApp(''),\n  docsConfig,\n  docsReadme: resolveApp('README.md'),\n  docsBuildDist: resolveApp('.crd-dist'),\n  cacheDirPath: resolveApp('.cache'),\n  searchFilePath: resolveApp('.cache/search.js'),\n  templatePath: resolveApp('node_modules/crd-templates'),\n  defaultHTMLPath: resolveApp('node_modules/crd-theme/index.html'),\n}\n"
  },
  {
    "path": "packages/crd-utils/package.json",
    "content": "{\n  \"name\": \"crd-utils\",\n  \"version\": \"1.5.0\",\n  \"description\": \"Utils with create react doc\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"js-yaml\": \"^3.14.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\",\n    \"directory\": \"packages/utils\"\n  },\n  \"keywords\": [],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"author\": \"muyunyun\",\n  \"license\": \"MIT\",\n  \"gitHead\": \"ffc5e4cbc94a7356da558c2dbf46e2f39bb8b199\"\n}\n"
  },
  {
    "path": "packages/crd-utils/path.js",
    "content": "const path = require('path')\nconst fs = require('fs')\n\n// handle the problem of symbol in any platform\nconst appDirectory = fs.realpathSync(process.cwd())\n// Markdown dir\nconst resolveApp = relativePath => path.resolve(appDirectory, relativePath)\n\nmodule.exports = {\n  resolveApp,\n}\n"
  },
  {
    "path": "packages/create-react-doc/.npmignore",
    "content": ".cache\n.gitignore\n.editorconfig\n.create-react-doc-dist\nnode_modules\npackage-lock.json\ndist"
  },
  {
    "path": "packages/create-react-doc/.npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n\n# https://github.com/sass/node-sass#binary-configuration-parameters\nsass_binary_site=https://npm.taobao.org/mirrors/node-sass/\n\n# https://github.com/Medium/phantomjs#deciding-where-to-get-phantomjs\n# phantomjs_cdnurl=http://cnpmjs.org/downloads\nphantomjs_cdnurl=https://npm.taobao.org/dist/phantomjs\n"
  },
  {
    "path": "packages/create-react-doc/.yarnrc",
    "content": "# .yarnrc\n\nregistry \"https://registry.npmjs.org/\"\n\n# https://github.com/sass/node-sass#binary-configuration-parameters\nsass_binary_site \"https://npm.taobao.org/mirrors/node-sass/\"\n\n# https://github.com/Medium/phantomjs#deciding-where-to-get-phantomjs\n# phantomjs_cdnurl \"http://cnpmjs.org/downloads\"\nphantomjs_cdnurl \"https://npm.taobao.org/dist/phantomjs\"\n"
  },
  {
    "path": "packages/create-react-doc/README.md",
    "content": "                                                     _.-\"\\\n                                                _.-\"      \\\n                                              ,-\"          \\\n                                              \\    create    \\\n                                              \\ \\    react    \\\n                                              \\ \\      doc     \\\n                                                \\ \\         _.-;\n                                                \\ \\    _.-\"   :\n                                                  \\ \\,-\"    _.-\"\n                                                  \\(   _.-\"\n                                                    `--\"\n\n# react-doc\n\nreact-doc 是配合 [Create React Doc](https://github.com/MuYunyun/create-react-doc) 使用的脚手架，其内置如下命令。\n\n```bash\n$ react-doc doc         // 在当前文件夹下创建名为 doc 的文档站点\n$ react-doc start       // 启动项目\n$ react-doc build       // 项目打包\n$ react-doc deploy      // 手动发布项目\n$ react-doc theme       // 创建新主题包\n$ react-doc generate    // 用于自动生成 Front-matter 中相关字段信息\n```\n\n# 调试\n\n进入该目录, 执行 `yarn link`, 即可在全局使用 react-doc xxx 命令。\n"
  },
  {
    "path": "packages/create-react-doc/index.js",
    "content": "#!/usr/bin/env node\nconst fs = require('fs-extra')\nconst path = require('path')\nconst program = require('commander')\nconst {\n  initProject,\n  initTheme,\n  initCache,\n  Deploy,\n  Generate,\n  Servers,\n  Build,\n} = require('crd-scripts')\nconst { docsReadme, docsBuildDist, getDocsConfig } = require('crd-utils')\nconst input = require('@inquirer/input')\nconst pkg = require('./package.json')\n\nprogram\n  .version(pkg.version, '-v, --version')\n  .description('Markdown doc site generator for React.')\n  .option('start', 'Start the documents site in local env.')\n  .option('build', 'Build the documents generated.')\n  .option('deploy', 'Deploy site to gh-pages.')\n  .option('theme', 'Create a new theme')\n  .option('generate', 'Generate info in front-matter')\n  .option('-o, --output <path>', 'Writes the compiled file to the disk directory.', '.crd-dist')\n  .option('-p, --port [number]', 'The port.', 3000)\n  .option('--host [host]', 'The host.', '0.0.0.0')\n  .option('-b, --branch <branch>', 'Name of the branch you are pushing to.', 'gh-pages')\n  .on('--help', () => {\n    console.log('\\n  Examples:')\n    console.log()\n    console.log('    $ react-doc xxx')\n    console.log('    $ react-doc start')\n    console.log('    $ react-doc build')\n    console.log('    $ react-doc deploy')\n    console.log('    $ react-doc theme')\n    console.log('    $ react-doc generate')\n    console.log()\n  })\n  // the third value in process.argv is the value we want.\n  .parse(process.argv)\n\nconst { start, build, deploy, theme, generate } = program\nif (!start && !build && !deploy && !theme && !generate) return initProject(program)\n\nif (theme) {\n  return input({\n    message: \"What's the theme name?\",\n    validate: (inputThemeName) => {\n      if (inputThemeName.length === 0) return 'Please input correct theme name'\n      return true\n    },\n  }).then((themeName) => {\n    initTheme(themeName)\n  })\n}\n\n// create-react-doc tool root dir.\n// program.crdPath = path.join(__dirname, '../');\n// all markdown dir\nprogram.markdownPaths = []\n// dir for output\nprogram.output = path.join(process.cwd(), program.output)\nconst docsConfig = getDocsConfig()\n\n// assign all the markdown dir\nif (start || build || generate) {\n  fs.existsSync(docsReadme) &&\n    program.markdownPaths.push(docsReadme)\n\n  docsConfig &&\n    docsConfig.menu\n      .forEach(itemPath =>\n        program.markdownPaths.push(path.join(process.cwd(), itemPath))\n      )\n}\n\nif (build && fs.pathExistsSync(docsBuildDist)) {\n  // clean dir\n  fs.emptyDirSync(docsBuildDist)\n}\n\n// deploy code to special git repo and branch.\nif (deploy) {\n  return Deploy(program, docsConfig)\n}\n\n// no point markdown paths\nif (program.markdownPaths.length === 0) {\n  return console.log('❎ Please specify the markdownPaths props in config.yml.'.red)\n}\n\nlet isExists = true\n// judge if files exist.\nprogram.markdownPaths.forEach((item) => {\n  if (!fs.existsSync(item)) {\n    isExists = false\n  }\n})\n\nif (!isExists) {\n  console.log(`❎ Error: Directory ${item.yellow} does not exist`.red)\n  return\n}\n\nif (generate) {\n  return Generate(program)\n}\n\ninitCache(program, () => {\n  if (build) {\n    Build(program)\n  } else {\n    Servers(program)\n  }\n})\n"
  },
  {
    "path": "packages/create-react-doc/package.json",
    "content": "{\n  \"name\": \"create-react-doc\",\n  \"version\": \"1.10.3\",\n  \"description\": \"Fast static generated site. Just write markdown file.\",\n  \"homepage\": \"\",\n  \"bin\": {\n    \"react-doc\": \"./index.js\"\n  },\n  \"scripts\": {},\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\",\n    \"directory\": \"packages/create-react-doc\"\n  },\n  \"keywords\": [\n    \"react\",\n    \"create-react-doc\",\n    \"blog\",\n    \"markdown\"\n  ],\n  \"author\": \"muyunyun\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@inquirer/input\": \"^0.0.13-alpha.0\",\n    \"commander\": \"^2.12.2\",\n    \"crd-scripts\": \"^1.10.3\",\n    \"crd-templates\": \"^1.10.0\",\n    \"crd-theme\": \"^1.10.3\",\n    \"fs-extra\": \"^5.0.0\"\n  },\n  \"gitHead\": \"ffc5e4cbc94a7356da558c2dbf46e2f39bb8b199\"\n}\n"
  },
  {
    "path": "packages/leetcode-cli/.npmrc",
    "content": "# .npmrc\n\nregistry=https://registry.npmjs.org/\n\n# https://github.com/sass/node-sass#binary-configuration-parameters\nsass_binary_site=https://npm.taobao.org/mirrors/node-sass/\n\n# https://github.com/Medium/phantomjs#deciding-where-to-get-phantomjs\n# phantomjs_cdnurl=http://cnpmjs.org/downloads\nphantomjs_cdnurl=https://npm.taobao.org/dist/phantomjs\n"
  },
  {
    "path": "packages/leetcode-cli/README.md",
    "content": "### crd-leetcode-cli\n\ncrd-leetcode-cli 提供将 [leetcode](https://leetcode-cn.com/) 中已 AC 的题目转化为 markdown 表格的能力。\n\n### Install\n\n执行 `yarn add crd-leetcode-cli -g`, 国内用户可以执行 `cnpm install crd-leetcode-cli -g`\n\n### Usage\n\n```\nleetcode download       // 增量拉取 AC 题目(若无登录, 则会先执行登录逻辑)\nleetcode download -a    // 全量拉取 AC 题目\nleetcode login          // 登录\nleetcode logout         // 登出\n```\n\n> [接入项目示例](https://github.com/MuYunyun/blog/blob/main/package.json#L8-L9)\n\n### Render Markdown Table Customly\n\n插件提供了自定义渲染 markdown table 的能力。\n\n* 在项目根目录创建 [config.js](https://github.com/MuYunyun/blog/blob/main/config.js) 文件。\n* 在 config.js 内自定义生成 markdown 的 [transform_markdown_table](https://github.com/MuYunyun/blog/blob/main/config.js#L5-L22) 函数。\n\n```js\nconst transform_markdown_table = (dataArr) => {\n  const beforeDescription = `The markdown table is generated by [crd-leetcode-cli](https://github.com/MuYunyun/create-react-doc/tree/main/packages/leetcode-cli)`;\n  let result = beforeDescription + '\\n' +\n    '| # | Title | Explanation | Difficulty | Type |' +\n    '\\n' +\n    '|:---:|:---:|:---:|:---:|:---:|';\n\n  for (let i = 0; i < dataArr.length; i++) {\n    result += `\\n| ${dataArr[i].questionId} | [${dataArr[i].title\n      }](https://leetcode.com/problems/${dataArr[i].titleSlug\n      }/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/${dataArr[i].questionId\n      }.${dataArr[i].title.split(' ').join('_')}.md) | ${dataArr[i].difficulty\n      } | ${dataArr[i].topicTags} |`;\n  }\n  return result;\n};\n\nmodule.exports = { transform_markdown_table }\n```\n\n通过自定义 transform_markdown_table 函数, 便可得到如下 [markdown table](https://github.com/MuYunyun/blog/tree/main/LeetCode):\n\n![](http://with.muyunyun.cn/0dd6ef8677ddcbd904cff9a23722df18.jpg)\n\n### Technology Details\n\n* 使用 [puppeteer](https://github.com/puppeteer/puppeteer) 登录 leetcode 获取 cookie 信息。\n  * ![](http://with.muyunyun.cn/f9301658ff81e6d47dcaab3684cab1ce.jpg)\n* 获取 cookie 后, 使用 [graphql-request](https://github.com/prisma-labs/graphql-request) 调用 graphql 接口获取题目详情信息。\n* 自定义生成 [markdown table](https://github.com/MuYunyun/blog/tree/main/LeetCode)。\n\n### Q & A\n\n* 如何开发调试?\n\n进入[项目目录](https://github.com/MuYunyun/create-react-doc/tree/main/packages/leetcode-cli), 执行上述 Usage 中的 leetcode 命令即可。\n\n> 因为 [puppeteer](https://github.com/puppeteer/puppeteer/issues/6425) 已知问题, 暂时只支持 mac 系统使用, 后续更新。"
  },
  {
    "path": "packages/leetcode-cli/leetcode-table.md",
    "content": "| # | Title | Explanation | Difficulty | Type |\n|:---:|:---:|:---:|:---:|:---:|\n| 1 | [Two Sum](https://leetcode.com/problems/two-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/1.Two_Sum.md) | Easy | Array, Hash Table |\n| 2 | [Add Two Numbers](https://leetcode.com/problems/add-two-numbers/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/2.Add_Two_Numbers.md) | Medium | Recursion, Linked List, Math |\n| 3 | [Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/3.Longest_Substring_Without_Repeating_Characters.md) | Medium | Hash Table, Two Pointers, String, Sliding Window |\n| 4 | [Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/4.Median_of_Two_Sorted_Arrays.md) | Hard | Array, Binary Search, Divide and Conquer |\n| 7 | [Reverse Integer](https://leetcode.com/problems/reverse-integer/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/7.Reverse_Integer.md) | Easy | Math |\n| 9 | [Palindrome Number](https://leetcode.com/problems/palindrome-number/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/9.Palindrome_Number.md) | Easy | Math |\n| 11 | [Container With Most Water](https://leetcode.com/problems/container-with-most-water/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/11.Container_With_Most_Water.md) | Medium | Array, Two Pointers |\n| 13 | [Roman to Integer](https://leetcode.com/problems/roman-to-integer/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/13.Roman_to_Integer.md) | Easy | Math, String |\n| 14 | [Longest Common Prefix](https://leetcode.com/problems/longest-common-prefix/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/14.Longest_Common_Prefix.md) | Easy | String |\n| 15 | [3Sum](https://leetcode.com/problems/3sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/15.3Sum.md) | Medium | Array, Two Pointers |\n| 16 | [3Sum Closest](https://leetcode.com/problems/3sum-closest/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/16.3Sum_Closest.md) | Medium | Array, Two Pointers |\n| 17 | [Letter Combinations of a Phone Number](https://leetcode.com/problems/letter-combinations-of-a-phone-number/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/17.Letter_Combinations_of_a_Phone_Number.md) | Medium | Depth-first Search, Recursion, String, Backtracking |\n| 18 | [4Sum](https://leetcode.com/problems/4sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/18.4Sum.md) | Medium | Array, Hash Table, Two Pointers |\n| 19 | [Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/19.Remove_Nth_Node_From_End_of_List.md) | Medium | Linked List, Two Pointers |\n| 20 | [Valid Parentheses](https://leetcode.com/problems/valid-parentheses/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/20.Valid_Parentheses.md) | Easy | Stack, String |\n| 21 | [Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/21.Merge_Two_Sorted_Lists.md) | Easy | Recursion, Linked List |\n| 22 | [Generate Parentheses](https://leetcode.com/problems/generate-parentheses/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/22.Generate_Parentheses.md) | Medium | String, Backtracking |\n| 23 | [Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/23.Merge_k_Sorted_Lists.md) | Hard | Heap, Linked List, Divide and Conquer |\n| 24 | [Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/24.Swap_Nodes_in_Pairs.md) | Medium | Recursion, Linked List |\n| 25 | [Reverse Nodes in k-Group](https://leetcode.com/problems/reverse-nodes-in-k-group/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/25.Reverse_Nodes_in_k-Group.md) | Hard | Linked List |\n| 26 | [Remove Duplicates from Sorted Array](https://leetcode.com/problems/remove-duplicates-from-sorted-array/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/26.Remove_Duplicates_from_Sorted_Array.md) | Easy | Array, Two Pointers |\n| 27 | [Remove Element](https://leetcode.com/problems/remove-element/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/27.Remove_Element.md) | Easy | Array, Two Pointers |\n| 28 | [Implement strStr()](https://leetcode.com/problems/implement-strstr/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/28.Implement_strStr().md) | Easy | Two Pointers, String |\n| 33 | [Search in Rotated Sorted Array](https://leetcode.com/problems/search-in-rotated-sorted-array/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/33.Search_in_Rotated_Sorted_Array.md) | Medium | Array, Binary Search |\n| 35 | [Search Insert Position](https://leetcode.com/problems/search-insert-position/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/35.Search_Insert_Position.md) | Easy | Array, Binary Search |\n| 36 | [Valid Sudoku](https://leetcode.com/problems/valid-sudoku/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/36.Valid_Sudoku.md) | Medium | Hash Table |\n| 37 | [Sudoku Solver](https://leetcode.com/problems/sudoku-solver/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/37.Sudoku_Solver.md) | Hard | Hash Table, Backtracking |\n| 38 | [Count and Say](https://leetcode.com/problems/count-and-say/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/38.Count_and_Say.md) | Easy | String |\n| 39 | [Combination Sum](https://leetcode.com/problems/combination-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/39.Combination_Sum.md) | Medium | Array, Backtracking |\n| 40 | [Combination Sum II](https://leetcode.com/problems/combination-sum-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/40.Combination_Sum_II.md) | Medium | Array, Backtracking |\n| 46 | [Permutations](https://leetcode.com/problems/permutations/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/46.Permutations.md) | Medium | Backtracking |\n| 47 | [Permutations II](https://leetcode.com/problems/permutations-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/47.Permutations_II.md) | Medium | Backtracking |\n| 48 | [Rotate Image](https://leetcode.com/problems/rotate-image/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/48.Rotate_Image.md) | Medium | Array |\n| 49 | [Group Anagrams](https://leetcode.com/problems/group-anagrams/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/49.Group_Anagrams.md) | Medium | Hash Table, String |\n| 50 | [Pow(x, n)](https://leetcode.com/problems/powx-n/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/50.Pow(x,_n).md) | Medium | Math, Binary Search |\n| 51 | [N-Queens](https://leetcode.com/problems/n-queens/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/51.N-Queens.md) | Hard | Backtracking |\n| 52 | [N-Queens II](https://leetcode.com/problems/n-queens-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/52.N-Queens_II.md) | Hard | Backtracking |\n| 61 | [Rotate List](https://leetcode.com/problems/rotate-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/61.Rotate_List.md) | Medium | Linked List, Two Pointers |\n| 62 | [Unique Paths](https://leetcode.com/problems/unique-paths/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/62.Unique_Paths.md) | Medium | Array, Dynamic Programming |\n| 64 | [Minimum Path Sum](https://leetcode.com/problems/minimum-path-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/64.Minimum_Path_Sum.md) | Medium | Array, Dynamic Programming |\n| 66 | [Plus One](https://leetcode.com/problems/plus-one/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/66.Plus_One.md) | Easy | Array |\n| 67 | [Add Binary](https://leetcode.com/problems/add-binary/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/67.Add_Binary.md) | Easy | Math, String |\n| 69 | [Sqrt(x)](https://leetcode.com/problems/sqrtx/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/69.Sqrt(x).md) | Easy | Math, Binary Search |\n| 70 | [Climbing Stairs](https://leetcode.com/problems/climbing-stairs/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/70.Climbing_Stairs.md) | Easy | Dynamic Programming |\n| 71 | [Simplify Path](https://leetcode.com/problems/simplify-path/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/71.Simplify_Path.md) | Medium | Stack, String |\n| 75 | [Sort Colors](https://leetcode.com/problems/sort-colors/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/75.Sort_Colors.md) | Medium | Sort, Array, Two Pointers |\n| 77 | [Combinations](https://leetcode.com/problems/combinations/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/77.Combinations.md) | Medium | Backtracking |\n| 78 | [Subsets](https://leetcode.com/problems/subsets/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/78.Subsets.md) | Medium | Bit Manipulation, Array, Backtracking |\n| 79 | [Word Search](https://leetcode.com/problems/word-search/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/79.Word_Search.md) | Medium | Array, Backtracking |\n| 80 | [Remove Duplicates from Sorted Array II](https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/80.Remove_Duplicates_from_Sorted_Array_II.md) | Medium | Array, Two Pointers |\n| 82 | [Remove Duplicates from Sorted List II](https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/82.Remove_Duplicates_from_Sorted_List_II.md) | Medium | Linked List |\n| 83 | [Remove Duplicates from Sorted List](https://leetcode.com/problems/remove-duplicates-from-sorted-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/83.Remove_Duplicates_from_Sorted_List.md) | Easy | Linked List |\n| 86 | [Partition List](https://leetcode.com/problems/partition-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/86.Partition_List.md) | Medium | Linked List, Two Pointers |\n| 88 | [Merge Sorted Array](https://leetcode.com/problems/merge-sorted-array/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/88.Merge_Sorted_Array.md) | Easy | Array, Two Pointers |\n| 89 | [Gray Code](https://leetcode.com/problems/gray-code/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/89.Gray_Code.md) | Medium | Backtracking |\n| 90 | [Subsets II](https://leetcode.com/problems/subsets-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/90.Subsets_II.md) | Medium | Array, Backtracking |\n| 92 | [Reverse Linked List II](https://leetcode.com/problems/reverse-linked-list-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/92.Reverse_Linked_List_II.md) | Medium | Linked List |\n| 93 | [Restore IP Addresses](https://leetcode.com/problems/restore-ip-addresses/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/93.Restore_IP_Addresses.md) | Medium | String, Backtracking |\n| 94 | [Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/94.Binary_Tree_Inorder_Traversal.md) | Medium | Stack, Tree, Hash Table |\n| 98 | [Validate Binary Search Tree](https://leetcode.com/problems/validate-binary-search-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/98.Validate_Binary_Search_Tree.md) | Medium | Tree, Depth-first Search, Recursion |\n| 100 | [Same Tree](https://leetcode.com/problems/same-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/100.Same_Tree.md) | Easy | Tree, Depth-first Search |\n| 101 | [Symmetric Tree](https://leetcode.com/problems/symmetric-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/101.Symmetric_Tree.md) | Easy | Tree, Depth-first Search, Breadth-first Search |\n| 102 | [Binary Tree Level Order Traversal](https://leetcode.com/problems/binary-tree-level-order-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/102.Binary_Tree_Level_Order_Traversal.md) | Medium | Tree, Breadth-first Search |\n| 103 | [Binary Tree Zigzag Level Order Traversal](https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/103.Binary_Tree_Zigzag_Level_Order_Traversal.md) | Medium | Stack, Tree, Breadth-first Search |\n| 104 | [Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/104.Maximum_Depth_of_Binary_Tree.md) | Easy | Tree, Depth-first Search, Recursion |\n| 107 | [Binary Tree Level Order Traversal II](https://leetcode.com/problems/binary-tree-level-order-traversal-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/107.Binary_Tree_Level_Order_Traversal_II.md) | Medium | Tree, Breadth-first Search |\n| 108 | [Convert Sorted Array to Binary Search Tree](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/108.Convert_Sorted_Array_to_Binary_Search_Tree.md) | Easy | Tree, Depth-first Search |\n| 110 | [Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/110.Balanced_Binary_Tree.md) | Easy | Tree, Depth-first Search, Recursion |\n| 111 | [Minimum Depth of Binary Tree](https://leetcode.com/problems/minimum-depth-of-binary-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/111.Minimum_Depth_of_Binary_Tree.md) | Easy | Tree, Depth-first Search, Breadth-first Search |\n| 112 | [Path Sum](https://leetcode.com/problems/path-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/112.Path_Sum.md) | Easy | Tree, Depth-first Search |\n| 113 | [Path Sum II](https://leetcode.com/problems/path-sum-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/113.Path_Sum_II.md) | Medium | Tree, Depth-first Search |\n| 120 | [Triangle](https://leetcode.com/problems/triangle/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/120.Triangle.md) | Medium | Array, Dynamic Programming |\n| 121 | [Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/121.Best_Time_to_Buy_and_Sell_Stock.md) | Easy | Array, Dynamic Programming |\n| 125 | [Valid Palindrome](https://leetcode.com/problems/valid-palindrome/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/125.Valid_Palindrome.md) | Easy | Two Pointers, String |\n| 127 | [Word Ladder](https://leetcode.com/problems/word-ladder/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/127.Word_Ladder.md) | Hard | Breadth-first Search |\n| 129 | [Sum Root to Leaf Numbers](https://leetcode.com/problems/sum-root-to-leaf-numbers/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/129.Sum_Root_to_Leaf_Numbers.md) | Medium | Tree, Depth-first Search |\n| 130 | [Surrounded Regions](https://leetcode.com/problems/surrounded-regions/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/130.Surrounded_Regions.md) | Medium | Depth-first Search, Breadth-first Search, Union Find |\n| 131 | [Palindrome Partitioning](https://leetcode.com/problems/palindrome-partitioning/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/131.Palindrome_Partitioning.md) | Medium | Depth-first Search, Dynamic Programming, Backtracking |\n| 143 | [Reorder List](https://leetcode.com/problems/reorder-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/143.Reorder_List.md) | Medium | Linked List |\n| 144 | [Binary Tree Preorder Traversal](https://leetcode.com/problems/binary-tree-preorder-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/144.Binary_Tree_Preorder_Traversal.md) | Medium | Stack, Tree |\n| 145 | [Binary Tree Postorder Traversal](https://leetcode.com/problems/binary-tree-postorder-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/145.Binary_Tree_Postorder_Traversal.md) | Medium | Stack, Tree |\n| 147 | [Insertion Sort List](https://leetcode.com/problems/insertion-sort-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/147.Insertion_Sort_List.md) | Medium | Sort, Linked List |\n| 148 | [Sort List](https://leetcode.com/problems/sort-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/148.Sort_List.md) | Medium | Sort, Linked List |\n| 149 | [Max Points on a Line](https://leetcode.com/problems/max-points-on-a-line/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/149.Max_Points_on_a_Line.md) | Hard | Hash Table, Math |\n| 150 | [Evaluate Reverse Polish Notation](https://leetcode.com/problems/evaluate-reverse-polish-notation/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/150.Evaluate_Reverse_Polish_Notation.md) | Medium | Stack |\n| 151 | [Reverse Words in a String](https://leetcode.com/problems/reverse-words-in-a-string/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/151.Reverse_Words_in_a_String.md) | Medium | String |\n| 167 | [Two Sum II - Input array is sorted](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/167.Two_Sum_II_-_Input_array_is_sorted.md) | Easy | Array, Two Pointers, Binary Search |\n| 199 | [Binary Tree Right Side View](https://leetcode.com/problems/binary-tree-right-side-view/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/199.Binary_Tree_Right_Side_View.md) | Medium | Tree, Depth-first Search, Breadth-first Search, Recursion, Queue |\n| 200 | [Number of Islands](https://leetcode.com/problems/number-of-islands/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/200.Number_of_Islands.md) | Medium | Depth-first Search, Breadth-first Search, Union Find |\n| 202 | [Happy Number](https://leetcode.com/problems/happy-number/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/202.Happy_Number.md) | Easy | Hash Table, Math |\n| 203 | [Remove Linked List Elements](https://leetcode.com/problems/remove-linked-list-elements/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/203.Remove_Linked_List_Elements.md) | Easy | Linked List |\n| 205 | [Isomorphic Strings](https://leetcode.com/problems/isomorphic-strings/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/205.Isomorphic_Strings.md) | Easy | Hash Table |\n| 206 | [Reverse Linked List](https://leetcode.com/problems/reverse-linked-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/206.Reverse_Linked_List.md) | Easy | Linked List |\n| 209 | [Minimum Size Subarray Sum](https://leetcode.com/problems/minimum-size-subarray-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/209.Minimum_Size_Subarray_Sum.md) | Medium | Array, Two Pointers, Binary Search |\n| 215 | [Kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/215.Kth_Largest_Element_in_an_Array.md) | Medium | Heap, Divide and Conquer |\n| 216 | [Combination Sum III](https://leetcode.com/problems/combination-sum-iii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/216.Combination_Sum_III.md) | Medium | Array, Backtracking |\n| 217 | [Contains Duplicate](https://leetcode.com/problems/contains-duplicate/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/217.Contains_Duplicate.md) | Easy | Array, Hash Table |\n| 219 | [Contains Duplicate II](https://leetcode.com/problems/contains-duplicate-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/219.Contains_Duplicate_II.md) | Easy | Array, Hash Table |\n| 220 | [Contains Duplicate III](https://leetcode.com/problems/contains-duplicate-iii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/220.Contains_Duplicate_III.md) | Medium | Sort, Ordered Map |\n| 222 | [Count Complete Tree Nodes](https://leetcode.com/problems/count-complete-tree-nodes/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/222.Count_Complete_Tree_Nodes.md) | Medium | Tree, Binary Search |\n| 226 | [Invert Binary Tree](https://leetcode.com/problems/invert-binary-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/226.Invert_Binary_Tree.md) | Easy | Tree |\n| 230 | [Kth Smallest Element in a BST](https://leetcode.com/problems/kth-smallest-element-in-a-bst/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/230.Kth_Smallest_Element_in_a_BST.md) | Medium | Tree, Binary Search |\n| 234 | [Palindrome Linked List](https://leetcode.com/problems/palindrome-linked-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/234.Palindrome_Linked_List.md) | Easy | Linked List, Two Pointers |\n| 235 | [Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/235.Lowest_Common_Ancestor_of_a_Binary_Search_Tree.md) | Easy | Tree |\n| 236 | [Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/236.Lowest_Common_Ancestor_of_a_Binary_Tree.md) | Medium | Tree |\n| 237 | [Delete Node in a Linked List](https://leetcode.com/problems/delete-node-in-a-linked-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/237.Delete_Node_in_a_Linked_List.md) | Easy | Linked List |\n| 242 | [Valid Anagram](https://leetcode.com/problems/valid-anagram/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/242.Valid_Anagram.md) | Easy | Sort, Hash Table |\n| 257 | [Binary Tree Paths](https://leetcode.com/problems/binary-tree-paths/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/257.Binary_Tree_Paths.md) | Easy | Tree, Depth-first Search |\n| 279 | [Perfect Squares](https://leetcode.com/problems/perfect-squares/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/279.Perfect_Squares.md) | Medium | Breadth-first Search, Math, Dynamic Programming |\n| 283 | [Move Zeroes](https://leetcode.com/problems/move-zeroes/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/283.Move_Zeroes.md) | Easy | Array, Two Pointers |\n| 290 | [Word Pattern](https://leetcode.com/problems/word-pattern/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/290.Word_Pattern.md) | Easy | Hash Table |\n| 328 | [Odd Even Linked List](https://leetcode.com/problems/odd-even-linked-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/328.Odd_Even_Linked_List.md) | Medium | Linked List |\n| 341 | [Flatten Nested List Iterator](https://leetcode.com/problems/flatten-nested-list-iterator/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/341.Flatten_Nested_List_Iterator.md) | Medium | Stack, Design |\n| 344 | [Reverse String](https://leetcode.com/problems/reverse-string/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/344.Reverse_String.md) | Easy | Two Pointers, String |\n| 347 | [Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/347.Top_K_Frequent_Elements.md) | Medium | Heap, Hash Table |\n| 349 | [Intersection of Two Arrays](https://leetcode.com/problems/intersection-of-two-arrays/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/349.Intersection_of_Two_Arrays.md) | Easy | Sort, Hash Table, Two Pointers, Binary Search |\n| 350 | [Intersection of Two Arrays II](https://leetcode.com/problems/intersection-of-two-arrays-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/350.Intersection_of_Two_Arrays_II.md) | Easy | Sort, Hash Table, Two Pointers, Binary Search |\n| 401 | [Binary Watch](https://leetcode.com/problems/binary-watch/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/401.Binary_Watch.md) | Easy | Bit Manipulation, Backtracking |\n| 404 | [Sum of Left Leaves](https://leetcode.com/problems/sum-of-left-leaves/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/404.Sum_of_Left_Leaves.md) | Easy | Tree |\n| 417 | [Pacific Atlantic Water Flow](https://leetcode.com/problems/pacific-atlantic-water-flow/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/417.Pacific_Atlantic_Water_Flow.md) | Medium | Depth-first Search, Breadth-first Search |\n| 437 | [Path Sum III](https://leetcode.com/problems/path-sum-iii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/437.Path_Sum_III.md) | Medium | Tree |\n| 438 | [Find All Anagrams in a String](https://leetcode.com/problems/find-all-anagrams-in-a-string/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/438.Find_All_Anagrams_in_a_String.md) | Medium | Hash Table |\n| 445 | [Add Two Numbers II](https://leetcode.com/problems/add-two-numbers-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/445.Add_Two_Numbers_II.md) | Medium | Linked List |\n| 447 | [Number of Boomerangs](https://leetcode.com/problems/number-of-boomerangs/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/447.Number_of_Boomerangs.md) | Medium | Hash Table, Math |\n| 450 | [Delete Node in a BST](https://leetcode.com/problems/delete-node-in-a-bst/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/450.Delete_Node_in_a_BST.md) | Medium | Tree |\n| 451 | [Sort Characters By Frequency](https://leetcode.com/problems/sort-characters-by-frequency/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/451.Sort_Characters_By_Frequency.md) | Medium | Heap, Hash Table |\n| 454 | [4Sum II](https://leetcode.com/problems/4sum-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/454.4Sum_II.md) | Medium | Hash Table, Binary Search |\n| 567 | [Permutation in String](https://leetcode.com/problems/permutation-in-string/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/567.Permutation_in_String.md) | Medium | Two Pointers, Sliding Window |"
  },
  {
    "path": "packages/leetcode-cli/package.json",
    "content": "{\n  \"name\": \"crd-leetcode-cli\",\n  \"version\": \"1.10.2\",\n  \"description\": \"Generate leetcode table autoly\",\n  \"bin\": {\n    \"leetcode\": \"./src/cli.js\"\n  },\n  \"dependencies\": {\n    \"axios\": \"^0.21.1\",\n    \"commander\": \"^2.20.0\",\n    \"crd-utils\": \"^1.5.0\",\n    \"enquirer\": \"^2.3.0\",\n    \"graphql-request\": \"^1.8.2\",\n    \"inquirer\": \"^7.3.3\",\n    \"node-fs-extra\": \"^0.8.2\",\n    \"ora\": \"^3.4.0\",\n    \"puppeteer\": \"^5.3.0\",\n    \"puppeteer-extra\": \"^3.1.15\",\n    \"puppeteer-extra-plugin-stealth\": \"^2.6.1\",\n    \"request\": \"^2.88.0\",\n    \"shelljs\": \"^0.8.3\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MuYunyun/create-react-doc\",\n    \"directory\": \"packages/leetcode\"\n  },\n  \"keywords\": [],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"author\": \"muyunyun\",\n  \"license\": \"MIT\",\n  \"gitHead\": \"d8a8dff5697da28623361231bd9b3d848d050e8b\"\n}\n"
  },
  {
    "path": "packages/leetcode-cli/problems.json",
    "content": "[\n  {\n    \"title\": \"Two Sum\",\n    \"titleSlug\": \"two-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"1\",\n    \"topicTags\": \"Array, Hash Table\"\n  },\n  {\n    \"title\": \"Add Two Numbers\",\n    \"titleSlug\": \"add-two-numbers\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"2\",\n    \"topicTags\": \"Recursion, Linked List, Math\"\n  },\n  {\n    \"title\": \"Longest Substring Without Repeating Characters\",\n    \"titleSlug\": \"longest-substring-without-repeating-characters\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"3\",\n    \"topicTags\": \"Hash Table, Two Pointers, String, Sliding Window\"\n  },\n  {\n    \"title\": \"Median of Two Sorted Arrays\",\n    \"titleSlug\": \"median-of-two-sorted-arrays\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"4\",\n    \"topicTags\": \"Array, Binary Search, Divide and Conquer\"\n  },\n  {\n    \"title\": \"Reverse Integer\",\n    \"titleSlug\": \"reverse-integer\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"7\",\n    \"topicTags\": \"Math\"\n  },\n  {\n    \"title\": \"Palindrome Number\",\n    \"titleSlug\": \"palindrome-number\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"9\",\n    \"topicTags\": \"Math\"\n  },\n  {\n    \"title\": \"Container With Most Water\",\n    \"titleSlug\": \"container-with-most-water\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"11\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Roman to Integer\",\n    \"titleSlug\": \"roman-to-integer\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"13\",\n    \"topicTags\": \"Math, String\"\n  },\n  {\n    \"title\": \"Longest Common Prefix\",\n    \"titleSlug\": \"longest-common-prefix\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"14\",\n    \"topicTags\": \"String\"\n  },\n  {\n    \"title\": \"3Sum\",\n    \"titleSlug\": \"3sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"15\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"3Sum Closest\",\n    \"titleSlug\": \"3sum-closest\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"16\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Letter Combinations of a Phone Number\",\n    \"titleSlug\": \"letter-combinations-of-a-phone-number\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"17\",\n    \"topicTags\": \"Depth-first Search, Recursion, String, Backtracking\"\n  },\n  {\n    \"title\": \"4Sum\",\n    \"titleSlug\": \"4sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"18\",\n    \"topicTags\": \"Array, Hash Table, Two Pointers\"\n  },\n  {\n    \"title\": \"Remove Nth Node From End of List\",\n    \"titleSlug\": \"remove-nth-node-from-end-of-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"19\",\n    \"topicTags\": \"Linked List, Two Pointers\"\n  },\n  {\n    \"title\": \"Valid Parentheses\",\n    \"titleSlug\": \"valid-parentheses\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"20\",\n    \"topicTags\": \"Stack, String\"\n  },\n  {\n    \"title\": \"Merge Two Sorted Lists\",\n    \"titleSlug\": \"merge-two-sorted-lists\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"21\",\n    \"topicTags\": \"Recursion, Linked List\"\n  },\n  {\n    \"title\": \"Generate Parentheses\",\n    \"titleSlug\": \"generate-parentheses\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"22\",\n    \"topicTags\": \"String, Backtracking\"\n  },\n  {\n    \"title\": \"Merge k Sorted Lists\",\n    \"titleSlug\": \"merge-k-sorted-lists\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"23\",\n    \"topicTags\": \"Heap, Linked List, Divide and Conquer\"\n  },\n  {\n    \"title\": \"Swap Nodes in Pairs\",\n    \"titleSlug\": \"swap-nodes-in-pairs\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"24\",\n    \"topicTags\": \"Recursion, Linked List\"\n  },\n  {\n    \"title\": \"Reverse Nodes in k-Group\",\n    \"titleSlug\": \"reverse-nodes-in-k-group\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"25\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Remove Duplicates from Sorted Array\",\n    \"titleSlug\": \"remove-duplicates-from-sorted-array\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"26\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Remove Element\",\n    \"titleSlug\": \"remove-element\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"27\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Implement strStr()\",\n    \"titleSlug\": \"implement-strstr\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"28\",\n    \"topicTags\": \"Two Pointers, String\"\n  },\n  {\n    \"title\": \"Search in Rotated Sorted Array\",\n    \"titleSlug\": \"search-in-rotated-sorted-array\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"33\",\n    \"topicTags\": \"Array, Binary Search\"\n  },\n  {\n    \"title\": \"Search Insert Position\",\n    \"titleSlug\": \"search-insert-position\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"35\",\n    \"topicTags\": \"Array, Binary Search\"\n  },\n  {\n    \"title\": \"Valid Sudoku\",\n    \"titleSlug\": \"valid-sudoku\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"36\",\n    \"topicTags\": \"Hash Table\"\n  },\n  {\n    \"title\": \"Sudoku Solver\",\n    \"titleSlug\": \"sudoku-solver\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"37\",\n    \"topicTags\": \"Hash Table, Backtracking\"\n  },\n  {\n    \"title\": \"Count and Say\",\n    \"titleSlug\": \"count-and-say\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"38\",\n    \"topicTags\": \"String\"\n  },\n  {\n    \"title\": \"Combination Sum\",\n    \"titleSlug\": \"combination-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"39\",\n    \"topicTags\": \"Array, Backtracking\"\n  },\n  {\n    \"title\": \"Combination Sum II\",\n    \"titleSlug\": \"combination-sum-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"40\",\n    \"topicTags\": \"Array, Backtracking\"\n  },\n  {\n    \"title\": \"Permutations\",\n    \"titleSlug\": \"permutations\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"46\",\n    \"topicTags\": \"Backtracking\"\n  },\n  {\n    \"title\": \"Permutations II\",\n    \"titleSlug\": \"permutations-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"47\",\n    \"topicTags\": \"Backtracking\"\n  },\n  {\n    \"title\": \"Rotate Image\",\n    \"titleSlug\": \"rotate-image\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"48\",\n    \"topicTags\": \"Array\"\n  },\n  {\n    \"title\": \"Group Anagrams\",\n    \"titleSlug\": \"group-anagrams\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"49\",\n    \"topicTags\": \"Hash Table, String\"\n  },\n  {\n    \"title\": \"Pow(x, n)\",\n    \"titleSlug\": \"powx-n\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"50\",\n    \"topicTags\": \"Math, Binary Search\"\n  },\n  {\n    \"title\": \"N-Queens\",\n    \"titleSlug\": \"n-queens\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"51\",\n    \"topicTags\": \"Backtracking\"\n  },\n  {\n    \"title\": \"N-Queens II\",\n    \"titleSlug\": \"n-queens-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"52\",\n    \"topicTags\": \"Backtracking\"\n  },\n  {\n    \"title\": \"Rotate List\",\n    \"titleSlug\": \"rotate-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"61\",\n    \"topicTags\": \"Linked List, Two Pointers\"\n  },\n  {\n    \"title\": \"Unique Paths\",\n    \"titleSlug\": \"unique-paths\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"62\",\n    \"topicTags\": \"Array, Dynamic Programming\"\n  },\n  {\n    \"title\": \"Minimum Path Sum\",\n    \"titleSlug\": \"minimum-path-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"64\",\n    \"topicTags\": \"Array, Dynamic Programming\"\n  },\n  {\n    \"title\": \"Plus One\",\n    \"titleSlug\": \"plus-one\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"66\",\n    \"topicTags\": \"Array\"\n  },\n  {\n    \"title\": \"Add Binary\",\n    \"titleSlug\": \"add-binary\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"67\",\n    \"topicTags\": \"Math, String\"\n  },\n  {\n    \"title\": \"Sqrt(x)\",\n    \"titleSlug\": \"sqrtx\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"69\",\n    \"topicTags\": \"Math, Binary Search\"\n  },\n  {\n    \"title\": \"Climbing Stairs\",\n    \"titleSlug\": \"climbing-stairs\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"70\",\n    \"topicTags\": \"Dynamic Programming\"\n  },\n  {\n    \"title\": \"Simplify Path\",\n    \"titleSlug\": \"simplify-path\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"71\",\n    \"topicTags\": \"Stack, String\"\n  },\n  {\n    \"title\": \"Sort Colors\",\n    \"titleSlug\": \"sort-colors\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"75\",\n    \"topicTags\": \"Sort, Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Combinations\",\n    \"titleSlug\": \"combinations\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"77\",\n    \"topicTags\": \"Backtracking\"\n  },\n  {\n    \"title\": \"Subsets\",\n    \"titleSlug\": \"subsets\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"78\",\n    \"topicTags\": \"Bit Manipulation, Array, Backtracking\"\n  },\n  {\n    \"title\": \"Word Search\",\n    \"titleSlug\": \"word-search\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"79\",\n    \"topicTags\": \"Array, Backtracking\"\n  },\n  {\n    \"title\": \"Remove Duplicates from Sorted Array II\",\n    \"titleSlug\": \"remove-duplicates-from-sorted-array-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"80\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Remove Duplicates from Sorted List II\",\n    \"titleSlug\": \"remove-duplicates-from-sorted-list-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"82\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Remove Duplicates from Sorted List\",\n    \"titleSlug\": \"remove-duplicates-from-sorted-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"83\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Partition List\",\n    \"titleSlug\": \"partition-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"86\",\n    \"topicTags\": \"Linked List, Two Pointers\"\n  },\n  {\n    \"title\": \"Merge Sorted Array\",\n    \"titleSlug\": \"merge-sorted-array\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"88\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Gray Code\",\n    \"titleSlug\": \"gray-code\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"89\",\n    \"topicTags\": \"Backtracking\"\n  },\n  {\n    \"title\": \"Subsets II\",\n    \"titleSlug\": \"subsets-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"90\",\n    \"topicTags\": \"Array, Backtracking\"\n  },\n  {\n    \"title\": \"Reverse Linked List II\",\n    \"titleSlug\": \"reverse-linked-list-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"92\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Restore IP Addresses\",\n    \"titleSlug\": \"restore-ip-addresses\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"93\",\n    \"topicTags\": \"String, Backtracking\"\n  },\n  {\n    \"title\": \"Binary Tree Inorder Traversal\",\n    \"titleSlug\": \"binary-tree-inorder-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"94\",\n    \"topicTags\": \"Stack, Tree, Hash Table\"\n  },\n  {\n    \"title\": \"Validate Binary Search Tree\",\n    \"titleSlug\": \"validate-binary-search-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"98\",\n    \"topicTags\": \"Tree, Depth-first Search, Recursion\"\n  },\n  {\n    \"title\": \"Same Tree\",\n    \"titleSlug\": \"same-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"100\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Symmetric Tree\",\n    \"titleSlug\": \"symmetric-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"101\",\n    \"topicTags\": \"Tree, Depth-first Search, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Binary Tree Level Order Traversal\",\n    \"titleSlug\": \"binary-tree-level-order-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"102\",\n    \"topicTags\": \"Tree, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Binary Tree Zigzag Level Order Traversal\",\n    \"titleSlug\": \"binary-tree-zigzag-level-order-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"103\",\n    \"topicTags\": \"Stack, Tree, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Maximum Depth of Binary Tree\",\n    \"titleSlug\": \"maximum-depth-of-binary-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"104\",\n    \"topicTags\": \"Tree, Depth-first Search, Recursion\"\n  },\n  {\n    \"title\": \"Binary Tree Level Order Traversal II\",\n    \"titleSlug\": \"binary-tree-level-order-traversal-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"107\",\n    \"topicTags\": \"Tree, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Convert Sorted Array to Binary Search Tree\",\n    \"titleSlug\": \"convert-sorted-array-to-binary-search-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"108\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Balanced Binary Tree\",\n    \"titleSlug\": \"balanced-binary-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"110\",\n    \"topicTags\": \"Tree, Depth-first Search, Recursion\"\n  },\n  {\n    \"title\": \"Minimum Depth of Binary Tree\",\n    \"titleSlug\": \"minimum-depth-of-binary-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"111\",\n    \"topicTags\": \"Tree, Depth-first Search, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Path Sum\",\n    \"titleSlug\": \"path-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"112\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Path Sum II\",\n    \"titleSlug\": \"path-sum-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"113\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Triangle\",\n    \"titleSlug\": \"triangle\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"120\",\n    \"topicTags\": \"Array, Dynamic Programming\"\n  },\n  {\n    \"title\": \"Best Time to Buy and Sell Stock\",\n    \"titleSlug\": \"best-time-to-buy-and-sell-stock\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"121\",\n    \"topicTags\": \"Array, Dynamic Programming\"\n  },\n  {\n    \"title\": \"Valid Palindrome\",\n    \"titleSlug\": \"valid-palindrome\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"125\",\n    \"topicTags\": \"Two Pointers, String\"\n  },\n  {\n    \"title\": \"Word Ladder\",\n    \"titleSlug\": \"word-ladder\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"127\",\n    \"topicTags\": \"Breadth-first Search\"\n  },\n  {\n    \"title\": \"Sum Root to Leaf Numbers\",\n    \"titleSlug\": \"sum-root-to-leaf-numbers\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"129\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Surrounded Regions\",\n    \"titleSlug\": \"surrounded-regions\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"130\",\n    \"topicTags\": \"Depth-first Search, Breadth-first Search, Union Find\"\n  },\n  {\n    \"title\": \"Palindrome Partitioning\",\n    \"titleSlug\": \"palindrome-partitioning\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"131\",\n    \"topicTags\": \"Depth-first Search, Dynamic Programming, Backtracking\"\n  },\n  {\n    \"title\": \"Reorder List\",\n    \"titleSlug\": \"reorder-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"143\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Binary Tree Preorder Traversal\",\n    \"titleSlug\": \"binary-tree-preorder-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"144\",\n    \"topicTags\": \"Stack, Tree\"\n  },\n  {\n    \"title\": \"Binary Tree Postorder Traversal\",\n    \"titleSlug\": \"binary-tree-postorder-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"145\",\n    \"topicTags\": \"Stack, Tree\"\n  },\n  {\n    \"title\": \"Insertion Sort List\",\n    \"titleSlug\": \"insertion-sort-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"147\",\n    \"topicTags\": \"Sort, Linked List\"\n  },\n  {\n    \"title\": \"Sort List\",\n    \"titleSlug\": \"sort-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"148\",\n    \"topicTags\": \"Sort, Linked List\"\n  },\n  {\n    \"title\": \"Max Points on a Line\",\n    \"titleSlug\": \"max-points-on-a-line\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"149\",\n    \"topicTags\": \"Hash Table, Math\"\n  },\n  {\n    \"title\": \"Evaluate Reverse Polish Notation\",\n    \"titleSlug\": \"evaluate-reverse-polish-notation\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"150\",\n    \"topicTags\": \"Stack\"\n  },\n  {\n    \"title\": \"Reverse Words in a String\",\n    \"titleSlug\": \"reverse-words-in-a-string\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"151\",\n    \"topicTags\": \"String\"\n  },\n  {\n    \"title\": \"Two Sum II - Input array is sorted\",\n    \"titleSlug\": \"two-sum-ii-input-array-is-sorted\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"167\",\n    \"topicTags\": \"Array, Two Pointers, Binary Search\"\n  },\n  {\n    \"title\": \"Binary Tree Right Side View\",\n    \"titleSlug\": \"binary-tree-right-side-view\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"199\",\n    \"topicTags\": \"Tree, Depth-first Search, Breadth-first Search, Recursion, Queue\"\n  },\n  {\n    \"title\": \"Number of Islands\",\n    \"titleSlug\": \"number-of-islands\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"200\",\n    \"topicTags\": \"Depth-first Search, Breadth-first Search, Union Find\"\n  },\n  {\n    \"title\": \"Happy Number\",\n    \"titleSlug\": \"happy-number\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"202\",\n    \"topicTags\": \"Hash Table, Math\"\n  },\n  {\n    \"title\": \"Remove Linked List Elements\",\n    \"titleSlug\": \"remove-linked-list-elements\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"203\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Isomorphic Strings\",\n    \"titleSlug\": \"isomorphic-strings\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"205\",\n    \"topicTags\": \"Hash Table\"\n  },\n  {\n    \"title\": \"Reverse Linked List\",\n    \"titleSlug\": \"reverse-linked-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"206\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Minimum Size Subarray Sum\",\n    \"titleSlug\": \"minimum-size-subarray-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"209\",\n    \"topicTags\": \"Array, Two Pointers, Binary Search\"\n  },\n  {\n    \"title\": \"Kth Largest Element in an Array\",\n    \"titleSlug\": \"kth-largest-element-in-an-array\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"215\",\n    \"topicTags\": \"Heap, Divide and Conquer\"\n  },\n  {\n    \"title\": \"Combination Sum III\",\n    \"titleSlug\": \"combination-sum-iii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"216\",\n    \"topicTags\": \"Array, Backtracking\"\n  },\n  {\n    \"title\": \"Contains Duplicate\",\n    \"titleSlug\": \"contains-duplicate\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"217\",\n    \"topicTags\": \"Array, Hash Table\"\n  },\n  {\n    \"title\": \"Contains Duplicate II\",\n    \"titleSlug\": \"contains-duplicate-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"219\",\n    \"topicTags\": \"Array, Hash Table\"\n  },\n  {\n    \"title\": \"Contains Duplicate III\",\n    \"titleSlug\": \"contains-duplicate-iii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"220\",\n    \"topicTags\": \"Sort, Ordered Map\"\n  },\n  {\n    \"title\": \"Count Complete Tree Nodes\",\n    \"titleSlug\": \"count-complete-tree-nodes\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"222\",\n    \"topicTags\": \"Tree, Binary Search\"\n  },\n  {\n    \"title\": \"Invert Binary Tree\",\n    \"titleSlug\": \"invert-binary-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"226\",\n    \"topicTags\": \"Tree\"\n  },\n  {\n    \"title\": \"Kth Smallest Element in a BST\",\n    \"titleSlug\": \"kth-smallest-element-in-a-bst\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"230\",\n    \"topicTags\": \"Tree, Binary Search\"\n  },\n  {\n    \"title\": \"Palindrome Linked List\",\n    \"titleSlug\": \"palindrome-linked-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"234\",\n    \"topicTags\": \"Linked List, Two Pointers\"\n  },\n  {\n    \"title\": \"Lowest Common Ancestor of a Binary Search Tree\",\n    \"titleSlug\": \"lowest-common-ancestor-of-a-binary-search-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"235\",\n    \"topicTags\": \"Tree\"\n  },\n  {\n    \"title\": \"Lowest Common Ancestor of a Binary Tree\",\n    \"titleSlug\": \"lowest-common-ancestor-of-a-binary-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"236\",\n    \"topicTags\": \"Tree\"\n  },\n  {\n    \"title\": \"Delete Node in a Linked List\",\n    \"titleSlug\": \"delete-node-in-a-linked-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"237\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Valid Anagram\",\n    \"titleSlug\": \"valid-anagram\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"242\",\n    \"topicTags\": \"Sort, Hash Table\"\n  },\n  {\n    \"title\": \"Binary Tree Paths\",\n    \"titleSlug\": \"binary-tree-paths\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"257\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Perfect Squares\",\n    \"titleSlug\": \"perfect-squares\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"279\",\n    \"topicTags\": \"Breadth-first Search, Math, Dynamic Programming\"\n  },\n  {\n    \"title\": \"Move Zeroes\",\n    \"titleSlug\": \"move-zeroes\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"283\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Word Pattern\",\n    \"titleSlug\": \"word-pattern\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"290\",\n    \"topicTags\": \"Hash Table\"\n  },\n  {\n    \"title\": \"Odd Even Linked List\",\n    \"titleSlug\": \"odd-even-linked-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"328\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Flatten Nested List Iterator\",\n    \"titleSlug\": \"flatten-nested-list-iterator\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"341\",\n    \"topicTags\": \"Stack, Design\"\n  },\n  {\n    \"title\": \"Reverse String\",\n    \"titleSlug\": \"reverse-string\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"344\",\n    \"topicTags\": \"Two Pointers, String\"\n  },\n  {\n    \"title\": \"Top K Frequent Elements\",\n    \"titleSlug\": \"top-k-frequent-elements\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"347\",\n    \"topicTags\": \"Heap, Hash Table\"\n  },\n  {\n    \"title\": \"Intersection of Two Arrays\",\n    \"titleSlug\": \"intersection-of-two-arrays\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"349\",\n    \"topicTags\": \"Sort, Hash Table, Two Pointers, Binary Search\"\n  },\n  {\n    \"title\": \"Intersection of Two Arrays II\",\n    \"titleSlug\": \"intersection-of-two-arrays-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"350\",\n    \"topicTags\": \"Sort, Hash Table, Two Pointers, Binary Search\"\n  },\n  {\n    \"title\": \"Binary Watch\",\n    \"titleSlug\": \"binary-watch\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"401\",\n    \"topicTags\": \"Bit Manipulation, Backtracking\"\n  },\n  {\n    \"title\": \"Sum of Left Leaves\",\n    \"titleSlug\": \"sum-of-left-leaves\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"404\",\n    \"topicTags\": \"Tree\"\n  },\n  {\n    \"title\": \"Pacific Atlantic Water Flow\",\n    \"titleSlug\": \"pacific-atlantic-water-flow\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"417\",\n    \"topicTags\": \"Depth-first Search, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Path Sum III\",\n    \"titleSlug\": \"path-sum-iii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"437\",\n    \"topicTags\": \"Tree\"\n  },\n  {\n    \"title\": \"Find All Anagrams in a String\",\n    \"titleSlug\": \"find-all-anagrams-in-a-string\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"438\",\n    \"topicTags\": \"Hash Table\"\n  },\n  {\n    \"title\": \"Add Two Numbers II\",\n    \"titleSlug\": \"add-two-numbers-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"445\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Number of Boomerangs\",\n    \"titleSlug\": \"number-of-boomerangs\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"447\",\n    \"topicTags\": \"Hash Table, Math\"\n  },\n  {\n    \"title\": \"Delete Node in a BST\",\n    \"titleSlug\": \"delete-node-in-a-bst\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"450\",\n    \"topicTags\": \"Tree\"\n  },\n  {\n    \"title\": \"Sort Characters By Frequency\",\n    \"titleSlug\": \"sort-characters-by-frequency\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"451\",\n    \"topicTags\": \"Heap, Hash Table\"\n  },\n  {\n    \"title\": \"4Sum II\",\n    \"titleSlug\": \"4sum-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"454\",\n    \"topicTags\": \"Hash Table, Binary Search\"\n  },\n  {\n    \"title\": \"Permutation in String\",\n    \"titleSlug\": \"permutation-in-string\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"567\",\n    \"topicTags\": \"Two Pointers, Sliding Window\"\n  }\n]"
  },
  {
    "path": "packages/leetcode-cli/src/cli.js",
    "content": "#!/usr/bin/env node\nconst commander = require('commander')\nconst packageJson = require('../package.json')\nconst download = require('./download')\nconst logout = require('./logout')\nconst { login } = require('./leetcode')\n\ncommander.version(packageJson.version)\n\ncommander\n  .command('download')\n  .option('-a, --all', 'Download all your accepted code from LeetCode.')\n  .description('Download your new accepted code from LeetCode.')\n  .action(download)\n\ncommander\n  .command('login')\n  .description('Log in to your Leetcode account.')\n  .action(login)\n\ncommander\n  .command('logout')\n  .description('Logout current LeetCode account')\n  .description('Log out of current account.')\n  .action(logout)\n\ncommander.parse(process.argv)\n"
  },
  {
    "path": "packages/leetcode-cli/src/download.js",
    "content": "/* eslint-disable import/no-dynamic-require */\n/* eslint-disable global-require */\nconst fs = require('fs')\nconst ora = require('ora')\nconst { transformToMarkdownTable, stringify } = require('./utils')\nconst { getAllACQuestions, getQuestionData } = require('./leetcode')\nconst { resolveApp } = require('crd-utils')\n\nconst difference = (problemsA = [], problemsB = []) => {\n  const map = problemsB.reduce((acc, problem) => {\n    acc[problem.titleSlug] = true\n    return acc\n  }, {})\n  return problemsA.filter(problem => !map[problem.titleSlug])\n}\nconst download = async (command) => {\n  const problemsPath = 'problems.json'\n  // get incremental problems through comapre json\n  let problems = []\n  let questions = await getAllACQuestions()\n  if (!command.all) {\n    if (fs.existsSync(problemsPath)) {\n      problems = JSON.parse(fs.readFileSync(problemsPath))\n    }\n    questions = difference(questions, problems)\n  }\n\n  const spinner = ora('Downloading accepted code...\\n').start()\n  const aux = async (xs = []) => {\n    if (xs.length === 0) {\n      return\n    }\n    const current = xs.shift()\n    try {\n      const { topicTags } = await getQuestionData(current.titleSlug)\n      const result = topicTags.reduce((prev, cur) => {\n        if (prev === '') return cur.name\n        return `${prev}, ${cur.name}`\n      }, '')\n      current.topicTags = result\n    } catch (error) {\n      console.error(error.message)\n    }\n    spinner.text = `${questions.length - xs.length}/${questions.length}: [${\n      current.title\n    }] has downloaded.`\n    problems.push(current)\n    // it can be extracted in to config if there is need.\n    let leetcodeReadme = 'leetcode-table.md'\n    if (fs.existsSync(resolveApp('LeetCode/README.md'))) {\n      leetcodeReadme = resolveApp('LeetCode/README.md')\n    }\n    let transformMarkdownTable = transformToMarkdownTable\n    if (fs.existsSync(resolveApp('config.js'))) {\n      transformMarkdownTable = require(resolveApp('config.js')).transform_markdown_table\n    }\n    fs.writeFileSync(leetcodeReadme, transformMarkdownTable(problems))\n    // the problemsPath is to get incremental data.\n    fs.writeFileSync(problemsPath, stringify(problems))\n    await aux(xs)\n  }\n  await aux([...questions])\n  spinner.stop()\n}\n\nmodule.exports = download\n"
  },
  {
    "path": "packages/leetcode-cli/src/leetcode-table.md",
    "content": "| # | Title | Explanation | Difficulty | Type |\n|:---:|:---:|:---:|:---:|:---:|\n| 1 | [Two Sum](https://leetcode.com/problems/two-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/1.Two_Sum.md) | Easy | Array, Hash Table |\n| 2 | [Add Two Numbers](https://leetcode.com/problems/add-two-numbers/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/2.Add_Two_Numbers.md) | Medium | Linked List, Math |\n| 3 | [Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/3.Longest_Substring_Without_Repeating_Characters.md) | Medium | Hash Table, Two Pointers, String, Sliding Window |\n| 4 | [Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/4.Median_of_Two_Sorted_Arrays.md) | Hard | Array, Binary Search, Divide and Conquer |\n| 7 | [Reverse Integer](https://leetcode.com/problems/reverse-integer/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/7.Reverse_Integer.md) | Easy | Math |\n| 9 | [Palindrome Number](https://leetcode.com/problems/palindrome-number/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/9.Palindrome_Number.md) | Easy | Math |\n| 11 | [Container With Most Water](https://leetcode.com/problems/container-with-most-water/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/11.Container_With_Most_Water.md) | Medium | Array, Two Pointers |\n| 13 | [Roman to Integer](https://leetcode.com/problems/roman-to-integer/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/13.Roman_to_Integer.md) | Easy | Math, String |\n| 14 | [Longest Common Prefix](https://leetcode.com/problems/longest-common-prefix/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/14.Longest_Common_Prefix.md) | Easy | String |\n| 15 | [3Sum](https://leetcode.com/problems/3sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/15.3Sum.md) | Medium | Array, Two Pointers |\n| 16 | [3Sum Closest](https://leetcode.com/problems/3sum-closest/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/16.3Sum_Closest.md) | Medium | Array, Two Pointers |\n| 17 | [Letter Combinations of a Phone Number](https://leetcode.com/problems/letter-combinations-of-a-phone-number/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/17.Letter_Combinations_of_a_Phone_Number.md) | Medium | String, Backtracking |\n| 18 | [4Sum](https://leetcode.com/problems/4sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/18.4Sum.md) | Medium | Array, Hash Table, Two Pointers |\n| 19 | [Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/19.Remove_Nth_Node_From_End_of_List.md) | Medium | Linked List, Two Pointers |\n| 20 | [Valid Parentheses](https://leetcode.com/problems/valid-parentheses/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/20.Valid_Parentheses.md) | Easy | Stack, String |\n| 21 | [Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/21.Merge_Two_Sorted_Lists.md) | Easy | Linked List |\n| 22 | [Generate Parentheses](https://leetcode.com/problems/generate-parentheses/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/22.Generate_Parentheses.md) | Medium | String, Backtracking |\n| 23 | [Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/23.Merge_k_Sorted_Lists.md) | Hard | Heap, Linked List, Divide and Conquer |\n| 24 | [Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/24.Swap_Nodes_in_Pairs.md) | Medium | Linked List |\n| 25 | [Reverse Nodes in k-Group](https://leetcode.com/problems/reverse-nodes-in-k-group/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/25.Reverse_Nodes_in_k-Group.md) | Hard | Linked List |\n| 26 | [Remove Duplicates from Sorted Array](https://leetcode.com/problems/remove-duplicates-from-sorted-array/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/26.Remove_Duplicates_from_Sorted_Array.md) | Easy | Array, Two Pointers |\n| 27 | [Remove Element](https://leetcode.com/problems/remove-element/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/27.Remove_Element.md) | Easy | Array, Two Pointers |\n| 28 | [Implement strStr()](https://leetcode.com/problems/implement-strstr/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/28.Implement_strStr().md) | Easy | Two Pointers, String |\n| 33 | [Search in Rotated Sorted Array](https://leetcode.com/problems/search-in-rotated-sorted-array/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/33.Search_in_Rotated_Sorted_Array.md) | Medium | Array, Binary Search |\n| 35 | [Search Insert Position](https://leetcode.com/problems/search-insert-position/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/35.Search_Insert_Position.md) | Easy | Array, Binary Search |\n| 36 | [Valid Sudoku](https://leetcode.com/problems/valid-sudoku/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/36.Valid_Sudoku.md) | Medium | Hash Table |\n| 38 | [Count and Say](https://leetcode.com/problems/count-and-say/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/38.Count_and_Say.md) | Easy | String |\n| 39 | [Combination Sum](https://leetcode.com/problems/combination-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/39.Combination_Sum.md) | Medium | Array, Backtracking |\n| 40 | [Combination Sum II](https://leetcode.com/problems/combination-sum-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/40.Combination_Sum_II.md) | Medium | Array, Backtracking |\n| 46 | [Permutations](https://leetcode.com/problems/permutations/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/46.Permutations.md) | Medium | Backtracking |\n| 47 | [Permutations II](https://leetcode.com/problems/permutations-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/47.Permutations_II.md) | Medium | Backtracking |\n| 48 | [Rotate Image](https://leetcode.com/problems/rotate-image/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/48.Rotate_Image.md) | Medium | Array |\n| 49 | [Group Anagrams](https://leetcode.com/problems/group-anagrams/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/49.Group_Anagrams.md) | Medium | Hash Table, String |\n| 50 | [Pow(x, n)](https://leetcode.com/problems/powx-n/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/50.Pow(x,_n).md) | Medium | Math, Binary Search |\n| 61 | [Rotate List](https://leetcode.com/problems/rotate-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/61.Rotate_List.md) | Medium | Linked List, Two Pointers |\n| 62 | [Unique Paths](https://leetcode.com/problems/unique-paths/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/62.Unique_Paths.md) | Medium | Array, Dynamic Programming |\n| 64 | [Minimum Path Sum](https://leetcode.com/problems/minimum-path-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/64.Minimum_Path_Sum.md) | Medium | Array, Dynamic Programming |\n| 66 | [Plus One](https://leetcode.com/problems/plus-one/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/66.Plus_One.md) | Easy | Array |\n| 67 | [Add Binary](https://leetcode.com/problems/add-binary/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/67.Add_Binary.md) | Easy | Math, String |\n| 69 | [Sqrt(x)](https://leetcode.com/problems/sqrtx/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/69.Sqrt(x).md) | Easy | Math, Binary Search |\n| 70 | [Climbing Stairs](https://leetcode.com/problems/climbing-stairs/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/70.Climbing_Stairs.md) | Easy | Dynamic Programming |\n| 71 | [Simplify Path](https://leetcode.com/problems/simplify-path/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/71.Simplify_Path.md) | Medium | Stack, String |\n| 75 | [Sort Colors](https://leetcode.com/problems/sort-colors/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/75.Sort_Colors.md) | Medium | Sort, Array, Two Pointers |\n| 78 | [Subsets](https://leetcode.com/problems/subsets/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/78.Subsets.md) | Medium | Bit Manipulation, Array, Backtracking |\n| 80 | [Remove Duplicates from Sorted Array II](https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/80.Remove_Duplicates_from_Sorted_Array_II.md) | Medium | Array, Two Pointers |\n| 82 | [Remove Duplicates from Sorted List II](https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/82.Remove_Duplicates_from_Sorted_List_II.md) | Medium | Linked List |\n| 83 | [Remove Duplicates from Sorted List](https://leetcode.com/problems/remove-duplicates-from-sorted-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/83.Remove_Duplicates_from_Sorted_List.md) | Easy | Linked List |\n| 86 | [Partition List](https://leetcode.com/problems/partition-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/86.Partition_List.md) | Medium | Linked List, Two Pointers |\n| 88 | [Merge Sorted Array](https://leetcode.com/problems/merge-sorted-array/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/88.Merge_Sorted_Array.md) | Easy | Array, Two Pointers |\n| 89 | [Gray Code](https://leetcode.com/problems/gray-code/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/89.Gray_Code.md) | Medium | Backtracking |\n| 92 | [Reverse Linked List II](https://leetcode.com/problems/reverse-linked-list-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/92.Reverse_Linked_List_II.md) | Medium | Linked List |\n| 93 | [Restore IP Addresses](https://leetcode.com/problems/restore-ip-addresses/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/93.Restore_IP_Addresses.md) | Medium | String, Backtracking |\n| 94 | [Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/94.Binary_Tree_Inorder_Traversal.md) | Medium | Stack, Tree, Hash Table |\n| 100 | [Same Tree](https://leetcode.com/problems/same-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/100.Same_Tree.md) | Easy | Tree, Depth-first Search |\n| 101 | [Symmetric Tree](https://leetcode.com/problems/symmetric-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/101.Symmetric_Tree.md) | Easy | Tree, Depth-first Search, Breadth-first Search |\n| 102 | [Binary Tree Level Order Traversal](https://leetcode.com/problems/binary-tree-level-order-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/102.Binary_Tree_Level_Order_Traversal.md) | Medium | Tree, Breadth-first Search |\n| 103 | [Binary Tree Zigzag Level Order Traversal](https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/103.Binary_Tree_Zigzag_Level_Order_Traversal.md) | Medium | Stack, Tree, Breadth-first Search |\n| 104 | [Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/104.Maximum_Depth_of_Binary_Tree.md) | Easy | Tree, Depth-first Search |\n| 107 | [Binary Tree Level Order Traversal II](https://leetcode.com/problems/binary-tree-level-order-traversal-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/107.Binary_Tree_Level_Order_Traversal_II.md) | Easy | Tree, Breadth-first Search |\n| 110 | [Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/110.Balanced_Binary_Tree.md) | Easy | Tree, Depth-first Search |\n| 111 | [Minimum Depth of Binary Tree](https://leetcode.com/problems/minimum-depth-of-binary-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/111.Minimum_Depth_of_Binary_Tree.md) | Easy | Tree, Depth-first Search, Breadth-first Search |\n| 112 | [Path Sum](https://leetcode.com/problems/path-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/112.Path_Sum.md) | Easy | Tree, Depth-first Search |\n| 113 | [Path Sum II](https://leetcode.com/problems/path-sum-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/113.Path_Sum_II.md) | Medium | Tree, Depth-first Search |\n| 121 | [Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/121.Best_Time_to_Buy_and_Sell_Stock.md) | Easy | Array, Dynamic Programming |\n| 125 | [Valid Palindrome](https://leetcode.com/problems/valid-palindrome/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/125.Valid_Palindrome.md) | Easy | Two Pointers, String |\n| 127 | [Word Ladder](https://leetcode.com/problems/word-ladder/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/127.Word_Ladder.md) | Medium | Breadth-first Search |\n| 129 | [Sum Root to Leaf Numbers](https://leetcode.com/problems/sum-root-to-leaf-numbers/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/129.Sum_Root_to_Leaf_Numbers.md) | Medium | Tree, Depth-first Search |\n| 143 | [Reorder List](https://leetcode.com/problems/reorder-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/143.Reorder_List.md) | Medium | Linked List |\n| 144 | [Binary Tree Preorder Traversal](https://leetcode.com/problems/binary-tree-preorder-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/144.Binary_Tree_Preorder_Traversal.md) | Medium | Stack, Tree |\n| 145 | [Binary Tree Postorder Traversal](https://leetcode.com/problems/binary-tree-postorder-traversal/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/145.Binary_Tree_Postorder_Traversal.md) | Medium | Stack, Tree |\n| 147 | [Insertion Sort List](https://leetcode.com/problems/insertion-sort-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/147.Insertion_Sort_List.md) | Medium | Sort, Linked List |\n| 148 | [Sort List](https://leetcode.com/problems/sort-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/148.Sort_List.md) | Medium | Sort, Linked List |\n| 149 | [Max Points on a Line](https://leetcode.com/problems/max-points-on-a-line/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/149.Max_Points_on_a_Line.md) | Hard | Hash Table, Math |\n| 150 | [Evaluate Reverse Polish Notation](https://leetcode.com/problems/evaluate-reverse-polish-notation/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/150.Evaluate_Reverse_Polish_Notation.md) | Medium | Stack |\n| 151 | [Reverse Words in a String](https://leetcode.com/problems/reverse-words-in-a-string/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/151.Reverse_Words_in_a_String.md) | Medium | String |\n| 167 | [Two Sum II - Input array is sorted](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/167.Two_Sum_II_-_Input_array_is_sorted.md) | Easy | Array, Two Pointers, Binary Search |\n| 199 | [Binary Tree Right Side View](https://leetcode.com/problems/binary-tree-right-side-view/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/199.Binary_Tree_Right_Side_View.md) | Medium | Tree, Depth-first Search, Breadth-first Search |\n| 202 | [Happy Number](https://leetcode.com/problems/happy-number/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/202.Happy_Number.md) | Easy | Hash Table, Math |\n| 203 | [Remove Linked List Elements](https://leetcode.com/problems/remove-linked-list-elements/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/203.Remove_Linked_List_Elements.md) | Easy | Linked List |\n| 205 | [Isomorphic Strings](https://leetcode.com/problems/isomorphic-strings/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/205.Isomorphic_Strings.md) | Easy | Hash Table |\n| 206 | [Reverse Linked List](https://leetcode.com/problems/reverse-linked-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/206.Reverse_Linked_List.md) | Easy | Linked List |\n| 209 | [Minimum Size Subarray Sum](https://leetcode.com/problems/minimum-size-subarray-sum/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/209.Minimum_Size_Subarray_Sum.md) | Medium | Array, Two Pointers, Binary Search |\n| 215 | [Kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/215.Kth_Largest_Element_in_an_Array.md) | Medium | Heap, Divide and Conquer |\n| 217 | [Contains Duplicate](https://leetcode.com/problems/contains-duplicate/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/217.Contains_Duplicate.md) | Easy | Array, Hash Table |\n| 219 | [Contains Duplicate II](https://leetcode.com/problems/contains-duplicate-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/219.Contains_Duplicate_II.md) | Easy | Array, Hash Table |\n| 220 | [Contains Duplicate III](https://leetcode.com/problems/contains-duplicate-iii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/220.Contains_Duplicate_III.md) | Medium | Sort, Ordered Map |\n| 222 | [Count Complete Tree Nodes](https://leetcode.com/problems/count-complete-tree-nodes/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/222.Count_Complete_Tree_Nodes.md) | Medium | Tree, Binary Search |\n| 226 | [Invert Binary Tree](https://leetcode.com/problems/invert-binary-tree/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/226.Invert_Binary_Tree.md) | Easy | Tree |\n| 234 | [Palindrome Linked List](https://leetcode.com/problems/palindrome-linked-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/234.Palindrome_Linked_List.md) | Easy | Linked List, Two Pointers |\n| 237 | [Delete Node in a Linked List](https://leetcode.com/problems/delete-node-in-a-linked-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/237.Delete_Node_in_a_Linked_List.md) | Easy | Linked List |\n| 242 | [Valid Anagram](https://leetcode.com/problems/valid-anagram/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/242.Valid_Anagram.md) | Easy | Sort, Hash Table |\n| 257 | [Binary Tree Paths](https://leetcode.com/problems/binary-tree-paths/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/257.Binary_Tree_Paths.md) | Easy | Tree, Depth-first Search |\n| 279 | [Perfect Squares](https://leetcode.com/problems/perfect-squares/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/279.Perfect_Squares.md) | Medium | Breadth-first Search, Math, Dynamic Programming |\n| 283 | [Move Zeroes](https://leetcode.com/problems/move-zeroes/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/283.Move_Zeroes.md) | Easy | Array, Two Pointers |\n| 290 | [Word Pattern](https://leetcode.com/problems/word-pattern/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/290.Word_Pattern.md) | Easy | Hash Table |\n| 328 | [Odd Even Linked List](https://leetcode.com/problems/odd-even-linked-list/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/328.Odd_Even_Linked_List.md) | Medium | Linked List |\n| 341 | [Flatten Nested List Iterator](https://leetcode.com/problems/flatten-nested-list-iterator/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/341.Flatten_Nested_List_Iterator.md) | Medium | Stack, Design |\n| 344 | [Reverse String](https://leetcode.com/problems/reverse-string/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/344.Reverse_String.md) | Easy | Two Pointers, String |\n| 347 | [Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/347.Top_K_Frequent_Elements.md) | Medium | Heap, Hash Table |\n| 349 | [Intersection of Two Arrays](https://leetcode.com/problems/intersection-of-two-arrays/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/349.Intersection_of_Two_Arrays.md) | Easy | Sort, Hash Table, Two Pointers, Binary Search |\n| 350 | [Intersection of Two Arrays II](https://leetcode.com/problems/intersection-of-two-arrays-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/350.Intersection_of_Two_Arrays_II.md) | Easy | Sort, Hash Table, Two Pointers, Binary Search |\n| 404 | [Sum of Left Leaves](https://leetcode.com/problems/sum-of-left-leaves/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/404.Sum_of_Left_Leaves.md) | Easy | Tree |\n| 438 | [Find All Anagrams in a String](https://leetcode.com/problems/find-all-anagrams-in-a-string/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/438.Find_All_Anagrams_in_a_String.md) | Medium | Hash Table |\n| 445 | [Add Two Numbers II](https://leetcode.com/problems/add-two-numbers-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/445.Add_Two_Numbers_II.md) | Medium | Linked List |\n| 447 | [Number of Boomerangs](https://leetcode.com/problems/number-of-boomerangs/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/447.Number_of_Boomerangs.md) | Easy | Hash Table |\n| 451 | [Sort Characters By Frequency](https://leetcode.com/problems/sort-characters-by-frequency/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/451.Sort_Characters_By_Frequency.md) | Medium | Heap, Hash Table |\n| 454 | [4Sum II](https://leetcode.com/problems/4sum-ii/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/454.4Sum_II.md) | Medium | Hash Table, Binary Search |\n| 567 | [Permutation in String](https://leetcode.com/problems/permutation-in-string/) | [Analyze](https://github.com/MuYunyun/blog/blob/master/LeetCode/567.Permutation_in_String.md) | Medium | Two Pointers, Sliding Window |"
  },
  {
    "path": "packages/leetcode-cli/src/leetcode.js",
    "content": "const { GraphQLClient } = require('graphql-request')\nconst ora = require('ora')\nconst inquirer = require('inquirer')\nconst puppeteer = require('puppeteer-extra')\nconst StealthPlugin = require('puppeteer-extra-plugin-stealth')\n\nconst {\n  // request,\n  getHeaders,\n  // unicodeToChar,\n  removeConfig,\n  getConfig,\n  setConfig,\n} = require('./utils')\n\n// use this plugin to close to the real login.\npuppeteer.use(StealthPlugin())\n\nconst { country } = getConfig()\n\nconst usUrl = 'https://leetcode.com'\nconst cnUrl = 'https://leetcode-cn.com'\nconst baseUrl = country === 'us' ? usUrl : cnUrl\nconst graphqlUrl = `${baseUrl}/graphql`\n\nconst login = async () => {\n  let loginUrl = baseUrl\n  if (country === undefined) {\n    loginUrl = (\n      await inquirer.prompt({\n        name: 'baseUrl',\n        type: 'list',\n        message: 'Log in to:',\n        choices: [usUrl, cnUrl],\n      })\n    ).baseUrl\n    setConfig({ country: loginUrl === cnUrl ? 'cn' : 'us' })\n  }\n  loginUrl += '/accounts/login/'\n\n  const spinner = ora('Login...').start()\n  try {\n    // it have to set executablePath or it'll be broken.https://github.com/puppeteer/puppeteer/issues/6425\n    // temporary way: https://stackoverflow.com/questions/47122579/run-puppeteer-on-already-installed-chrome-on-macos\n    const browser = await puppeteer.launch({ headless: false, executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' })\n    const page = await browser.newPage()\n    await page.goto(loginUrl)\n    await page.waitForFunction('window.location.href.indexOf(\"login\") === -1')\n    let cookies = await page.cookies()\n    await browser.close()\n    spinner.stop()\n    cookies = cookies.reduce((acc, cookie) => {\n      const { name } = cookie\n      acc[name] = cookie\n      return acc\n    }, {})\n    setConfig({ cookies })\n    return cookies\n  } catch (error) {\n    console.error('Login failure, retry...', error.message)\n    throw error\n  } finally {\n    spinner.stop()\n  }\n}\n\nconst getCookie = async () => {\n  // eslint-disable-line\n  try {\n    const { cookies } = getConfig()\n    const { LEETCODE_SESSION } = cookies\n    if (\n      !LEETCODE_SESSION ||\n      new Date(LEETCODE_SESSION.expires) <= new Date().getTime() / 1000\n    ) {\n      console.error('Cookie expires, retry...')\n      removeConfig('cookies')\n      return getCookie()\n    }\n    return Object.keys(cookies).reduce((acc, name) => {\n      acc[name] = cookies[name].value\n      return acc\n    }, {})\n  } catch (error) {\n    const cookies = await login()\n    return cookies\n  }\n}\n\nconst createGqlRequest = async () => {\n  const cookies = await getCookie()\n  const client = new GraphQLClient(graphqlUrl, {\n    headers: getHeaders(cookies),\n  })\n  return client.request.bind(client)\n}\n\n// restful request\n// const createRequest = async () => {\n//   const cookies = await getCookie();\n//   return url =>\n//     request(url, {\n//       headers: getHeaders(cookies),\n//     });\n// };\nconst filterAcQuestions = (questions = []) =>\n  questions.filter(({ status }) => status === 'ac')\n\nconst getAllACQuestions = async () => {\n  const gqlRequest = await createGqlRequest()\n  const spinner = ora('Fetching all questions...').start()\n  // interface see https://leetcode-cn.com/problems/add-two-numbers/\n  const json = await gqlRequest(`{\n    allQuestions{\n      title\n      titleSlug\n      status\n      difficulty\n      questionId,\n    }\n  }`)\n  spinner.stop()\n  const questions = json.allQuestions || []\n  return filterAcQuestions(questions)\n}\n\n// get details of ac code.\nconst getQuestionData = async (titleSlug) => {\n  const qglRequest = await createGqlRequest()\n  // interface from 'https://leetcode-cn.com/problems/add-two-numbers/'\n  const json = await qglRequest(`{\n    question(titleSlug: \"${titleSlug}\") {\n      topicTags {\n        name\n        slug\n      }\n    }\n  }`)\n  const question = json.question || {}\n  return question\n}\n\nmodule.exports = {\n  login,\n  getAllACQuestions,\n  getQuestionData,\n  getCookie,\n}\n"
  },
  {
    "path": "packages/leetcode-cli/src/logout.js",
    "content": "const { removeConfig } = require('./utils')\n\nconst logOut = () => {\n  removeConfig('cookies')\n}\n\nmodule.exports = logOut\n"
  },
  {
    "path": "packages/leetcode-cli/src/problems.json",
    "content": "[\n  {\n    \"title\": \"Two Sum\",\n    \"titleSlug\": \"two-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"1\",\n    \"topicTags\": \"Array, Hash Table\"\n  },\n  {\n    \"title\": \"Add Two Numbers\",\n    \"titleSlug\": \"add-two-numbers\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"2\",\n    \"topicTags\": \"Linked List, Math\"\n  },\n  {\n    \"title\": \"Longest Substring Without Repeating Characters\",\n    \"titleSlug\": \"longest-substring-without-repeating-characters\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"3\",\n    \"topicTags\": \"Hash Table, Two Pointers, String, Sliding Window\"\n  },\n  {\n    \"title\": \"Median of Two Sorted Arrays\",\n    \"titleSlug\": \"median-of-two-sorted-arrays\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"4\",\n    \"topicTags\": \"Array, Binary Search, Divide and Conquer\"\n  },\n  {\n    \"title\": \"Reverse Integer\",\n    \"titleSlug\": \"reverse-integer\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"7\",\n    \"topicTags\": \"Math\"\n  },\n  {\n    \"title\": \"Palindrome Number\",\n    \"titleSlug\": \"palindrome-number\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"9\",\n    \"topicTags\": \"Math\"\n  },\n  {\n    \"title\": \"Container With Most Water\",\n    \"titleSlug\": \"container-with-most-water\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"11\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Roman to Integer\",\n    \"titleSlug\": \"roman-to-integer\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"13\",\n    \"topicTags\": \"Math, String\"\n  },\n  {\n    \"title\": \"Longest Common Prefix\",\n    \"titleSlug\": \"longest-common-prefix\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"14\",\n    \"topicTags\": \"String\"\n  },\n  {\n    \"title\": \"3Sum\",\n    \"titleSlug\": \"3sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"15\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"3Sum Closest\",\n    \"titleSlug\": \"3sum-closest\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"16\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Letter Combinations of a Phone Number\",\n    \"titleSlug\": \"letter-combinations-of-a-phone-number\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"17\",\n    \"topicTags\": \"String, Backtracking\"\n  },\n  {\n    \"title\": \"4Sum\",\n    \"titleSlug\": \"4sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"18\",\n    \"topicTags\": \"Array, Hash Table, Two Pointers\"\n  },\n  {\n    \"title\": \"Remove Nth Node From End of List\",\n    \"titleSlug\": \"remove-nth-node-from-end-of-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"19\",\n    \"topicTags\": \"Linked List, Two Pointers\"\n  },\n  {\n    \"title\": \"Valid Parentheses\",\n    \"titleSlug\": \"valid-parentheses\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"20\",\n    \"topicTags\": \"Stack, String\"\n  },\n  {\n    \"title\": \"Merge Two Sorted Lists\",\n    \"titleSlug\": \"merge-two-sorted-lists\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"21\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Generate Parentheses\",\n    \"titleSlug\": \"generate-parentheses\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"22\",\n    \"topicTags\": \"String, Backtracking\"\n  },\n  {\n    \"title\": \"Merge k Sorted Lists\",\n    \"titleSlug\": \"merge-k-sorted-lists\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"23\",\n    \"topicTags\": \"Heap, Linked List, Divide and Conquer\"\n  },\n  {\n    \"title\": \"Swap Nodes in Pairs\",\n    \"titleSlug\": \"swap-nodes-in-pairs\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"24\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Reverse Nodes in k-Group\",\n    \"titleSlug\": \"reverse-nodes-in-k-group\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"25\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Remove Duplicates from Sorted Array\",\n    \"titleSlug\": \"remove-duplicates-from-sorted-array\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"26\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Remove Element\",\n    \"titleSlug\": \"remove-element\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"27\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Implement strStr()\",\n    \"titleSlug\": \"implement-strstr\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"28\",\n    \"topicTags\": \"Two Pointers, String\"\n  },\n  {\n    \"title\": \"Search in Rotated Sorted Array\",\n    \"titleSlug\": \"search-in-rotated-sorted-array\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"33\",\n    \"topicTags\": \"Array, Binary Search\"\n  },\n  {\n    \"title\": \"Search Insert Position\",\n    \"titleSlug\": \"search-insert-position\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"35\",\n    \"topicTags\": \"Array, Binary Search\"\n  },\n  {\n    \"title\": \"Valid Sudoku\",\n    \"titleSlug\": \"valid-sudoku\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"36\",\n    \"topicTags\": \"Hash Table\"\n  },\n  {\n    \"title\": \"Count and Say\",\n    \"titleSlug\": \"count-and-say\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"38\",\n    \"topicTags\": \"String\"\n  },\n  {\n    \"title\": \"Combination Sum\",\n    \"titleSlug\": \"combination-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"39\",\n    \"topicTags\": \"Array, Backtracking\"\n  },\n  {\n    \"title\": \"Combination Sum II\",\n    \"titleSlug\": \"combination-sum-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"40\",\n    \"topicTags\": \"Array, Backtracking\"\n  },\n  {\n    \"title\": \"Permutations\",\n    \"titleSlug\": \"permutations\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"46\",\n    \"topicTags\": \"Backtracking\"\n  },\n  {\n    \"title\": \"Permutations II\",\n    \"titleSlug\": \"permutations-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"47\",\n    \"topicTags\": \"Backtracking\"\n  },\n  {\n    \"title\": \"Rotate Image\",\n    \"titleSlug\": \"rotate-image\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"48\",\n    \"topicTags\": \"Array\"\n  },\n  {\n    \"title\": \"Group Anagrams\",\n    \"titleSlug\": \"group-anagrams\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"49\",\n    \"topicTags\": \"Hash Table, String\"\n  },\n  {\n    \"title\": \"Pow(x, n)\",\n    \"titleSlug\": \"powx-n\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"50\",\n    \"topicTags\": \"Math, Binary Search\"\n  },\n  {\n    \"title\": \"Rotate List\",\n    \"titleSlug\": \"rotate-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"61\",\n    \"topicTags\": \"Linked List, Two Pointers\"\n  },\n  {\n    \"title\": \"Unique Paths\",\n    \"titleSlug\": \"unique-paths\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"62\",\n    \"topicTags\": \"Array, Dynamic Programming\"\n  },\n  {\n    \"title\": \"Minimum Path Sum\",\n    \"titleSlug\": \"minimum-path-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"64\",\n    \"topicTags\": \"Array, Dynamic Programming\"\n  },\n  {\n    \"title\": \"Plus One\",\n    \"titleSlug\": \"plus-one\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"66\",\n    \"topicTags\": \"Array\"\n  },\n  {\n    \"title\": \"Add Binary\",\n    \"titleSlug\": \"add-binary\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"67\",\n    \"topicTags\": \"Math, String\"\n  },\n  {\n    \"title\": \"Sqrt(x)\",\n    \"titleSlug\": \"sqrtx\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"69\",\n    \"topicTags\": \"Math, Binary Search\"\n  },\n  {\n    \"title\": \"Climbing Stairs\",\n    \"titleSlug\": \"climbing-stairs\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"70\",\n    \"topicTags\": \"Dynamic Programming\"\n  },\n  {\n    \"title\": \"Simplify Path\",\n    \"titleSlug\": \"simplify-path\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"71\",\n    \"topicTags\": \"Stack, String\"\n  },\n  {\n    \"title\": \"Sort Colors\",\n    \"titleSlug\": \"sort-colors\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"75\",\n    \"topicTags\": \"Sort, Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Subsets\",\n    \"titleSlug\": \"subsets\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"78\",\n    \"topicTags\": \"Bit Manipulation, Array, Backtracking\"\n  },\n  {\n    \"title\": \"Remove Duplicates from Sorted Array II\",\n    \"titleSlug\": \"remove-duplicates-from-sorted-array-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"80\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Remove Duplicates from Sorted List II\",\n    \"titleSlug\": \"remove-duplicates-from-sorted-list-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"82\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Remove Duplicates from Sorted List\",\n    \"titleSlug\": \"remove-duplicates-from-sorted-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"83\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Partition List\",\n    \"titleSlug\": \"partition-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"86\",\n    \"topicTags\": \"Linked List, Two Pointers\"\n  },\n  {\n    \"title\": \"Merge Sorted Array\",\n    \"titleSlug\": \"merge-sorted-array\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"88\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Gray Code\",\n    \"titleSlug\": \"gray-code\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"89\",\n    \"topicTags\": \"Backtracking\"\n  },\n  {\n    \"title\": \"Reverse Linked List II\",\n    \"titleSlug\": \"reverse-linked-list-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"92\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Restore IP Addresses\",\n    \"titleSlug\": \"restore-ip-addresses\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"93\",\n    \"topicTags\": \"String, Backtracking\"\n  },\n  {\n    \"title\": \"Binary Tree Inorder Traversal\",\n    \"titleSlug\": \"binary-tree-inorder-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"94\",\n    \"topicTags\": \"Stack, Tree, Hash Table\"\n  },\n  {\n    \"title\": \"Same Tree\",\n    \"titleSlug\": \"same-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"100\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Symmetric Tree\",\n    \"titleSlug\": \"symmetric-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"101\",\n    \"topicTags\": \"Tree, Depth-first Search, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Binary Tree Level Order Traversal\",\n    \"titleSlug\": \"binary-tree-level-order-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"102\",\n    \"topicTags\": \"Tree, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Binary Tree Zigzag Level Order Traversal\",\n    \"titleSlug\": \"binary-tree-zigzag-level-order-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"103\",\n    \"topicTags\": \"Stack, Tree, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Maximum Depth of Binary Tree\",\n    \"titleSlug\": \"maximum-depth-of-binary-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"104\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Binary Tree Level Order Traversal II\",\n    \"titleSlug\": \"binary-tree-level-order-traversal-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"107\",\n    \"topicTags\": \"Tree, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Balanced Binary Tree\",\n    \"titleSlug\": \"balanced-binary-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"110\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Minimum Depth of Binary Tree\",\n    \"titleSlug\": \"minimum-depth-of-binary-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"111\",\n    \"topicTags\": \"Tree, Depth-first Search, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Path Sum\",\n    \"titleSlug\": \"path-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"112\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Path Sum II\",\n    \"titleSlug\": \"path-sum-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"113\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Best Time to Buy and Sell Stock\",\n    \"titleSlug\": \"best-time-to-buy-and-sell-stock\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"121\",\n    \"topicTags\": \"Array, Dynamic Programming\"\n  },\n  {\n    \"title\": \"Valid Palindrome\",\n    \"titleSlug\": \"valid-palindrome\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"125\",\n    \"topicTags\": \"Two Pointers, String\"\n  },\n  {\n    \"title\": \"Word Ladder\",\n    \"titleSlug\": \"word-ladder\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"127\",\n    \"topicTags\": \"Breadth-first Search\"\n  },\n  {\n    \"title\": \"Sum Root to Leaf Numbers\",\n    \"titleSlug\": \"sum-root-to-leaf-numbers\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"129\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Reorder List\",\n    \"titleSlug\": \"reorder-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"143\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Binary Tree Preorder Traversal\",\n    \"titleSlug\": \"binary-tree-preorder-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"144\",\n    \"topicTags\": \"Stack, Tree\"\n  },\n  {\n    \"title\": \"Binary Tree Postorder Traversal\",\n    \"titleSlug\": \"binary-tree-postorder-traversal\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"145\",\n    \"topicTags\": \"Stack, Tree\"\n  },\n  {\n    \"title\": \"Insertion Sort List\",\n    \"titleSlug\": \"insertion-sort-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"147\",\n    \"topicTags\": \"Sort, Linked List\"\n  },\n  {\n    \"title\": \"Sort List\",\n    \"titleSlug\": \"sort-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"148\",\n    \"topicTags\": \"Sort, Linked List\"\n  },\n  {\n    \"title\": \"Max Points on a Line\",\n    \"titleSlug\": \"max-points-on-a-line\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Hard\",\n    \"questionId\": \"149\",\n    \"topicTags\": \"Hash Table, Math\"\n  },\n  {\n    \"title\": \"Evaluate Reverse Polish Notation\",\n    \"titleSlug\": \"evaluate-reverse-polish-notation\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"150\",\n    \"topicTags\": \"Stack\"\n  },\n  {\n    \"title\": \"Reverse Words in a String\",\n    \"titleSlug\": \"reverse-words-in-a-string\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"151\",\n    \"topicTags\": \"String\"\n  },\n  {\n    \"title\": \"Two Sum II - Input array is sorted\",\n    \"titleSlug\": \"two-sum-ii-input-array-is-sorted\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"167\",\n    \"topicTags\": \"Array, Two Pointers, Binary Search\"\n  },\n  {\n    \"title\": \"Binary Tree Right Side View\",\n    \"titleSlug\": \"binary-tree-right-side-view\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"199\",\n    \"topicTags\": \"Tree, Depth-first Search, Breadth-first Search\"\n  },\n  {\n    \"title\": \"Happy Number\",\n    \"titleSlug\": \"happy-number\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"202\",\n    \"topicTags\": \"Hash Table, Math\"\n  },\n  {\n    \"title\": \"Remove Linked List Elements\",\n    \"titleSlug\": \"remove-linked-list-elements\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"203\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Isomorphic Strings\",\n    \"titleSlug\": \"isomorphic-strings\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"205\",\n    \"topicTags\": \"Hash Table\"\n  },\n  {\n    \"title\": \"Reverse Linked List\",\n    \"titleSlug\": \"reverse-linked-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"206\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Minimum Size Subarray Sum\",\n    \"titleSlug\": \"minimum-size-subarray-sum\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"209\",\n    \"topicTags\": \"Array, Two Pointers, Binary Search\"\n  },\n  {\n    \"title\": \"Kth Largest Element in an Array\",\n    \"titleSlug\": \"kth-largest-element-in-an-array\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"215\",\n    \"topicTags\": \"Heap, Divide and Conquer\"\n  },\n  {\n    \"title\": \"Contains Duplicate\",\n    \"titleSlug\": \"contains-duplicate\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"217\",\n    \"topicTags\": \"Array, Hash Table\"\n  },\n  {\n    \"title\": \"Contains Duplicate II\",\n    \"titleSlug\": \"contains-duplicate-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"219\",\n    \"topicTags\": \"Array, Hash Table\"\n  },\n  {\n    \"title\": \"Contains Duplicate III\",\n    \"titleSlug\": \"contains-duplicate-iii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"220\",\n    \"topicTags\": \"Sort, Ordered Map\"\n  },\n  {\n    \"title\": \"Count Complete Tree Nodes\",\n    \"titleSlug\": \"count-complete-tree-nodes\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"222\",\n    \"topicTags\": \"Tree, Binary Search\"\n  },\n  {\n    \"title\": \"Invert Binary Tree\",\n    \"titleSlug\": \"invert-binary-tree\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"226\",\n    \"topicTags\": \"Tree\"\n  },\n  {\n    \"title\": \"Palindrome Linked List\",\n    \"titleSlug\": \"palindrome-linked-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"234\",\n    \"topicTags\": \"Linked List, Two Pointers\"\n  },\n  {\n    \"title\": \"Delete Node in a Linked List\",\n    \"titleSlug\": \"delete-node-in-a-linked-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"237\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Valid Anagram\",\n    \"titleSlug\": \"valid-anagram\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"242\",\n    \"topicTags\": \"Sort, Hash Table\"\n  },\n  {\n    \"title\": \"Binary Tree Paths\",\n    \"titleSlug\": \"binary-tree-paths\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"257\",\n    \"topicTags\": \"Tree, Depth-first Search\"\n  },\n  {\n    \"title\": \"Perfect Squares\",\n    \"titleSlug\": \"perfect-squares\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"279\",\n    \"topicTags\": \"Breadth-first Search, Math, Dynamic Programming\"\n  },\n  {\n    \"title\": \"Move Zeroes\",\n    \"titleSlug\": \"move-zeroes\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"283\",\n    \"topicTags\": \"Array, Two Pointers\"\n  },\n  {\n    \"title\": \"Word Pattern\",\n    \"titleSlug\": \"word-pattern\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"290\",\n    \"topicTags\": \"Hash Table\"\n  },\n  {\n    \"title\": \"Odd Even Linked List\",\n    \"titleSlug\": \"odd-even-linked-list\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"328\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Flatten Nested List Iterator\",\n    \"titleSlug\": \"flatten-nested-list-iterator\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"341\",\n    \"topicTags\": \"Stack, Design\"\n  },\n  {\n    \"title\": \"Reverse String\",\n    \"titleSlug\": \"reverse-string\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"344\",\n    \"topicTags\": \"Two Pointers, String\"\n  },\n  {\n    \"title\": \"Top K Frequent Elements\",\n    \"titleSlug\": \"top-k-frequent-elements\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"347\",\n    \"topicTags\": \"Heap, Hash Table\"\n  },\n  {\n    \"title\": \"Intersection of Two Arrays\",\n    \"titleSlug\": \"intersection-of-two-arrays\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"349\",\n    \"topicTags\": \"Sort, Hash Table, Two Pointers, Binary Search\"\n  },\n  {\n    \"title\": \"Intersection of Two Arrays II\",\n    \"titleSlug\": \"intersection-of-two-arrays-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"350\",\n    \"topicTags\": \"Sort, Hash Table, Two Pointers, Binary Search\"\n  },\n  {\n    \"title\": \"Sum of Left Leaves\",\n    \"titleSlug\": \"sum-of-left-leaves\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"404\",\n    \"topicTags\": \"Tree\"\n  },\n  {\n    \"title\": \"Find All Anagrams in a String\",\n    \"titleSlug\": \"find-all-anagrams-in-a-string\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"438\",\n    \"topicTags\": \"Hash Table\"\n  },\n  {\n    \"title\": \"Add Two Numbers II\",\n    \"titleSlug\": \"add-two-numbers-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"445\",\n    \"topicTags\": \"Linked List\"\n  },\n  {\n    \"title\": \"Number of Boomerangs\",\n    \"titleSlug\": \"number-of-boomerangs\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Easy\",\n    \"questionId\": \"447\",\n    \"topicTags\": \"Hash Table\"\n  },\n  {\n    \"title\": \"Sort Characters By Frequency\",\n    \"titleSlug\": \"sort-characters-by-frequency\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"451\",\n    \"topicTags\": \"Heap, Hash Table\"\n  },\n  {\n    \"title\": \"4Sum II\",\n    \"titleSlug\": \"4sum-ii\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"454\",\n    \"topicTags\": \"Hash Table, Binary Search\"\n  },\n  {\n    \"title\": \"Permutation in String\",\n    \"titleSlug\": \"permutation-in-string\",\n    \"status\": \"ac\",\n    \"difficulty\": \"Medium\",\n    \"questionId\": \"567\",\n    \"topicTags\": \"Two Pointers, Sliding Window\"\n  }\n]"
  },
  {
    "path": "packages/leetcode-cli/src/utils.js",
    "content": "/* eslint-disable no-plusplus */\nconst { promisify } = require('util')\nconst homedir = require('os').homedir()\nconst fs = require('fs')\nconst path = require('path')\nlet request = require('request')\n\nconst parseCookie = response =>\n  response.headers['set-cookie']\n    .map((x = '') => x.split('; '))\n    .reduce((acc, item) => acc.concat(item))\n    .reduce((acc, item) => {\n      const [key, value] = item.split('=')\n      acc[key] = value\n      return acc\n    }, {})\n\nrequest = promisify(request)\nrequest.post = promisify(request.post)\n\nconst getHeaders = session => ({\n  'Content-Type': 'application/json',\n  'x-csrftoken': session.csrftoken,\n  cookie: `LEETCODE_SESSION=${session.LEETCODE_SESSION};csrftoken=${session.csrftoken};`,\n})\n\nconst unicodeToChar = text =>\n  text.replace(/\\\\u[\\dA-F]{4}/gi, match =>\n    String.fromCharCode(parseInt(match.replace(/\\\\u/g, ''), 16))\n  )\n\nconst configPath = path.join(homedir, '.crd-leetcode.json')\nconst getConfig = () => {\n  try {\n    const config = JSON.parse(fs.readFileSync(configPath))\n    return config\n  } catch (error) {\n    return {\n      country: undefined,\n      cookies: undefined,\n    }\n  }\n}\nconst stringify = data => JSON.stringify(data, null, 2)\n\nconst setConfig = (payload = {}) => {\n  const config = {\n    ...getConfig(),\n    ...payload,\n  }\n  fs.writeFileSync(configPath, stringify(config))\n}\n\nconst removeConfig = (key) => {\n  const config = getConfig()\n  config[key] = undefined\n  fs.writeFileSync(configPath, stringify(config))\n}\n\nconst transformToMarkdownTable = (dataArr) => {\n  let result =\n    '| # | Title | Explanation | Difficulty | Type |' +\n    '\\n' +\n    '|:---:|:---:|:---:|:---:|:---:|'\n\n  for (let i = 0; i < dataArr.length; i++) {\n    result += `\\n| ${dataArr[i].questionId} | [${\n      dataArr[i].title\n    }](https://leetcode.com/problems/${\n      dataArr[i].titleSlug\n    }/) | [Analyze](https://github.com/MuYunyun/blog/blob/main/LeetCode/${\n      dataArr[i].questionId\n    }.${dataArr[i].title.split(' ').join('_')}.md) | ${\n      dataArr[i].difficulty\n    } | ${dataArr[i].topicTags} |`\n  }\n  return result\n}\n\nmodule.exports = {\n  parseCookie,\n  request,\n  getHeaders,\n  unicodeToChar,\n  getConfig,\n  setConfig,\n  removeConfig,\n  stringify,\n  transformToMarkdownTable,\n}\n"
  },
  {
    "path": "utils/uppackage-dev.sh",
    "content": "lerna add $1 --scope=$2 --dev"
  },
  {
    "path": "utils/uppackage.sh",
    "content": "lerna add $1 --scope=$2"
  }
]