├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github └── workflows │ └── docsify-cli.yml ├── .gitignore ├── .gitpod.yml ├── .npmignore ├── .nvmrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── ava.config.js ├── docs ├── .nojekyll ├── CNAME ├── README.md └── index.html ├── e2e ├── cli.test.js ├── cli.test.js.md ├── cli.test.js.snap ├── commands │ ├── generate.test.js │ └── init.test.js └── helpers │ └── test-utils.js ├── lib ├── cli.js ├── commands │ ├── generate.js │ ├── init.js │ ├── serve.js │ └── start.js ├── index.js ├── template │ ├── .nojekyll │ ├── README.md │ ├── index.html │ └── index.local.html └── util │ ├── index.js │ └── logger.js ├── media ├── icon.svg └── screencast.gif ├── package-lock.json ├── package.json ├── rollup.config.js └── tools └── locales ├── de.json ├── en.json ├── index.js └── zh.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "xo-space", 3 | "rules": { 4 | "semi": [2, "never"], 5 | "no-return-assign": "off", 6 | "no-unused-expressions": "off", 7 | "no-new-func": "off", 8 | "no-multi-assign": "off", 9 | "no-mixed-operators": "off", 10 | "max-params": "off", 11 | "no-script-url": "off", 12 | "camelcase": "off", 13 | "no-warning-comments": "off" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/docsify-cli.yml: -------------------------------------------------------------------------------- 1 | name: docsify-cli 2 | 3 | on: 4 | push: 5 | pull_request: 6 | branches: 7 | - master 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: "${{ matrix.os }}" 13 | strategy: 14 | matrix: 15 | os: [ macos-latest, ubuntu-latest, windows-latest ] 16 | node-version: [ 'lts/*' ] 17 | fail-fast: false 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Use Node.js ${{ matrix.node-version }} 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | 26 | - name: Install dependencies 27 | run: npm ci 28 | 29 | - name: Build docsify-cli 30 | run: npm run build 31 | 32 | - name: Run e2e tests 33 | run: npm run test 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | .vscode/ 4 | node_modules/ 5 | yarn.lock 6 | bin/ 7 | test_docs/ 8 | .idea 9 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: npm install && npm run build 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .eslintignore 2 | .eslintrc 3 | .gitignore 4 | .travis.yml 5 | tools/gulp-tasks/ 6 | gulpfile.babel.js 7 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | stable 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [4.4.4](https://github.com/docsifyjs/docsify-cli/compare/v4.4.3...v4.4.4) (2022-03-12) 6 | 7 | 8 | ### Features 9 | 10 | * support docsify init --plugins ([#99](https://github.com/docsifyjs/docsify-cli/issues/99)) ([8bb295c](https://github.com/docsifyjs/docsify-cli/commit/8bb295c54e92b11f61f38ac261c5dabd7da23b51)), closes [/github.com/docsifyjs/docsify-cli/pull/99#discussion_r621952975](https://github.com/docsifyjs//github.com/docsifyjs/docsify-cli/pull/99/issues/discussion_r621952975) 11 | 12 | 13 | ### Bug Fixes 14 | 15 | * package.json & package-lock.json to reduce vulnerabilities ([#161](https://github.com/docsifyjs/docsify-cli/issues/161)) ([e9ea2c1](https://github.com/docsifyjs/docsify-cli/commit/e9ea2c12ee7d27fb8d83299a8ea86b95935615db)) 16 | * Repeat generation and hump naming ([#164](https://github.com/docsifyjs/docsify-cli/issues/164)) ([238326e](https://github.com/docsifyjs/docsify-cli/commit/238326e79a8f5dfbaba86e4e197c05655f5945e1)) 17 | * Support refresh and livereload in serve when using routerMode history ([#166](https://github.com/docsifyjs/docsify-cli/issues/166)) ([625c9f2](https://github.com/docsifyjs/docsify-cli/commit/625c9f201e6dedb62947530c094b1b911b7a18e4)) 18 | 19 | ### [4.4.3](https://github.com/docsifyjs/docsify-cli/compare/v4.4.2...v4.4.3) (2021-03-09) 20 | 21 | 22 | ### Features 23 | 24 | * auto generate sidebar ([#130](https://github.com/docsifyjs/docsify-cli/issues/130)) ([e83bfcb](https://github.com/docsifyjs/docsify-cli/commit/e83bfcbd88b43fa8f13d7db13b801da98cca4aea)) 25 | 26 | ### [4.4.2](https://github.com/docsifyjs/docsify-cli/compare/v4.4.1...v4.4.2) (2020-11-17) 27 | 28 | 29 | ### Features 30 | 31 | * Added asking whether to rewrite files ([#117](https://github.com/docsifyjs/docsify-cli/issues/117)) ([f811906](https://github.com/docsifyjs/docsify-cli/commit/f8119064c54d3ad1817f31be058d25d3384e85c6)) 32 | * Included docsify version in url for the template ([#107](https://github.com/docsifyjs/docsify-cli/issues/107)) ([d92d030](https://github.com/docsifyjs/docsify-cli/commit/d92d03005e4f0188671a212f1eb0abc59f46a0b1)) 33 | 34 | 35 | ### Bug Fixes 36 | 37 | * alias not working ([#125](https://github.com/docsifyjs/docsify-cli/issues/125)) ([f3af553](https://github.com/docsifyjs/docsify-cli/commit/f3af553912b962a132743b03ba56ab292bd1b4b9)) 38 | 39 | ### [4.4.1](https://github.com/QingWei-Li/docsify-cli/compare/v4.4.0...v4.4.1) (2020-06-05) 40 | 41 | 42 | ### Bug Fixes 43 | 44 | * Allow config flag to take a parameter ([9b35260](https://github.com/QingWei-Li/docsify-cli/commit/9b352607d78bf2bbe07fd358ada3ce3c56d3fc29)) 45 | * generate snapshot for default behavior ([3ebfd82](https://github.com/QingWei-Li/docsify-cli/commit/3ebfd82d1e678cc38e3e2f412704e1c0600f8f35)) 46 | * lint ([10c29c9](https://github.com/QingWei-Li/docsify-cli/commit/10c29c9d18a135ed39de2a3fb0524bd81a664f87)) 47 | * lint codebase ([518b3ef](https://github.com/QingWei-Li/docsify-cli/commit/518b3efc897409fbb65bb4dbe2dcab0342eba6ff)) 48 | * lint-staged config ([fa1c125](https://github.com/QingWei-Li/docsify-cli/commit/fa1c1255a167f599bfc2e6f99aec599761966c1f)) 49 | * remove redundant snapshot files ([4f69e30](https://github.com/QingWei-Li/docsify-cli/commit/4f69e30a8b896214fde96eebfa924832ce27cf10)) 50 | * tweak ([959741d](https://github.com/QingWei-Li/docsify-cli/commit/959741d7769431ab3c62aa9be4332289e3a60ee3)) 51 | * tweak ([463f642](https://github.com/QingWei-Li/docsify-cli/commit/463f64275814ff679272a2254e29d43fe1371dd4)) 52 | * typo ([94c60be](https://github.com/QingWei-Li/docsify-cli/commit/94c60be91ed5480576c9573b82dff16b21f1bde0)) 53 | 54 | ## [4.4.0](https://github.com/QingWei-Li/docsify-cli/compare/v4.3.0...v4.4.0) (2019-11-20) 55 | 56 | 57 | ### Features 58 | 59 | * **chore:** show up help if no args were passed ([#72](https://github.com/QingWei-Li/docsify-cli/issues/72)) ([2226057](https://github.com/QingWei-Li/docsify-cli/commit/22260576ef67ab6069873219080afad5257916bd)), closes [#71](https://github.com/QingWei-Li/docsify-cli/issues/71) 60 | * **serve:** add --index-name to rewrite default index name ([#48](https://github.com/QingWei-Li/docsify-cli/issues/48)) ([dc8e993](https://github.com/QingWei-Li/docsify-cli/commit/dc8e9930133f05726712b7392f22cba67e9f5c4f)) 61 | 62 | 63 | ### Bug Fixes 64 | 65 | * **chore:** warn on unknown commands and command recommendation ([#74](https://github.com/QingWei-Li/docsify-cli/issues/74)) ([b46a707](https://github.com/QingWei-Li/docsify-cli/commit/b46a707c528555531bf7cb4ec448f670c20c2210)) 66 | * npm audit issues ([ac1bcc3](https://github.com/QingWei-Li/docsify-cli/commit/ac1bcc36616f295a51843ddd0eebca158a7b6b6a)) 67 | * remove gulp-connect ([032817b](https://github.com/QingWei-Li/docsify-cli/commit/032817b4f6fa512d8d55ba02e18626386a891900)) 68 | 69 | 70 | ## [4.1.9](https://github.com/QingWei-Li/docsify-cli/compare/v4.1.8...v4.1.9) (2017-07-12) 71 | 72 | 73 | ### Performance Improvements 74 | 75 | * **serve:** exclude node_modules from livereload ([#17](https://github.com/QingWei-Li/docsify-cli/issues/17)) ([3f488d0](https://github.com/QingWei-Li/docsify-cli/commit/3f488d0)) 76 | 77 | 78 | 79 | 80 | ## [4.1.8](https://github.com/QingWei-Li/docsify-cli/compare/v4.1.7...v4.1.8) (2017-05-31) 81 | 82 | 83 | 84 | 85 | ## [4.1.7](https://github.com/QingWei-Li/docsify-cli/compare/v4.1.6...v4.1.7) (2017-05-30) 86 | 87 | 88 | ### Bug Fixes 89 | 90 | * **ssr:** clean files ([8e81b1a](https://github.com/QingWei-Li/docsify-cli/commit/8e81b1a)) 91 | 92 | 93 | 94 | 95 | ## [4.1.6](https://github.com/QingWei-Li/docsify-cli/compare/v4.1.5...v4.1.6) (2017-05-30) 96 | 97 | 98 | ### Bug Fixes 99 | 100 | * **ssr:** add debug ([653f24f](https://github.com/QingWei-Li/docsify-cli/commit/653f24f)) 101 | 102 | 103 | 104 | 105 | ## [4.1.5](https://github.com/QingWei-Li/docsify-cli/compare/v4.1.4...v4.1.5) (2017-05-30) 106 | 107 | 108 | ### Bug Fixes 109 | 110 | * **ssr:** missing package ([86e6511](https://github.com/QingWei-Li/docsify-cli/commit/86e6511)) 111 | 112 | 113 | 114 | 115 | ## [4.1.4](https://github.com/QingWei-Li/docsify-cli/compare/v4.1.3...v4.1.4) (2017-05-30) 116 | 117 | 118 | ### Bug Fixes 119 | 120 | * **ssr:** file path ([924a6cf](https://github.com/QingWei-Li/docsify-cli/commit/924a6cf)) 121 | 122 | 123 | 124 | 125 | ## [4.1.3](https://github.com/QingWei-Li/docsify-cli/compare/v4.1.2...v4.1.3) (2017-05-30) 126 | 127 | 128 | ### Bug Fixes 129 | 130 | * update babel config ([49dbfe6](https://github.com/QingWei-Li/docsify-cli/commit/49dbfe6)) 131 | 132 | 133 | 134 | 135 | ## [4.1.2](https://github.com/QingWei-Li/docsify-cli/compare/v4.1.1...v4.1.2) (2017-05-30) 136 | 137 | 138 | ### Bug Fixes 139 | 140 | * update babel config ([7095a0a](https://github.com/QingWei-Li/docsify-cli/commit/7095a0a)) 141 | 142 | 143 | 144 | 145 | ## [4.1.1](https://github.com/QingWei-Li/docsify-cli/compare/v4.1.0...v4.1.1) (2017-05-30) 146 | 147 | 148 | ### Bug Fixes 149 | 150 | * update docsify-server-renderer ([ce7833e](https://github.com/QingWei-Li/docsify-cli/commit/ce7833e)) 151 | 152 | 153 | 154 | 155 | # [4.1.0](https://github.com/QingWei-Li/docsify-cli/compare/v4.0.2...v4.1.0) (2017-05-30) 156 | 157 | 158 | ### Bug Fixes 159 | 160 | * update docsify-server-renderer ([7f56467](https://github.com/QingWei-Li/docsify-cli/commit/7f56467)) 161 | 162 | 163 | ### Features 164 | 165 | * test history mode ([f898a01](https://github.com/QingWei-Li/docsify-cli/commit/f898a01)) 166 | 167 | 168 | 169 | 170 | ## [4.0.2](https://github.com/QingWei-Li/docsify-cli/compare/v4.0.1...v4.0.2) (2017-05-29) 171 | 172 | 173 | ### Bug Fixes 174 | 175 | * remove context ([8b3679f](https://github.com/QingWei-Li/docsify-cli/commit/8b3679f)) 176 | 177 | 178 | 179 | 180 | ## [4.0.1](https://github.com/QingWei-Li/docsify-cli/compare/v4.0.0...v4.0.1) (2017-05-29) 181 | 182 | 183 | ### Bug Fixes 184 | 185 | * path => context ([d83fa69](https://github.com/QingWei-Li/docsify-cli/commit/d83fa69)) 186 | 187 | 188 | 189 | 190 | # [4.0.0](https://github.com/QingWei-Li/docsify-cli/compare/v3.3.2...v4.0.0) (2017-05-29) 191 | 192 | 193 | ### Features 194 | 195 | * add start command ([#14](https://github.com/QingWei-Li/docsify-cli/issues/14)) ([feefcce](https://github.com/QingWei-Li/docsify-cli/commit/feefcce)) 196 | 197 | 198 | 199 | 200 | ## [3.3.2](https://github.com/QingWei-Li/docsify-cli/compare/v3.3.1...v3.3.2) (2017-04-28) 201 | 202 | 203 | 204 | 205 | ## [3.3.1](https://github.com/QingWei-Li/docsify-cli/compare/v3.3.0...v3.3.1) (2017-03-26) 206 | 207 | 208 | 209 | 210 | # [3.3.0](https://github.com/QingWei-Li/docsify-cli/compare/v3.2.5...v3.3.0) (2017-03-24) 211 | 212 | 213 | ### Bug Fixes 214 | 215 | * pkg.engines ([3e50f07](https://github.com/QingWei-Li/docsify-cli/commit/3e50f07)) 216 | * **template:** update template ([da67d07](https://github.com/QingWei-Li/docsify-cli/commit/da67d07)) 217 | 218 | 219 | ### Features 220 | 221 | * **dev:** add gulp tasks ([76f0193](https://github.com/QingWei-Li/docsify-cli/commit/76f0193)) 222 | 223 | 224 | 225 | 226 | ## [3.2.5](https://github.com/QingWei-Li/docsify-cli/compare/v3.2.4...v3.2.5) (2017-03-23) 227 | 228 | 229 | 230 | 231 | ## [3.2.4](https://github.com/QingWei-Li/docsify-cli/compare/v3.2.3...v3.2.4) (2017-03-19) 232 | 233 | 234 | ### Bug Fixes 235 | 236 | * **grammar:** isOpen --> openInBrowser ([d823a07](https://github.com/QingWei-Li/docsify-cli/commit/d823a07)) 237 | * travis-ci ([a313412](https://github.com/QingWei-Li/docsify-cli/commit/a313412)) 238 | 239 | 240 | ### Features 241 | 242 | * **cli:** print shell completion script ([804639e](https://github.com/QingWei-Li/docsify-cli/commit/804639e)) 243 | * **cli:** support completion rules ([fb31bd5](https://github.com/QingWei-Li/docsify-cli/commit/fb31bd5)) 244 | 245 | 246 | 247 | 248 | ## [3.2.3](https://github.com/QingWei-Li/docsify-cli/compare/v3.2.2...v3.2.3) (2017-03-17) 249 | 250 | 251 | 252 | 253 | ## [3.2.2](https://github.com/QingWei-Li/docsify-cli/compare/v3.2.1...v3.2.2) (2017-03-17) 254 | 255 | 256 | 257 | 258 | ## [3.2.1](https://github.com/QingWei-Li/docsify-cli/compare/v3.2.0...v3.2.1) (2017-03-15) 259 | 260 | 261 | 262 | 263 | # [3.2.0](https://github.com/QingWei-Li/docsify-cli/compare/v3.1.1...v3.2.0) (2017-03-15) 264 | 265 | 266 | 267 | 268 | ## [3.1.1](https://github.com/QingWei-Li/docsify-cli/compare/v3.1.0...v3.1.1) (2017-03-14) 269 | 270 | 271 | ### Bug Fixes 272 | 273 | * default print help info ([54567bc](https://github.com/QingWei-Li/docsify-cli/commit/54567bc)) 274 | 275 | 276 | 277 | 278 | # [3.1.0](https://github.com/QingWei-Li/docsify-cli/compare/v3.0.2...v3.1.0) (2017-03-14) 279 | 280 | 281 | ### Features 282 | 283 | * **locale:** add zh-cn ([2c5e19f](https://github.com/QingWei-Li/docsify-cli/commit/2c5e19f)) 284 | 285 | 286 | 287 | 288 | ## [3.0.2](https://github.com/QingWei-Li/docsify-cli/compare/v3.0.1...v3.0.2) (2017-03-10) 289 | 290 | 291 | 292 | 293 | ## [3.0.1](https://github.com/QingWei-Li/docsify-cli/compare/v3.0.0...v3.0.1) (2017-02-19) 294 | 295 | 296 | 297 | 298 | # [3.0.0](https://github.com/QingWei-Li/docsify-cli/compare/v2.1.0...v3.0.0) (2017-02-19) 299 | 300 | 301 | 302 | 303 | # [2.1.0](https://github.com/QingWei-Li/docsify-cli/compare/v2.0.0...v2.1.0) (2017-02-09) 304 | 305 | 306 | ### Features 307 | 308 | * add livereload ([661cbe2](https://github.com/QingWei-Li/docsify-cli/commit/661cbe2)) 309 | 310 | 311 | 312 | 313 | # [2.0.0](https://github.com/QingWei-Li/docsify-cli/compare/v1.5.1...v2.0.0) (2017-02-05) 314 | 315 | 316 | 317 | 318 | ## [1.5.1](https://github.com/QingWei-Li/docsify-cli/compare/v1.5.0...v1.5.1) (2017-01-24) 319 | 320 | 321 | 322 | 323 | # [1.5.0](https://github.com/QingWei-Li/docsify-cli/compare/v1.4.0...v1.5.0) (2017-01-24) 324 | 325 | 326 | 327 | 328 | # [1.4.0](https://github.com/QingWei-Li/docsify-cli/compare/v1.3.0...v1.4.0) (2017-01-14) 329 | 330 | 331 | 332 | 333 | # [1.3.0](https://github.com/QingWei-Li/docsify-cli/compare/v1.2.1...v1.3.0) (2017-01-13) 334 | 335 | 336 | 337 | 338 | ## [1.2.1](https://github.com/QingWei-Li/docsify-cli/compare/v1.2.0...v1.2.1) (2016-12-24) 339 | 340 | 341 | 342 | 343 | # [1.2.0](https://github.com/QingWei-Li/docsify-cli/compare/v1.1.1...v1.2.0) (2016-12-24) 344 | 345 | 346 | 347 | 348 | ## [1.1.1](https://github.com/QingWei-Li/docsify-cli/compare/v1.1.0...v1.1.1) (2016-12-19) 349 | 350 | 351 | 352 | 353 | # [1.1.0](https://github.com/QingWei-Li/docsify-cli/compare/v1.0.0...v1.1.0) (2016-12-18) 354 | 355 | 356 | 357 | 358 | # [1.0.0](https://github.com/QingWei-Li/docsify-cli/compare/v0.2.2...v1.0.0) (2016-12-08) 359 | 360 | 361 | 362 | 363 | ## [0.2.2](https://github.com/QingWei-Li/docsify-cli/compare/v0.2.1...v0.2.2) (2016-11-28) 364 | 365 | 366 | 367 | 368 | ## [0.2.1](https://github.com/QingWei-Li/docsify-cli/compare/v0.1.0...v0.2.1) (2016-11-27) 369 | 370 | 371 | 372 | 373 | # 0.1.0 (2016-11-24) 374 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the development of `docsify-cli` 2 | 3 | - Fork the repository on Github. 4 | - Clone the repository locally. 5 | - Make your changes to the code. 6 | - Run `npm install`. 7 | - Run `npm link` which creates a symlink and thereby `docsify` can be accessed globally. 8 | - We use [commitlint conventional naming rules](https://www.npmjs.com/package/@commitlint/config-conventional#rules) for our commits, make sure that you follow them. 9 | - Push to Github and open a pull request. 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 cinwell.li 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | docsify 4 | 5 |

6 | 7 |

8 | 🖌 docsify cli - A magical documentation generator. 9 |

10 | 11 |

12 | Backers on Open Collective 13 | Sponsors on Open Collective 14 | npm 15 | Github Actions Status 16 | Join Discord community and chat about Docsify 17 | license 18 | npm-total-download 19 | npm-monthly-download 20 | 21 |

22 | 23 |

Gold Sponsor via Open Collective

24 | 25 |

26 | 27 | 28 | 29 |

30 | 31 | ## Screencast 32 | 33 | ![Screencast](https://raw.githubusercontent.com/docsifyjs/docsify-cli/master/media/screencast.gif) 34 | 35 | > Running a server on `localhost` with live-reload. 36 | 37 | ## Installation 38 | 39 | Install `docsify-cli` via `npm` or `yarn` globally. 40 | 41 | ```shell 42 | npm i docsify-cli -g 43 | # yarn global add docsify-cli 44 | ``` 45 | 46 | ## Usage 47 | 48 | ### `init` command 49 | 50 | Use `init` to generate your docs. 51 | 52 | ```shell 53 | docsify init [path] [--local false] [--theme vue] [--plugins false] 54 | 55 | # docsify i [path] [-l false] [-t vue] [--plugins false] 56 | ``` 57 | 58 | `[path]` defaults to the current directory. Use relative paths like `./docs` (or `docs`). 59 | 60 | - `--local` option: 61 | - Shorthand: `-l` 62 | - Type: boolean 63 | - Default: `false` 64 | - Description: Copy `docsify` files to the docs path, defaults to `false` using `cdn.jsdelivr.net` as the content delivery network (CDN). To explicitly set this option to `false` use `--no-local`. 65 | - `--theme` option: 66 | - Shorthand: `-t` 67 | - Type: string 68 | - Default: `vue` 69 | - Description: Choose a theme, defaults to `vue`, other choices are `buble`, `dark` and `pure`. 70 | - `--plugins` option: 71 | - Shorthand: `-p` 72 | - Type: boolean 73 | - Default: `false` 74 | - Description: Provide a list of plugins to insert as ` 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /e2e/cli.test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const test = require('ava') 4 | 5 | const {run} = require('./helpers/test-utils.js') 6 | 7 | test('shows up help message without any args', t => { 8 | const {stderr} = run([], {reject: false}) 9 | t.snapshot(stderr) 10 | }) 11 | 12 | const matchSnapshot = (t, arg) => { 13 | const {stdout} = run([arg]) 14 | t.snapshot(stdout) 15 | } 16 | 17 | test('shows help with -h flag', matchSnapshot, '-h') 18 | test('shows help with --help flag', matchSnapshot, '--help') 19 | test('shows version information with -v flag', matchSnapshot, '-v') 20 | test('shows version information with --version flag', matchSnapshot, '--version') 21 | 22 | test('rejects promise due to error on passing in an unknown command', t => { 23 | const {stderr} = run(['junkcmd'], {reject: false}) 24 | t.snapshot(stderr) 25 | }) 26 | -------------------------------------------------------------------------------- /e2e/cli.test.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `e2e/cli.test.js` 2 | 3 | The actual snapshot is saved in `cli.test.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## shows up help message without any args 8 | 9 | > Snapshot 1 10 | 11 | `Usage: docsify [path]␊ 12 | ␊ 13 | Commands:␊ 14 | docsify init [path] Creates new docs [aliases: i]␊ 15 | docsify serve [path] Run local server to preview site. [aliases: s]␊ 16 | docsify start [path] Server for SSR␊ 17 | docsify generate [path] Docsify's generators [aliases: g]␊ 18 | ␊ 19 | Global Options␊ 20 | --help, -h Show help [boolean]␊ 21 | --version, -v Show version number [boolean]␊ 22 | ␊ 23 | Documentation:␊ 24 | https://docsifyjs.github.io/docsify␊ 25 | https://docsifyjs.github.io/docsify-cli␊ 26 | ␊ 27 | Development:␊ 28 | https://github.com/docsifyjs/docsify-cli/blob/master/CONTRIBUTING.md␊ 29 | ␊ 30 | [ERROR] 0 arguments passed. Please specify a command` 31 | 32 | ## shows help with -h flag 33 | 34 | > Snapshot 1 35 | 36 | `Usage: docsify [path]␊ 37 | ␊ 38 | Commands:␊ 39 | docsify init [path] Creates new docs [aliases: i]␊ 40 | docsify serve [path] Run local server to preview site. [aliases: s]␊ 41 | docsify start [path] Server for SSR␊ 42 | docsify generate [path] Docsify's generators [aliases: g]␊ 43 | ␊ 44 | Global Options␊ 45 | --help, -h Show help [boolean]␊ 46 | --version, -v Show version number [boolean]␊ 47 | ␊ 48 | Documentation:␊ 49 | https://docsifyjs.github.io/docsify␊ 50 | https://docsifyjs.github.io/docsify-cli␊ 51 | ␊ 52 | Development:␊ 53 | https://github.com/docsifyjs/docsify-cli/blob/master/CONTRIBUTING.md` 54 | 55 | ## shows help with --help flag 56 | 57 | > Snapshot 1 58 | 59 | `Usage: docsify [path]␊ 60 | ␊ 61 | Commands:␊ 62 | docsify init [path] Creates new docs [aliases: i]␊ 63 | docsify serve [path] Run local server to preview site. [aliases: s]␊ 64 | docsify start [path] Server for SSR␊ 65 | docsify generate [path] Docsify's generators [aliases: g]␊ 66 | ␊ 67 | Global Options␊ 68 | --help, -h Show help [boolean]␊ 69 | --version, -v Show version number [boolean]␊ 70 | ␊ 71 | Documentation:␊ 72 | https://docsifyjs.github.io/docsify␊ 73 | https://docsifyjs.github.io/docsify-cli␊ 74 | ␊ 75 | Development:␊ 76 | https://github.com/docsifyjs/docsify-cli/blob/master/CONTRIBUTING.md` 77 | 78 | ## shows version information with -v flag 79 | 80 | > Snapshot 1 81 | 82 | `␊ 83 | docsify-cli version:␊ 84 | 4.4.4␊ 85 | ` 86 | 87 | ## shows version information with --version flag 88 | 89 | > Snapshot 1 90 | 91 | `␊ 92 | docsify-cli version:␊ 93 | 4.4.4␊ 94 | ` 95 | 96 | ## rejects promise due to error on passing in an unknown command 97 | 98 | > Snapshot 1 99 | 100 | `Usage: docsify [path]␊ 101 | ␊ 102 | Commands:␊ 103 | docsify init [path] Creates new docs [aliases: i]␊ 104 | docsify serve [path] Run local server to preview site. [aliases: s]␊ 105 | docsify start [path] Server for SSR␊ 106 | docsify generate [path] Docsify's generators [aliases: g]␊ 107 | ␊ 108 | Global Options␊ 109 | --help, -h Show help [boolean]␊ 110 | --version, -v Show version number [boolean]␊ 111 | ␊ 112 | Documentation:␊ 113 | https://docsifyjs.github.io/docsify␊ 114 | https://docsifyjs.github.io/docsify-cli␊ 115 | ␊ 116 | Development:␊ 117 | https://github.com/docsifyjs/docsify-cli/blob/master/CONTRIBUTING.md␊ 118 | ␊ 119 | Unknown argument: junkcmd` 120 | -------------------------------------------------------------------------------- /e2e/cli.test.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docsifyjs/docsify-cli/c74c3d280b2c70b20bd8176e021ee78ec4e5bcdf/e2e/cli.test.js.snap -------------------------------------------------------------------------------- /e2e/commands/generate.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const fs = require('fs') 3 | const path = require('path') 4 | 5 | const {run} = require('../helpers/test-utils.js') 6 | 7 | const genPath = path.join(__dirname, 'generate-cmd') 8 | const docsPath = path.join(genPath, 'docs') 9 | 10 | test.before('create temp directory', () => { 11 | // Cleanup if the directory already exists 12 | if (fs.existsSync(genPath)) { 13 | fs.rmSync(genPath, {recursive: true}) 14 | } 15 | 16 | fs.mkdirSync(genPath) 17 | }) 18 | 19 | test.after('cleanup', () => { 20 | fs.rmSync(genPath, {recursive: true}) 21 | }) 22 | 23 | test('generate _sidebar.md', t => { 24 | run(['init', 'docs'], {cwd: genPath}) 25 | run(['generate', 'docs'], {cwd: genPath}) 26 | // Check for existence 27 | t.true(fs.existsSync(path.join(docsPath, '_sidebar.md'))) 28 | 29 | const {exitCode, stderr} = run(['generate', 'docs'], { 30 | cwd: genPath, 31 | reject: false 32 | }) 33 | t.is(exitCode, 1) 34 | t.is(stderr, 'The sidebar file \'_sidebar.md\' already exists.') 35 | }) 36 | -------------------------------------------------------------------------------- /e2e/commands/init.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const fs = require('fs') 3 | const path = require('path') 4 | const {ENTER} = require('cli-prompts-test') 5 | 6 | const {run, runPromptWithAnswers} = require('../helpers/test-utils.js') 7 | 8 | const genPath = path.join(__dirname, 'init-cmd') 9 | const docsPath = path.join(genPath, 'docs') 10 | 11 | test.before('create temp directory', () => { 12 | // Cleanup if the directory already exists 13 | if (fs.existsSync(genPath)) { 14 | fs.rmSync(genPath, {recursive: true}) 15 | } 16 | 17 | fs.mkdirSync(genPath) 18 | }) 19 | 20 | test.after('cleanup', () => { 21 | fs.rmSync(genPath, {recursive: true}) 22 | }) 23 | 24 | test('generates docs directory', t => { 25 | const {exitCode} = run(['init', 'docs'], {cwd: genPath}) 26 | 27 | // Assert for exit code 28 | t.is(exitCode, 0) 29 | 30 | // Check for existence 31 | t.true(fs.existsSync(path.join(docsPath, 'README.md'))) 32 | t.true(fs.existsSync(path.join(docsPath, 'index.html'))) 33 | }) 34 | 35 | test('force generates docs directory with --local flag', async t => { 36 | const {exitCode} = await runPromptWithAnswers( 37 | ['init', 'docs', '--local'], 38 | ['y', ENTER], 39 | genPath 40 | ) 41 | t.is(exitCode, 0) 42 | t.true(fs.existsSync(path.join(docsPath, 'vendor'))) 43 | }) 44 | -------------------------------------------------------------------------------- /e2e/helpers/test-utils.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa') 2 | const path = require('path') 3 | const runTest = require('cli-prompts-test') 4 | 5 | const CLI_PATH = path.join(__dirname, '..', '..', 'bin', 'docsify') 6 | 7 | const run = (args, options = {}) => execa.sync(CLI_PATH, args, options) 8 | 9 | const runPromptWithAnswers = (args, answers, testPath) => { 10 | return runTest([CLI_PATH].concat(args), answers, { 11 | testPath 12 | }) 13 | } 14 | 15 | module.exports = { 16 | run, 17 | runPromptWithAnswers 18 | } 19 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const updateNotifier = require('update-notifier') 3 | 4 | const pkg = require('../package.json') 5 | const run = require('../lib') 6 | 7 | updateNotifier({pkg: pkg}).notify() 8 | 9 | const Locales = require('../tools/locales') 10 | const y18n = new Locales() 11 | 12 | require('yargonaut') 13 | .style('yellow', 'required') 14 | .helpStyle('green') 15 | .errorsStyle('red.bold') 16 | 17 | require('yargs') 18 | .demandCommand(1, chalk.red('[ERROR] 0 arguments passed. Please specify a command')) 19 | .strict() 20 | .recommendCommands() 21 | .usage(chalk.bold(y18n.__('usage') + ': docsify [path]')) 22 | .command({ 23 | command: 'init [path]', 24 | aliases: 'i', 25 | desc: chalk.gray(y18n.__('init')), 26 | builder: yargs => 27 | yargs.options({ 28 | local: { 29 | alias: 'l', 30 | default: false, 31 | desc: chalk.gray(y18n.__('init.local')), 32 | nargs: 0, 33 | requiresArg: false, 34 | type: 'boolean' 35 | }, 36 | theme: { 37 | alias: 't', 38 | default: 'vue', 39 | desc: chalk.gray(y18n.__('init.theme')), 40 | choices: ['vue', 'buble', 'dark', 'pure'], 41 | nargs: 1, 42 | requiresArg: true, 43 | type: 'string' 44 | }, 45 | plugins: { 46 | alias: 'p', 47 | default: false, 48 | desc: chalk.gray(y18n.__('init.plugins')), 49 | nargs: 0, 50 | requiresArg: false, 51 | type: 'boolean' 52 | } 53 | }), 54 | handler: argv => run.init(argv.path, argv.local, argv.theme, argv.plugins) 55 | }) 56 | .command({ 57 | command: 'serve [path]', 58 | aliases: 's', 59 | desc: chalk.gray(y18n.__('serve')), 60 | builder: yargs => 61 | yargs.options({ 62 | open: { 63 | alias: 'o', 64 | default: false, 65 | desc: chalk.gray(y18n.__('serve.open')), 66 | nargs: 0, 67 | requiresArg: false, 68 | type: 'boolean' 69 | }, 70 | port: { 71 | alias: 'p', 72 | default: 3000, 73 | desc: chalk.gray(y18n.__('serve.port')), 74 | nargs: 1, 75 | requiresArg: true, 76 | type: 'number' 77 | }, 78 | 'livereload-port': { 79 | alias: 'P', 80 | default: 35729, 81 | desc: chalk.gray(y18n.__('livereload.port')), 82 | nargs: 1, 83 | requiresArg: true, 84 | type: 'number' 85 | }, 86 | 'index-name': { 87 | alias: 'i', 88 | desc: chalk.gray(y18n.__('serve.indexname')), 89 | nargs: 1, 90 | requiresArg: true, 91 | type: 'string' 92 | } 93 | }), 94 | handler: argv => run.serve(argv.path, argv.open, argv.port, argv.P, argv.i) 95 | }) 96 | .command({ 97 | command: 'start [path]', 98 | desc: chalk.gray(y18n.__('start')), 99 | builder: yargs => 100 | yargs.options({ 101 | config: { 102 | alias: 'c', 103 | default: false, 104 | desc: chalk.gray(y18n.__('start.config')), 105 | nargs: 1, 106 | requiresArg: false, 107 | type: 'string' 108 | }, 109 | port: { 110 | alias: 'p', 111 | default: 4000, 112 | desc: chalk.gray(y18n.__('start.port')), 113 | nargs: 1, 114 | requiresArg: true, 115 | type: 'number' 116 | } 117 | }), 118 | handler: argv => run.start(argv.path, argv.config, argv.port) 119 | }) 120 | .command({ 121 | command: 'generate [path]', 122 | aliases: 'g', 123 | desc: chalk.gray(y18n.__('generate')), 124 | builder: yargs => 125 | yargs.options({ 126 | overwrite: { 127 | alias: 'o', 128 | default: false, 129 | desc: chalk.gray(y18n.__('generate.overwrite')), 130 | nargs: 0, 131 | type: 'boolean' 132 | }, 133 | sidebar: { 134 | alias: 's', 135 | default: '_sidebar.md', 136 | desc: chalk.gray(y18n.__('generate.sidebar')), 137 | nargs: 1, 138 | requiresArg: true, 139 | type: 'string' 140 | } 141 | }), 142 | handler: argv => run.generate(argv.path, argv.sidebar, {overwrite: argv.overwrite}) 143 | }) 144 | .help() 145 | .option('help', { 146 | alias: 'h', 147 | type: 'boolean', 148 | desc: chalk.gray(y18n.__('help')), 149 | group: chalk.green(y18n.__('group.globaloptions')) 150 | }) 151 | .version('\ndocsify-cli version:\n ' + pkg.version + '\n') 152 | .option('version', { 153 | alias: 'v', 154 | type: 'boolean', 155 | desc: chalk.gray(y18n.__('version')), 156 | group: chalk.green(y18n.__('group.globaloptions')) 157 | }) 158 | .epilog(chalk.gray(y18n.__('epilog'))).argv 159 | -------------------------------------------------------------------------------- /lib/commands/generate.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fs = require('fs') 4 | const os = require('os') 5 | const {cwd, exists} = require('../util') 6 | const path = require('path') 7 | const logger = require('../util/logger') 8 | const ignoreFiles = ['_navbar', '_coverpage', '_sidebar'] 9 | 10 | module.exports = function (path, sidebar, options) { 11 | const cwdPath = cwd(path || '.') 12 | 13 | if (exists(cwdPath)) { 14 | if (sidebar) { 15 | const sidebarPath = cwdPath + '/' + sidebar || '_sidebar.md' 16 | 17 | if (!exists(sidebarPath) || options.overwrite) { 18 | genSidebar(cwdPath, sidebarPath) 19 | logger.success(`Successfully generated the sidebar file '${sidebar}'.`) 20 | return true 21 | } 22 | 23 | logger.error(`The sidebar file '${sidebar}' already exists.`) 24 | process.exitCode = 1 25 | return false 26 | } 27 | } 28 | 29 | logger.error(`${cwdPath} directory does not exist.`) 30 | } 31 | 32 | function genSidebar(cwdPath, sidebarPath) { 33 | let tree = '' 34 | let lastPath = '' 35 | let nodeName = '' 36 | getDirFiles(cwdPath, function (pathname) { 37 | path.relative(pathname, cwdPath) 38 | pathname = pathname.replace(cwdPath + path.sep, '') 39 | let filename = path.basename(pathname, '.md') 40 | let splitPath = pathname.split(path.sep) 41 | 42 | if (ignoreFiles.indexOf(filename) !== -1) { 43 | return true 44 | } 45 | 46 | nodeName = '- [' + toCamelCase(filename) + '](' + pathname.replace(/\\/g, '/') + ')' + os.EOL 47 | 48 | if (splitPath.length > 1) { 49 | if (splitPath[0] !== lastPath) { 50 | lastPath = splitPath[0] 51 | tree += os.EOL + '- ' + toCamelCase(splitPath[0]) + os.EOL 52 | } 53 | 54 | tree += ' ' + nodeName 55 | } else { 56 | if (lastPath !== '') { 57 | lastPath = '' 58 | tree += os.EOL 59 | } 60 | 61 | tree += nodeName 62 | } 63 | }) 64 | fs.writeFile(sidebarPath, tree, 'utf8', err => { 65 | if (err) { 66 | logger.error(`Couldn't generate the sidebar file, error: ${err.message}`) 67 | } 68 | }) 69 | } 70 | 71 | function getDirFiles(dir, callback) { 72 | fs.readdirSync(dir).forEach(function (file) { 73 | let pathname = path.join(dir, file) 74 | 75 | if (fs.statSync(pathname).isDirectory()) { 76 | getDirFiles(pathname, callback) 77 | } else if (path.extname(file) === '.md') { 78 | callback(pathname) 79 | } 80 | }) 81 | } 82 | 83 | function toCamelCase(str) { 84 | return str.replace(/\b(\w)/g, function (match, capture) { 85 | return capture.toUpperCase() 86 | }).replace(/-|_/g, ' ') 87 | } 88 | -------------------------------------------------------------------------------- /lib/commands/init.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fs = require('fs') 4 | const cp = require('cp-file').sync 5 | const chalk = require('chalk') 6 | const {version} = require('../../package.json') 7 | const logger = require('../util/logger') 8 | const {prompt, MultiSelect} = require('enquirer') 9 | const {cwd, exists, pkg, pwd, read, resolve} = require('../util') 10 | const colors = require('ansi-colors') 11 | 12 | const replace = function (file, tpl, replace) { 13 | fs.writeFileSync(file, read(file).replace(tpl, replace), 'utf-8') 14 | } 15 | 16 | // eslint-disable-next-line 17 | module.exports = async function (path = '', local, theme, plugins) { 18 | const msg = 19 | '\n' + 20 | chalk.green('Initialization succeeded!') + 21 | ' Please run ' + 22 | chalk.inverse(`docsify serve ${path}`) + 23 | '\n' 24 | 25 | const cwdPath = cwd(path || '.') 26 | 27 | if (exists(cwdPath)) { 28 | logger.error(`${path || '.'} already exists.`) 29 | 30 | let answer = {} 31 | try { 32 | answer = await prompt({ 33 | type: 'confirm', 34 | name: 'rewrite', 35 | symbols: { 36 | separator: '' 37 | }, 38 | message: 'Are you sure you want to rewrite it?' 39 | }) 40 | } catch (err) { 41 | err && logger.error(err) 42 | process.exit(1) 43 | } 44 | 45 | if (!answer.rewrite) { 46 | return 47 | } 48 | } 49 | 50 | await createFile(cwdPath, local, theme, plugins) 51 | console.log(msg) 52 | } 53 | 54 | async function createFile(path, local, theme, plugins) { 55 | const target = file => resolve(path, file) 56 | const readme = exists(cwd('README.md')) || pwd('template/README.md') 57 | let main = pwd('template/index.html') 58 | 59 | if (local) { 60 | main = pwd('template/index.local.html') 61 | 62 | const vendor = 63 | exists(cwd('node_modules/docsify')) || pwd('../node_modules/docsify') 64 | 65 | cp(resolve(vendor, 'lib/docsify.min.js'), target('vendor/docsify.js')) 66 | cp( 67 | resolve(vendor, `lib/themes/${theme}.css`), 68 | target(`vendor/themes/${theme}.css`) 69 | ) 70 | } 71 | 72 | const filename = 'index.html' 73 | 74 | cp(readme, target('README.md')) 75 | cp(main, target(filename)) 76 | cp(pwd('template/.nojekyll'), target('.nojekyll')) 77 | 78 | replace(target(filename), 'vue.css', `${theme}.css`) 79 | 80 | if (pkg.name) { 81 | replace( 82 | target(filename), 83 | 'Document', 84 | pkg.name + (pkg.description ? ' - ' + pkg.description : '') 85 | ) 86 | replace(target(filename), 'name: \'\',', `name: '${pkg.name}',`) 87 | } 88 | 89 | if (pkg.description) { 90 | replace(target(filename), 'Description', pkg.description) 91 | } 92 | 93 | if (pkg.repository) { 94 | const repo = (pkg.repository.url || pkg.repository) 95 | .replace(/\.git$/g, '') 96 | .replace(/^git\+/g, '') 97 | replace(target(filename), 'repo: \'\'', `repo: '${repo}'`) 98 | } 99 | 100 | // Return early if not opted for plugins 101 | if (!plugins) { 102 | return replace(target(filename), '\n _plugins_', '') 103 | } 104 | 105 | const officialPlugins = [ 106 | 'front-matter', 107 | 'search', 108 | 'disqus', 109 | 'emoji', 110 | 'external-script', 111 | 'ga', 112 | 'gitalk', 113 | 'matomo', 114 | 'zoom-image' 115 | ] 116 | 117 | const choices = officialPlugins.map(name => ({name, value: name})) 118 | const prompt = new MultiSelect({ 119 | name: 'plugins', 120 | message: 'Select plugins to be used', 121 | hint: '(Use to select, to submit)', 122 | default: '', 123 | choices, 124 | indicator(state, choice) { 125 | if (choice.enabled) { 126 | return colors.cyan(state.symbols.radio.on) 127 | } 128 | 129 | return colors.gray(state.symbols.radio.off) 130 | } 131 | }) 132 | 133 | prompt.on('cancel', () => replace(target(filename), '\n _plugins_', '')) 134 | 135 | let answers = [] 136 | try { 137 | answers = await prompt.run() 138 | } catch (err) { 139 | if (err) { 140 | logger.error(err) 141 | process.exitCode = 1 142 | } 143 | 144 | return 145 | } 146 | 147 | replace(target(filename), ' _plugins_', '_plugin'.repeat(answers.length + 1)) 148 | 149 | answers.forEach(plugin => { 150 | const url = `//cdn.jsdelivr.net/npm/docsify@${version[0]}/lib/plugins/${plugin}.min.js` 151 | replace(target(filename), '_plugin', ` \n`) 152 | }) 153 | 154 | replace(target(filename), '\n_plugin', '') 155 | } 156 | -------------------------------------------------------------------------------- /lib/commands/serve.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const serveStatic = require('serve-static') 4 | const connect = require('connect') 5 | const livereload = require('connect-livereload') 6 | const history = require('connect-history-api-fallback') 7 | const lrserver = require('livereload') 8 | const open = require('open') 9 | const chalk = require('chalk') 10 | const logger = require('../util/logger') 11 | const {exists, resolve} = require('../util') 12 | const getPort = require('get-port') 13 | 14 | module.exports = function ( 15 | path, 16 | openInBrowser, 17 | port, 18 | livereloadPort, 19 | indexName 20 | ) { 21 | getPort({port}) 22 | .then(p => { 23 | port = p 24 | return getPort({port: livereloadPort}) 25 | }) 26 | .then(p => { 27 | livereloadPort = p 28 | }) 29 | .then(_ => { 30 | path = resolve(path || '.') 31 | const indexFileName = indexName || 'index.html' 32 | const indexFile = resolve(path, indexFileName) 33 | 34 | if (!exists(indexFile)) { 35 | const msg = 36 | '\nNo docs found ' + 37 | indexFile + 38 | '\nPlease run ' + 39 | chalk.green('docsify init') + 40 | ' first.\n' 41 | console.log(msg) 42 | process.exit(0) 43 | } 44 | 45 | const server = connect() 46 | server.use( 47 | livereload({ 48 | port: livereloadPort 49 | }) 50 | ) 51 | server.use(history({index: '/' + indexFileName})) 52 | server.use(serveStatic(path, {index: indexName})) 53 | server.listen(port) 54 | lrserver 55 | .createServer({ 56 | extraExts: ['md'], 57 | exclusions: ['node_modules/'], 58 | port: livereloadPort 59 | }) 60 | .watch(path) 61 | 62 | if (openInBrowser) { 63 | open(`http://localhost:${port}`) 64 | } 65 | 66 | const msg = 67 | '\nServing ' + 68 | chalk.green(`${path}`) + 69 | ' now.\n' + 70 | 'Listening at ' + 71 | chalk.green(`http://localhost:${port}`) + 72 | '\n' 73 | console.log(msg) 74 | }) 75 | .catch(err => { 76 | logger.error(err.message) 77 | }) 78 | } 79 | -------------------------------------------------------------------------------- /lib/commands/start.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const connect = require('connect') 4 | const serveStatic = require('serve-static') 5 | const Renderer = require('docsify-server-renderer') 6 | const util = require('../util') 7 | const chalk = require('chalk') 8 | const logger = require('../util/logger') 9 | const LRU = require('lru-cache') 10 | 11 | const defaultConfig = { 12 | template: ` 13 | 14 | 15 | 16 | My Doc 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ` 27 | } 28 | 29 | function loadConfig(config) { 30 | try { 31 | return require(util.cwd(config)) 32 | } catch (e) { 33 | logger.error(`${e.message} in ${config}`) 34 | process.exit(1) 35 | } 36 | } 37 | 38 | module.exports = function (path, configFile, port) { 39 | let config = defaultConfig 40 | const pkg = util.pkg() 41 | const ctx = util.cwd('.') 42 | 43 | path = path || './' 44 | 45 | if (configFile) { 46 | config = loadConfig(configFile) 47 | config.template = /\.html$/.test(config.template) ? 48 | util.read(util.resolve(ctx, config.template)) : 49 | defaultConfig.template 50 | } else if (pkg.docsify) { 51 | const tpl = pkg.docsify.template 52 | 53 | config = pkg.docsify 54 | config.template = 55 | tpl && util.exists(util.resolve(ctx, tpl)) ? 56 | util.read(tpl) : 57 | defaultConfig.template 58 | } 59 | 60 | const renderer = new Renderer(Object.assign(defaultConfig, config)) 61 | const server = connect() 62 | const cached = new LRU(config.maxAge || 0) 63 | 64 | server.use(serveStatic(path)) 65 | server.use(function (req, res) { 66 | serveStatic(path)(req, res, function () { 67 | if ( 68 | /\.(jpg|jpeg|gif|png|svg|ico|mp4|webm|ogg|ogv|js|css|md)(?:\?v=[0-9.]+)?$/.test( 69 | req.url 70 | ) 71 | ) { 72 | res.writeHead(404) 73 | res.end() 74 | } 75 | 76 | Promise.resolve(cached.get(req.url) || renderer.renderToString(req.url)) 77 | .then(function (html) { 78 | cached.set(req.url) 79 | res.end(html) 80 | }) 81 | .catch(function (err) { 82 | logger.error(err) 83 | res.writeHead(404) 84 | res.end() 85 | }) 86 | }) 87 | }) 88 | server.listen(port || 4000) 89 | 90 | const msg = 91 | '\n' + 92 | chalk.blue('[SSR]') + 93 | ' Serving ' + 94 | chalk.green(`${path}`) + 95 | ' now.\n' + 96 | 'Listening at ' + 97 | chalk.green(`http://localhost:${port}`) + 98 | '\n' 99 | 100 | console.log(msg) 101 | } 102 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | init: require('./commands/init'), 3 | serve: require('./commands/serve'), 4 | start: require('./commands/start'), 5 | generate: require('./commands/generate') 6 | } 7 | -------------------------------------------------------------------------------- /lib/template/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docsifyjs/docsify-cli/c74c3d280b2c70b20bd8176e021ee78ec4e5bcdf/lib/template/.nojekyll -------------------------------------------------------------------------------- /lib/template/README.md: -------------------------------------------------------------------------------- 1 | # Headline 2 | 3 | > An awesome project. 4 | -------------------------------------------------------------------------------- /lib/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 19 | 20 | 21 | _plugins_ 22 | 23 | 24 | -------------------------------------------------------------------------------- /lib/template/index.local.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib/util/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fs = require('fs') 4 | 5 | const resolve = (exports.resolve = require('path').resolve) 6 | 7 | exports.cwd = function (path) { 8 | return resolve(process.cwd(), path || '.') 9 | } 10 | 11 | exports.pwd = function (path) { 12 | return resolve(require('path').dirname(__dirname), path) 13 | } 14 | 15 | exports.exists = function (path) { 16 | if (fs.existsSync(path)) { 17 | return path 18 | } 19 | 20 | return undefined 21 | } 22 | 23 | exports.pkg = function () { 24 | return exports.exists(exports.cwd('package.json')) ? 25 | require(exports.cwd('package.json')) : 26 | {} 27 | } 28 | 29 | exports.read = function (path) { 30 | return fs.readFileSync(path, 'utf-8').toString() 31 | } 32 | -------------------------------------------------------------------------------- /lib/util/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const chalk = require('chalk') 4 | 5 | exports.error = msg => console.error(chalk.red(msg)) 6 | 7 | exports.success = msg => console.log(chalk.green(msg)) 8 | 9 | -------------------------------------------------------------------------------- /media/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /media/screencast.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docsifyjs/docsify-cli/c74c3d280b2c70b20bd8176e021ee78ec4e5bcdf/media/screencast.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docsify-cli", 3 | "version": "4.4.4", 4 | "description": "A magical documentation generator.", 5 | "author": { 6 | "name": "qingwei-li", 7 | "email": "cinwell.li@gmail.com", 8 | "url": "https://github.com/QingWei-Li" 9 | }, 10 | "homepage": "https://github.com/docsifyjs/docsify-cli#readme", 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/docsifyjs/docsify-cli.git" 14 | }, 15 | "license": "MIT", 16 | "engines": { 17 | "node": ">= 10", 18 | "npm": ">= 6" 19 | }, 20 | "main": "bin/docsify", 21 | "bin": { 22 | "docsify": "bin/docsify" 23 | }, 24 | "scripts": { 25 | "lint": "eslint .", 26 | "lint:fix": "eslint . --fix", 27 | "pretest": "npm run lint", 28 | "test": "ava", 29 | "prebuild": "rimraf bin", 30 | "build": "rollup -c", 31 | "prerelease": "npm run build", 32 | "release": "standard-version -a" 33 | }, 34 | "husky": { 35 | "hooks": { 36 | "pre-commit": "lint-staged" 37 | } 38 | }, 39 | "lint-staged": { 40 | "*.js": [ 41 | "eslint --fix", 42 | "git add" 43 | ] 44 | }, 45 | "standard-version": { 46 | "scripts": { 47 | "postbump": "ava e2e/cli.test.js -u && git add ." 48 | } 49 | }, 50 | "files": [ 51 | "bin", 52 | "lib", 53 | "tools/locales" 54 | ], 55 | "dependencies": { 56 | "chalk": "^2.4.2", 57 | "connect": "^3.6.0", 58 | "connect-history-api-fallback": "^1.6.0", 59 | "connect-livereload": "^0.6.0", 60 | "cp-file": "^7.0.0", 61 | "docsify": "^4.12.2", 62 | "docsify-server-renderer": ">=4.13.1", 63 | "enquirer": "^2.3.6", 64 | "fs-extra": "^8.1.0", 65 | "get-port": "^5.0.0", 66 | "livereload": "^0.9.2", 67 | "lru-cache": "^5.1.1", 68 | "open": "^6.4.0", 69 | "serve-static": "^1.12.1", 70 | "update-notifier": "^4.1.0", 71 | "yargonaut": "^1.1.2", 72 | "yargs": "^15.3.0" 73 | }, 74 | "devDependencies": { 75 | "ava": "^3.13.0", 76 | "cli-prompts-test": "^0.3.0", 77 | "cors": "^2.8.1", 78 | "eslint": "^6.8.0", 79 | "eslint-config-xo-space": "^0.22.0", 80 | "execa": "^4.0.0", 81 | "husky": "^3.1.0", 82 | "lint-staged": "^9.5.0", 83 | "rimraf": "^3.0.0", 84 | "rollup": "^1.27.13", 85 | "rollup-plugin-executable": "^1.5.2", 86 | "standard-version": "^9.0.0" 87 | }, 88 | "keywords": [ 89 | "docsify", 90 | "doc", 91 | "docs", 92 | "documentation", 93 | "creator", 94 | "generator", 95 | "cli" 96 | ] 97 | } 98 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import executable from 'rollup-plugin-executable' 2 | 3 | module.exports = { 4 | input: 'lib/cli.js', // Entry file 5 | plugins: [executable()], 6 | output: { 7 | file: 'bin/docsify', 8 | format: 'cjs', // Compiles to CJS 9 | banner: '#!/usr/bin/env node' // Adds node shebang on top of the file 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tools/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "epilog": "Dokumentation:\n https://docsifyjs.github.io/docsify\n https://docsifyjs.github.io/docsify-cli\n\nEntwicklung:\n https://github.com/docsifyjs/docsify-cli/blob/master/CONTRIBUTING.md\n", 3 | "group.globaloptions": "Globale Optionen", 4 | "help": "Zeige Hilfe an", 5 | "init": "Erzeuge neue Dokumentation.", 6 | "start": "Server for SSR", 7 | "init.local": "Kopiere docsify Dateien in lokale Ordner. Um explizit --local auf false zu setzen, kannst du --no-local verwenden.", 8 | "init.theme": "Zu verwendende Theme Dateien.", 9 | "serve": "Lasse lokalen Server zur Webseitenvorschau laufen.", 10 | "serve.open": "Dokumentation im Standardbrowser öffnen. Um explizit --open auf false zu setzen, kannst du --no-open verwenden.", 11 | "serve.port": "Listen port.", 12 | "serve.indexname": "Custom filename instead of index.html to serve by default", 13 | "livereload.port": "livereload Listen port.", 14 | "usage": "Anwendung", 15 | "version": "Zeige Versionsnummer an" 16 | } 17 | -------------------------------------------------------------------------------- /tools/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "epilog": "Documentation:\n https://docsifyjs.github.io/docsify\n https://docsifyjs.github.io/docsify-cli\n\nDevelopment:\n https://github.com/docsifyjs/docsify-cli/blob/master/CONTRIBUTING.md\n", 3 | "group.globaloptions": "Global Options", 4 | "help": "Show help", 5 | "init": "Creates new docs", 6 | "start": "Server for SSR", 7 | "init.local": "Copy docsify files to local. To explicitly set --local to false you may use --no-local.", 8 | "init.theme": "Theme file to be used.", 9 | "init.plugins": "A list of plugins to be used.", 10 | "serve": "Run local server to preview site.", 11 | "serve.open": "Open docs in default browser. To explicitly set --open to false you may use --no-open.", 12 | "serve.port": "Listen port.", 13 | "serve.indexname": "Custom filename instead of index.html to serve by default", 14 | "generate": "Docsify's generators", 15 | "generate.sidebar": "Generate sidebar file", 16 | "generate.overwrite": "Allow overwrite generated files", 17 | "livereload.port": "livereload Listen port.", 18 | "usage": "Usage", 19 | "version": "Show version number" 20 | } 21 | -------------------------------------------------------------------------------- /tools/locales/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | const Y18n = require('y18n') 5 | const fse = require('fs-extra') 6 | 7 | class Locales { 8 | constructor() { 9 | // eslint-disable-next-line 10 | this.y18n = Y18n({ 11 | directory: path.resolve(__dirname), 12 | updateFiles: false, 13 | locale: this.detectLocale() 14 | }) 15 | } 16 | 17 | detectLocale() { 18 | const yargs = require('yargs') 19 | 20 | const locale = yargs.locale() 21 | 22 | try { 23 | this._existsLocaleFile(locale) 24 | } catch (e) { // eslint-disable-line 25 | return 'en' 26 | } 27 | 28 | return locale 29 | } 30 | 31 | _existsLocaleFile(locale) { 32 | return fse.readJsonSync(path.join(__dirname, `${locale.substring(0, 2)}.json`)) 33 | } 34 | 35 | __(str) { 36 | return this.y18n.__(str) 37 | } 38 | 39 | __n(singular, plural, count) { 40 | return this.y18n.__n(singular, plural, count) 41 | } 42 | } 43 | 44 | module.exports = Locales 45 | -------------------------------------------------------------------------------- /tools/locales/zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "epilog": "文档地址:\n https://docsifyjs.github.io/docsify\n https://docsifyjs.github.io/docsify-cli\n\n开发:\n https://github.com/docsifyjs/docsify-cli/blob/master/CONTRIBUTING.md\n", 3 | "group.globaloptions": "全局选项", 4 | "help": "帮助", 5 | "start": "Server for SSR", 6 | "init": "创建 docs", 7 | "init.local": "拷贝 docsify 到本地", 8 | "init.theme": "选择主题", 9 | "init.plugins": "选择插件", 10 | "serve": "本地预览", 11 | "serve.open": "自动打开浏览器", 12 | "serve.port": "设置端口", 13 | "serve.indexname": "自定义入口文件名,代替默认的 index.html", 14 | "generate": "docsify 的生成器", 15 | "generate.sidebar": "生成侧边栏文件", 16 | "generate.overwrite": "允许覆盖生成的文件", 17 | "livereload.port": "设置 livereload 端口", 18 | "usage": "例子", 19 | "version": "当前版本号" 20 | } 21 | --------------------------------------------------------------------------------