├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmignore ├── .snyk ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── appveyor.yml ├── config.json ├── index.js ├── japaFile.js ├── lib ├── Steps.js └── ace.js ├── package.json ├── src ├── Commands │ ├── Addon │ │ └── index.js │ ├── Base │ │ └── index.js │ ├── Install │ │ └── index.js │ ├── Instructions │ │ ├── Context.js │ │ └── index.js │ ├── KeyGenerate │ │ └── index.js │ ├── Make │ │ ├── Base.js │ │ ├── Command.js │ │ ├── Controller.js │ │ ├── Exception.js │ │ ├── ExceptionHandler.js │ │ ├── Hook.js │ │ ├── Listener.js │ │ ├── Middleware.js │ │ ├── Migration.js │ │ ├── Model.js │ │ ├── Provider.js │ │ ├── Seed.js │ │ ├── Trait.js │ │ └── View.js │ ├── New │ │ └── index.js │ ├── Repl │ │ └── index.js │ ├── RouteList │ │ └── index.js │ ├── Serve │ │ └── index.js │ └── index.js ├── Generators │ ├── index.js │ └── templates │ │ ├── command.mustache │ │ ├── exception.mustache │ │ ├── exceptionHandler.mustache │ │ ├── hook.mustache │ │ ├── httpController.mustache │ │ ├── listener.mustache │ │ ├── middleware.mustache │ │ ├── model.mustache │ │ ├── provider.mustache │ │ ├── schema.mustache │ │ ├── seed.mustache │ │ ├── trait.mustache │ │ ├── view.mustache │ │ └── wsController.mustache └── Services │ ├── check-node-version.js │ ├── clone.js │ ├── copy-env-file.js │ ├── exec.js │ ├── generate-app-key.js │ ├── install.js │ ├── render-instructions-md.js │ ├── run-instructions.js │ └── verify-existing-folder.js └── test ├── clone.spec.js ├── copy-env-file.spec.js ├── generators.spec.js ├── install.spec.js ├── new.spec.js ├── run-instructions.spec.js └── verify-existing-folder.spec.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.json] 13 | insert_final_newline = ignore 14 | 15 | [**.min.js] 16 | indent_style = ignore 17 | insert_final_newline = ignore 18 | 19 | [MakeFile] 20 | indent_style = tab 21 | 22 | [*.md] 23 | trim_trailing_whitespace = false 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report identified bugs 4 | --- 5 | 6 | 7 | 8 | ## Prerequisites 9 | 10 | We do our best to reply to all the issues on time. If you will follow the given guidelines, the turn around time will be faster. 11 | 12 | - Lots of raised issues are directly not bugs but instead are design decisions taken by us. 13 | - Make use of our [forum](https://forum.adonisjs.com/), or [discord server](https://discord.me/adonisjs), if you are not sure that you are reporting a bug. 14 | - Ensure the issue isn't already reported. 15 | - Ensure you are reporting the bug in the correct repo. 16 | 17 | *Delete the above section and the instructions in the sections below before submitting* 18 | 19 | ## Package version 20 | 21 | 22 | ## Node.js and npm version 23 | 24 | 25 | ## Sample Code (to reproduce the issue) 26 | 27 | 28 | ## BONUS (a sample repo to reproduce the issue) 29 | 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Propose changes for adding a new feature 4 | --- 5 | 6 | 7 | 8 | ## Prerequisites 9 | 10 | We do our best to reply to all the issues on time. If you will follow the given guidelines, the turn around time will be faster. 11 | 12 | ## Consider an RFC 13 | 14 | Please create an [RFC](https://github.com/adonisjs/rfcs) instead, if 15 | 16 | - Feature introduces a breaking change 17 | - Demands lots of time and changes in the current code base. 18 | 19 | *Delete the above section and the instructions in the sections below before submitting* 20 | 21 | ## Why this feature is required (specific use-cases will be appreciated)? 22 | 23 | 24 | ## Have you tried any other work arounds? 25 | 26 | 27 | ## Are you willing to work on it with little guidance? 28 | 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Proposed changes 4 | 5 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. 6 | 7 | ## Types of changes 8 | 9 | What types of changes does your code introduce? 10 | 11 | _Put an `x` in the boxes that apply_ 12 | 13 | - [ ] Bugfix (non-breaking change which fixes an issue) 14 | - [ ] New feature (non-breaking change which adds functionality) 15 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 16 | 17 | ## Checklist 18 | 19 | _Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._ 20 | 21 | - [ ] I have read the [CONTRIBUTING](https://github.com/adonisjs/adonis-cli/blob/develop/CONTRIBUTING.md) doc 22 | - [ ] Lint and unit tests pass locally with my changes 23 | - [ ] I have added tests that prove my fix is effective or that my feature works. 24 | - [ ] I have added necessary documentation (if appropriate) 25 | 26 | ## Further comments 27 | 28 | If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !.gitkeep 2 | node_modules 3 | npm-debug.log 4 | .nyc_output 5 | coverage 6 | test/yardstick 7 | test/yardstick-app 8 | .DS_STORE 9 | .idea 10 | .vscode/ 11 | *.sublime-project 12 | *.sublime-workspace 13 | *.log 14 | build 15 | dist 16 | yarn.lock 17 | shrinkwrap.yaml 18 | package-lock.json 19 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .editorconfig 2 | .gitignore 3 | test 4 | .nyc_output 5 | coverage 6 | -------------------------------------------------------------------------------- /.snyk: -------------------------------------------------------------------------------- 1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. 2 | version: v1.13.5 3 | ignore: {} 4 | # patches apply the minimum changes required to fix a vulnerability 5 | patch: 6 | SNYK-JS-LODASH-450202: 7 | - lodash: 8 | patched: '2019-07-04T02:19:04.709Z' 9 | - '@adonisjs/ace > lodash': 10 | patched: '2019-07-04T02:19:04.709Z' 11 | SNYK-JS-HTTPSPROXYAGENT-469131: 12 | - snyk > proxy-agent > https-proxy-agent: 13 | patched: '2019-10-05T02:19:18.739Z' 14 | - snyk > proxy-agent > pac-proxy-agent > https-proxy-agent: 15 | patched: '2019-10-05T02:19:18.739Z' 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - node 4 | - 8.0.0 5 | sudo: false 6 | install: 7 | - npm install 8 | after_script: 9 | - npm run coverage 10 | notifications: 11 | slack: 12 | secure: >- 13 | m91zkX2cLVDRDMBAUnR1d+hbZqtSHXLkuPencHadhJ3C3wm53Box8U25co/goAmjnW5HNJ1SMSIg+DojtgDhqTbReSh5gSbU0uU8YaF8smbvmUv3b2Q8PRCA7f6hQiea+a8+jAb7BOvwh66dV4Al/1DJ2b4tCjPuVuxQ96Wll7Pnj1S7yW/Hb8fQlr9wc+INXUZOe8erFin+508r5h1L4Xv0N5ZmNw+Gqvn2kPJD8f/YBPpx0AeZdDssTL0IOcol1+cDtDzMw5PAkGnqwamtxhnsw+i8OW4avFt1GrRNlz3eci5Cb3NQGjHxJf+JIALvBeSqkOEFJIFGqwAXMctJ9q8/7XyXk7jVFUg5+0Z74HIkBwdtLwi/BTyXMZAgsnDjndmR9HsuBP7OSTJF5/V7HCJZAaO9shEgS8DwR78owv9Fr5er5m9IMI+EgSH3qtb8iuuQaPtflbk+cPD3nmYbDqmPwkSCXcXRfq3IxdcV9hkiaAw52AIqqhnAXJWZfL6+Ct32i2mtSaov9FYtp/G0xb4tjrUAsDUd/AGmMJNEBVoHtP7mKjrVQ35cEtFwJr/8SmZxGvOaJXPaLs43dhXKa2tAGl11wF02d+Rz1HhbOoq9pJvJuqkLAVvRdBHUJrB4/hnTta5B0W5pe3mIgLw3AmOpk+s/H4hAP4Hp0gOWlPA= 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [4.0.12](https://github.com/adonisjs/adonis-cli/compare/4.0.11...4.0.12) (2019-04-11) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * package.json to reduce vulnerabilities ([#130](https://github.com/adonisjs/adonis-cli/issues/130)) ([57b5520](https://github.com/adonisjs/adonis-cli/commit/57b5520)) 7 | 8 | 9 | ### Features 10 | 11 | * **serve:** merge --ext with default in development mode ([#126](https://github.com/adonisjs/adonis-cli/issues/126)) ([a6fa0dd](https://github.com/adonisjs/adonis-cli/commit/a6fa0dd)) 12 | 13 | 14 | 15 | 16 | ## [4.0.11](https://github.com/adonisjs/adonis-cli/compare/v4.0.10...v4.0.11) (2019-01-18) 17 | 18 | 19 | ### Bug Fixes 20 | 21 | * **new:** correctly verify the versionn of npm ([1ceef76](https://github.com/adonisjs/adonis-cli/commit/1ceef76)) 22 | 23 | 24 | ### Features 25 | 26 | * **new:** add api flag as alternative to api-only ([fb88973](https://github.com/adonisjs/adonis-cli/commit/fb88973)) 27 | * **new:** remove dev flag ([3f8394b](https://github.com/adonisjs/adonis-cli/commit/3f8394b)) 28 | 29 | 30 | 31 | 32 | ## [4.0.10](https://github.com/adonisjs/adonis-cli/compare/v4.0.9...v4.0.10) (2018-11-27) 33 | 34 | 35 | ### Bug Fixes 36 | 37 | * **deps:** upgrade `nodemon` ([#117](https://github.com/adonisjs/adonis-cli/issues/117)) ([8a77564](https://github.com/adonisjs/adonis-cli/commit/8a77564)) 38 | 39 | 40 | 41 | 42 | ## [4.0.9](https://github.com/adonisjs/adonis-cli/compare/v4.0.8...v4.0.9) (2018-10-02) 43 | 44 | 45 | ### Bug Fixes 46 | 47 | * use bgGreen vs bgGreenBright coz of kleur over chalk ([56eaba2](https://github.com/adonisjs/adonis-cli/commit/56eaba2)) 48 | 49 | 50 | 51 | 52 | ## [4.0.8](https://github.com/adonisjs/adonis-cli/compare/v4.0.7...v4.0.8) (2018-10-01) 53 | 54 | 55 | ### Features 56 | 57 | * **intellisense:** add type comments to templates ([878154a](https://github.com/adonisjs/adonis-cli/commit/878154a)) 58 | * **template:** add typedoc to middleware template ([9920b4a](https://github.com/adonisjs/adonis-cli/commit/9920b4a)) 59 | 60 | 61 | 62 | 63 | ## [4.0.7](https://github.com/adonisjs/adonis-cli/compare/v4.0.6...v4.0.7) (2018-09-05) 64 | 65 | 66 | ### Features 67 | 68 | * **serve:** add ignore options ([#115](https://github.com/adonisjs/adonis-cli/issues/115)) ([876d13e](https://github.com/adonisjs/adonis-cli/commit/876d13e)) 69 | 70 | 71 | 72 | 73 | ## [4.0.6](https://github.com/adonisjs/adonis-cli/compare/v4.0.5...v4.0.6) (2018-08-03) 74 | 75 | 76 | ### Bug Fixes 77 | 78 | * **commands:** support prereleases of Node.js ([#114](https://github.com/adonisjs/adonis-cli/issues/114)) ([f28cdd6](https://github.com/adonisjs/adonis-cli/commit/f28cdd6)) 79 | 80 | 81 | ### Features 82 | 83 | * **new:** add support for complete git urls ([64ca4e4](https://github.com/adonisjs/adonis-cli/commit/64ca4e4)), closes [prividers#109](https://github.com/prividers/issues/109) 84 | * **serve:** add support for defining ext for watch & remove domain ([f6ec54c](https://github.com/adonisjs/adonis-cli/commit/f6ec54c)), closes [#96](https://github.com/adonisjs/adonis-cli/issues/96) 85 | 86 | 87 | 88 | 89 | ## [4.0.5](https://github.com/adonisjs/adonis-cli/compare/v4.0.4...v4.0.5) (2018-06-04) 90 | 91 | 92 | ### Bug Fixes 93 | 94 | * **package:** update marked to version 0.4.0 ([#105](https://github.com/adonisjs/adonis-cli/issues/105)) ([8b7b190](https://github.com/adonisjs/adonis-cli/commit/8b7b190)) 95 | 96 | 97 | ### Features 98 | 99 | * **install:** use cnpm flag for install ([71ae975](https://github.com/adonisjs/adonis-cli/commit/71ae975)) 100 | * **make:** add docblocks & params to resource controller ([#92](https://github.com/adonisjs/adonis-cli/issues/92)) ([d7cf77f](https://github.com/adonisjs/adonis-cli/commit/d7cf77f)) 101 | * **make:** add make:provider command ([#94](https://github.com/adonisjs/adonis-cli/issues/94)) ([3344066](https://github.com/adonisjs/adonis-cli/commit/3344066)) 102 | * **new:** add cnpm flag ([d64cb7f](https://github.com/adonisjs/adonis-cli/commit/d64cb7f)) 103 | * **serve:** add option to specify debug port ([c0735ff](https://github.com/adonisjs/adonis-cli/commit/c0735ff)) 104 | 105 | 106 | 107 | 108 | ## [4.0.4](https://github.com/adonisjs/adonis-cli/compare/v4.0.3...v4.0.4) (2018-02-14) 109 | 110 | 111 | ### Bug Fixes 112 | 113 | * **serve:** boxen has been removed ([97890a2](https://github.com/adonisjs/adonis-cli/commit/97890a2)), closes [#93](https://github.com/adonisjs/adonis-cli/issues/93) 114 | 115 | 116 | 117 | 118 | ## [4.0.3](https://github.com/adonisjs/adonis-cli/compare/v4.0.2...v4.0.3) (2018-02-09) 119 | 120 | 121 | 122 | 123 | ## [4.0.2](https://github.com/adonisjs/adonis-cli/compare/v4.0.0...v4.0.2) (2018-02-07) 124 | 125 | 126 | ### Bug Fixes 127 | 128 | * **package:** update [@adonisjs](https://github.com/adonisjs)/ignitor to version 2.0.0 ([#90](https://github.com/adonisjs/adonis-cli/issues/90)) ([a24bc49](https://github.com/adonisjs/adonis-cli/commit/a24bc49)) 129 | 130 | 131 | 132 | 133 | ## [4.0.1](https://github.com/adonisjs/adonis-cli/compare/v4.0.0...v4.0.1) (2018-02-07) 134 | 135 | 136 | 137 | 138 | # [4.0.0](https://github.com/adonisjs/adonis-cli/compare/v3.0.17...v4.0.0) (2018-01-31) 139 | 140 | 141 | ### Bug Fixes 142 | 143 | * **package:** update dotenv to version 5.0.0 ([#89](https://github.com/adonisjs/adonis-cli/issues/89)) ([454a8bf](https://github.com/adonisjs/adonis-cli/commit/454a8bf)) 144 | * **package:** update dotenv to version 5.0.0 ([#89](https://github.com/adonisjs/adonis-cli/issues/89)) ([e655cb7](https://github.com/adonisjs/adonis-cli/commit/e655cb7)) 145 | * **package:** update shelljs to version 0.8.0 ([#82](https://github.com/adonisjs/adonis-cli/issues/82)) ([05f0919](https://github.com/adonisjs/adonis-cli/commit/05f0919)) 146 | * **serve:** add root directory to ignore files nodemon ([#76](https://github.com/adonisjs/adonis-cli/issues/76)) ([11d8b5c](https://github.com/adonisjs/adonis-cli/commit/11d8b5c)) 147 | 148 | 149 | ### Features 150 | 151 | * **new:** re-design new command output & add raw option ([db4c5d9](https://github.com/adonisjs/adonis-cli/commit/db4c5d9)) 152 | 153 | 154 | 155 | 156 | ## [3.0.17](https://github.com/adonisjs/adonis-cli/compare/v3.0.16...v3.0.17) (2017-11-08) 157 | 158 | 159 | ### Features 160 | 161 | * **generators:** add traits generator ([16bebfb](https://github.com/adonisjs/adonis-cli/commit/16bebfb)) 162 | 163 | 164 | 165 | 166 | ## [3.0.16](https://github.com/adonisjs/adonis-cli/compare/v3.0.15...v3.0.16) (2017-10-30) 167 | 168 | 169 | ### Bug Fixes 170 | 171 | * **serve:** exit process on close everytime ([f1b6c77](https://github.com/adonisjs/adonis-cli/commit/f1b6c77)) 172 | 173 | 174 | 175 | 176 | ## [3.0.15](https://github.com/adonisjs/adonis-cli/compare/v3.0.14...v3.0.15) (2017-10-29) 177 | 178 | 179 | ### Features 180 | 181 | * **model:** add the possibility to generate a resourceful controller ([#63](https://github.com/adonisjs/adonis-cli/issues/63)) ([c8cdbc0](https://github.com/adonisjs/adonis-cli/commit/c8cdbc0)) 182 | * **serve:** add .dev domains support via hotel ([b3c7bdd](https://github.com/adonisjs/adonis-cli/commit/b3c7bdd)) 183 | * **serve:** add polling option for legacy watch ([695b7df](https://github.com/adonisjs/adonis-cli/commit/695b7df)) 184 | * **serve:** allow user to register `.dev` domain ([14fc1e8](https://github.com/adonisjs/adonis-cli/commit/14fc1e8)) 185 | * **setup:** add `setup` command to allow projects define setup process ([4954433](https://github.com/adonisjs/adonis-cli/commit/4954433)) 186 | 187 | 188 | ### Reverts 189 | 190 | * **commands:** remove setup command ([15258e8](https://github.com/adonisjs/adonis-cli/commit/15258e8)) 191 | 192 | 193 | 194 | 195 | ## [3.0.14](https://github.com/adonisjs/adonis-cli/compare/v3.0.12...v3.0.14) (2017-10-10) 196 | 197 | 198 | ### Bug Fixes 199 | 200 | * **clone:** allow white space ([dd2b551](https://github.com/adonisjs/adonis-cli/commit/dd2b551)) 201 | * **make:controller:** entertain the resource flag ([977b160](https://github.com/adonisjs/adonis-cli/commit/977b160)) 202 | * **repl:** create history file if doesn't exists ([#58](https://github.com/adonisjs/adonis-cli/issues/58)) ([3fb526b](https://github.com/adonisjs/adonis-cli/commit/3fb526b)) 203 | * **watch:** ignore public directory ([67ca54d](https://github.com/adonisjs/adonis-cli/commit/67ca54d)) 204 | 205 | 206 | 207 | 208 | ## [3.0.13](https://github.com/adonisjs/adonis-cli/compare/v3.0.12...v3.0.13) (2017-10-03) 209 | 210 | 211 | 212 | 213 | ## [3.0.12](https://github.com/adonisjs/adonis-cli/compare/v3.0.11...v3.0.12) (2017-08-22) 214 | 215 | 216 | ### Features 217 | 218 | * **new:** add --dev flag to the new command ([4282267](https://github.com/adonisjs/adonis-cli/commit/4282267)) 219 | 220 | 221 | 222 | 223 | ## [3.0.11](https://github.com/adonisjs/adonis-cli/compare/v3.0.10...v3.0.11) (2017-08-22) 224 | 225 | 226 | ### Bug Fixes 227 | 228 | * **install:** do not require app ace file ([ab536d5](https://github.com/adonisjs/adonis-cli/commit/ab536d5)) 229 | * **package:** update pluralize to version 7.0.0 ([#53](https://github.com/adonisjs/adonis-cli/issues/53)) ([0e46de1](https://github.com/adonisjs/adonis-cli/commit/0e46de1)) 230 | 231 | 232 | ### Features 233 | 234 | * **make:** add make:exception command ([a9b2c3c](https://github.com/adonisjs/adonis-cli/commit/a9b2c3c)) 235 | * **new:** install fullstack app by default ([e07860c](https://github.com/adonisjs/adonis-cli/commit/e07860c)) 236 | 237 | 238 | 239 | 240 | ## [3.0.10](https://github.com/adonisjs/adonis-cli/compare/v3.0.9...v3.0.10) (2017-08-18) 241 | 242 | 243 | ### Features 244 | 245 | * **serve:** add --debug flag to run in debug mode ([d6197b8](https://github.com/adonisjs/adonis-cli/commit/d6197b8)) 246 | 247 | 248 | 249 | 250 | ## [3.0.9](https://github.com/adonisjs/adonis-cli/compare/v3.0.8...v3.0.9) (2017-08-16) 251 | 252 | 253 | ### Bug Fixes 254 | 255 | * **generators:** add WsController template ([#51](https://github.com/adonisjs/adonis-cli/issues/51)) ([a10e1e4](https://github.com/adonisjs/adonis-cli/commit/a10e1e4)) 256 | * **generators:** generate proper paths to nested folders ([6cae861](https://github.com/adonisjs/adonis-cli/commit/6cae861)) 257 | * **install:** pass `--save` flag to npm install ([9b39aa7](https://github.com/adonisjs/adonis-cli/commit/9b39aa7)) 258 | * **wsController:** make proper path for subdirs ([28f7af0](https://github.com/adonisjs/adonis-cli/commit/28f7af0)) 259 | 260 | 261 | ### Features 262 | 263 | * **serve:** remove forever for nodemon ([23f1798](https://github.com/adonisjs/adonis-cli/commit/23f1798)) 264 | 265 | 266 | 267 | 268 | ## [3.0.8](https://github.com/adonisjs/adonis-cli/compare/v3.0.7...v3.0.8) (2017-08-08) 269 | 270 | 271 | ### Bug Fixes 272 | 273 | * **template:** fix command template ([cb3bb86](https://github.com/adonisjs/adonis-cli/commit/cb3bb86)) 274 | 275 | 276 | 277 | 278 | ## [3.0.7](https://github.com/adonisjs/adonis-cli/compare/v3.0.6...v3.0.7) (2017-08-04) 279 | 280 | 281 | ### Bug Fixes 282 | 283 | * **context:** cli.copy should not overwrite the existing file ([8fc3bd1](https://github.com/adonisjs/adonis-cli/commit/8fc3bd1)) 284 | * **instructions:** make sure instruction fn is a function ([acc7e82](https://github.com/adonisjs/adonis-cli/commit/acc7e82)) 285 | * **serve:** fix glob pattern for ignore dirs ([4860502](https://github.com/adonisjs/adonis-cli/commit/4860502)) 286 | 287 | 288 | 289 | 290 | ## [3.0.6](https://github.com/adonisjs/adonis-cli/compare/v3.0.5...v3.0.6) (2017-08-02) 291 | 292 | 293 | 294 | 295 | ## [3.0.5](https://github.com/adonisjs/adonis-cli/compare/v3.0.4...v3.0.5) (2017-08-01) 296 | 297 | 298 | ### Bug Fixes 299 | 300 | * **commands:** use as flag over name ([e11ae80](https://github.com/adonisjs/adonis-cli/commit/e11ae80)) 301 | 302 | 303 | 304 | 305 | ## [3.0.4](https://github.com/adonisjs/adonis-cli/compare/v3.0.3...v3.0.4) (2017-08-01) 306 | 307 | 308 | ### Features 309 | 310 | * **commands:** add install command ([56834a8](https://github.com/adonisjs/adonis-cli/commit/56834a8)) 311 | * **commands:** add run:instructions command ([459d7c9](https://github.com/adonisjs/adonis-cli/commit/459d7c9)) 312 | 313 | 314 | 315 | 316 | ## [3.0.3](https://github.com/adonisjs/adonis-cli/compare/v3.0.2...v3.0.3) (2017-07-28) 317 | 318 | 319 | ### Features 320 | 321 | * **commands:** add make:ehandler command ([8703159](https://github.com/adonisjs/adonis-cli/commit/8703159)) 322 | * **commands:** add make:seed command ([c7898da](https://github.com/adonisjs/adonis-cli/commit/c7898da)) 323 | * **commands:** add repl command ([e0c0f7f](https://github.com/adonisjs/adonis-cli/commit/e0c0f7f)) 324 | * **commands:** add route:list command ([a0b63ed](https://github.com/adonisjs/adonis-cli/commit/a0b63ed)) 325 | 326 | 327 | 328 | 329 | ## [3.0.2](https://github.com/adonisjs/adonis-cli/compare/v3.0.1...v3.0.2) (2017-07-27) 330 | 331 | 332 | ### Features 333 | 334 | * **serve:** add ignore patterns to serve command ([eb132ef](https://github.com/adonisjs/adonis-cli/commit/eb132ef)) 335 | 336 | 337 | 338 | 339 | ## [3.0.1](https://github.com/adonisjs/adonis-cli/compare/v3.0.0...v3.0.1) (2017-07-27) 340 | 341 | 342 | ### Bug Fixes 343 | 344 | * **bin:** remove --harmony flag ([a814d45](https://github.com/adonisjs/adonis-cli/commit/a814d45)) 345 | 346 | 347 | 348 | 349 | # [3.0.0](https://github.com/adonisjs/adonis-cli/compare/v2.1.9...v3.0.0) (2017-07-27) 350 | 351 | 352 | ### Bug Fixes 353 | 354 | * **test:** add hack for windows ([5ee5071](https://github.com/adonisjs/adonis-cli/commit/5ee5071)) 355 | * **test:** another attempt for window ([5a98518](https://github.com/adonisjs/adonis-cli/commit/5a98518)) 356 | * **test:** fix breaking tests ([525312a](https://github.com/adonisjs/adonis-cli/commit/525312a)) 357 | * **test:** fs.remove doesn't work in windows ([c4539cf](https://github.com/adonisjs/adonis-cli/commit/c4539cf)) 358 | 359 | 360 | ### Features 361 | 362 | * **command:** cleanup & add `new` command ([5844ef6](https://github.com/adonisjs/adonis-cli/commit/5844ef6)) 363 | * **commands:** add key:generate ([e4d105e](https://github.com/adonisjs/adonis-cli/commit/e4d105e)) 364 | * **commands:** add make commands ([c4d21d4](https://github.com/adonisjs/adonis-cli/commit/c4d21d4)) 365 | * **commands:** add make:listener command ([6e276d6](https://github.com/adonisjs/adonis-cli/commit/6e276d6)) 366 | * **commands:** add migration make command ([d13b2f7](https://github.com/adonisjs/adonis-cli/commit/d13b2f7)) 367 | * **commands:** add serve command ([34ee502](https://github.com/adonisjs/adonis-cli/commit/34ee502)) 368 | 369 | 370 | 371 | 372 | ## [2.1.9](https://github.com/adonisjs/adonis-cli/compare/v2.1.8...v2.1.9) (2017-03-14) 373 | 374 | 375 | ### Bug Fixes 376 | 377 | * **new:** change process directory ([#26](https://github.com/adonisjs/adonis-cli/issues/26)) ([35afe17](https://github.com/adonisjs/adonis-cli/commit/35afe17)) 378 | 379 | 380 | 381 | 382 | ## [2.1.8](https://github.com/adonisjs/adonis-cli/compare/v2.1.7...v2.1.8) (2017-01-30) 383 | 384 | 385 | ### Bug Fixes 386 | 387 | * **fs:** fs.constants is undefined across versions ([b0d8841](https://github.com/adonisjs/adonis-cli/commit/b0d8841)) 388 | 389 | 390 | 391 | 392 | ## [2.1.7](https://github.com/adonisjs/adonis-cli/compare/v2.1.6...v2.1.7) (2017-01-28) 393 | 394 | 395 | ### Bug Fixes 396 | 397 | * **dependencies:** install adonis-fold as main dependency ([dbf9e21](https://github.com/adonisjs/adonis-cli/commit/dbf9e21)) 398 | 399 | 400 | 401 | 402 | ## [2.1.6](https://github.com/adonisjs/adonis-cli/compare/v2.1.5...v2.1.6) (2017-01-28) 403 | 404 | 405 | ### Bug Fixes 406 | 407 | * closes [#3](https://github.com/adonisjs/adonis-cli/issues/3) ([25d2edd](https://github.com/adonisjs/adonis-cli/commit/25d2edd)) 408 | * use the requiredNodeVersion and requiredNpmVersion const ([246dde6](https://github.com/adonisjs/adonis-cli/commit/246dde6)) 409 | * **install:** install using --no-optional flag ([0426fa3](https://github.com/adonisjs/adonis-cli/commit/0426fa3)) 410 | 411 | 412 | ### Features 413 | 414 | * add check node.js and npm required versions to the new command. ([7493ee6](https://github.com/adonisjs/adonis-cli/commit/7493ee6)) 415 | * check node.js and npm required versions ([954f3e8](https://github.com/adonisjs/adonis-cli/commit/954f3e8)) 416 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | AdonisJs is a community driven project. You are free to contribute in any of the following ways. 4 | 5 | - [Coding style](coding-style) 6 | - [Fix bugs by creating PR's](fix-bugs-by-creating-prs) 7 | - [Share an RFC for new features or big changes](share-an-rfc-for-new-features-or-big-changes) 8 | - [Report security issues](report-security-issues) 9 | - [Be a part of the community](be-a-part-of-community) 10 | 11 | ## Coding style 12 | 13 | Majority of AdonisJs core packages are written in Typescript. Having a brief knowledge of Typescript is required to contribute to the core. [Learn more](https://adonisjs.com/coding-style) about the same. 14 | 15 | ## Fix bugs by creating PR's 16 | 17 | We appreciate every time you report a bug in the framework or related libraries. However, taking time to submit a PR can help us in fixing bugs quickly and ensure a healthy and stable eco-system. 18 | 19 | Go through the following points, before creating a new PR. 20 | 21 | 1. Create an issue discussing the bug or short-coming in the framework. 22 | 2. Once approved, go ahead and fork the REPO. 23 | 3. Make sure to start from the `develop`, since this is the upto date branch. 24 | 4. Make sure to keep commits small and relevant. 25 | 5. We follow [conventional-commits](https://github.com/conventional-changelog/conventional-changelog) to structure our commit messages. Instead of running `git commit`, you must run `npm commit`, which will show you prompts to create a valid commit message. 26 | 6. Once done with all the changes, create a PR against the `develop` branch. 27 | 28 | ## Share an RFC for new features or big changes 29 | 30 | Sharing PR's for small changes works great. However, when contributing big features to the framework, it is required to go through the RFC process. 31 | 32 | ### What is an RFC? 33 | 34 | RFC stands for **Request for Commits**, a standard process followed by many other frameworks including [Ember](https://github.com/emberjs/rfcs), [yarn](https://github.com/yarnpkg/rfcs) and [rust](https://github.com/rust-lang/rfcs). 35 | 36 | In brief, RFC process allows you to talk about the changes with everyone in the community and get a view of the core team before dedicating your time to work on the feature. 37 | 38 | The RFC proposals are created as issues on [adonisjs/rfcs](https://github.com/adonisjs/rfcs) repo. Make sure to read the README to learn about the process in depth. 39 | 40 | ## Report security issues 41 | 42 | All of the security issues, must be reported via [email](mailto:virk@adonisjs.com) and not using any of the public channels. [Learn more](https://adonisjs.com/security) about the security policy 43 | 44 | ## Be a part of community 45 | 46 | We welcome you to participate in the [forum](https://forum.adonisjs.com/) and the AdonisJs [discord server](https://discord.me/adonisjs). You are free to ask your questions and share your work or contributions made to AdonisJs eco-system. 47 | 48 | We follow a strict [Code of Conduct](https://adonisjs.com/community-guidelines) to make sure everyone is respectful to each other. 49 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright 2018 Harminder Virk, contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AdonisJs Cli 🍺 2 | > Scaffolding tool for Adonisjs 3 | 4 | [![NPM Version][npm-image]][npm-url] 5 | [![Build Status][travis-image]][travis-url] 6 | [![Appveyor][appveyor-image]][appveyor-url] 7 | [![Coveralls][coveralls-image]][coveralls-url] 8 | 9 | Adonis cli is built on top of [Adonis ace](https://github.com/adonisjs/ace) and helps you scaffold new Adonisjs projects. 10 | 11 | Also it can proxy all the ace commands for a project, so that you can run them using the global `adonis` command. 12 | 13 | 14 | 15 | ## Installation 16 | You can install the package from npm. 17 | ```bash 18 | npm i --global @adonisjs/cli 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```bash 24 | adonis new yardstick 25 | 26 | # start http server 27 | adonis serve --dev 28 | ``` 29 | 30 | ## Moving Forward 31 | Checkout the [official documentation](https://adonisjs.com/docs/4.1/installation) at the AdonisJs website for more info. 32 | 33 | ## Tests 34 | Tests are written using [japa](http://github.com/thetutlage/japa). Run the following commands to run tests. 35 | 36 | ```bash 37 | npm run test:local 38 | 39 | # report coverage 40 | npm run test 41 | 42 | # on windows 43 | npm run test:win 44 | ``` 45 | 46 | ## Release History 47 | 48 | Checkout [CHANGELOG.md](CHANGELOG.md) file for release history. 49 | 50 | ## Meta 51 | 52 | AdonisJs – [@adonisframework](https://twitter.com/adonisframework) – virk@adonisjs.com 53 | 54 | Checkout [LICENSE.txt](LICENSE.txt) for license information 55 | 56 | Harminder Virk (Aman) - [https://github.com/thetutlage](https://github.com/thetutlage) 57 | 58 | [appveyor-image]: https://img.shields.io/appveyor/ci/thetutlage/adonis-cli/master.svg?style=flat-square 59 | 60 | [appveyor-url]: https://ci.appveyor.com/project/thetutlage/adonis-cli 61 | 62 | [npm-image]: https://img.shields.io/npm/v/@adonisjs/cli.svg?style=flat-square 63 | [npm-url]: https://npmjs.org/package/@adonisjs/cli 64 | 65 | [travis-image]: https://img.shields.io/travis/adonisjs/adonis-cli/master.svg?style=flat-square 66 | [travis-url]: https://travis-ci.org/adonisjs/adonis-cli 67 | 68 | [coveralls-image]: https://img.shields.io/coveralls/adonisjs/adonis-cli/develop.svg?style=flat-square 69 | 70 | [coveralls-url]: https://coveralls.io/github/adonisjs/adonis-cli 71 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: Stable 4 | - nodejs_version: 8.0.0 5 | init: git config --global core.autocrlf true 6 | install: 7 | - ps: 'Install-Product node $env:nodejs_version' 8 | - npm install 9 | test_script: 10 | - node --version 11 | - npm --version 12 | - npm run test 13 | build: 'off' 14 | clone_depth: 1 15 | matrix: 16 | fast_finish: true 17 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "core": true, 3 | "ts": false, 4 | "license": "MIT", 5 | "services": [ 6 | "travis", 7 | "appveyor", 8 | "coveralls" 9 | ], 10 | "appveyorUsername": "thetutlage", 11 | "minNodeVersion": "8.0.0" 12 | } 13 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict' 3 | 4 | /* 5 | * adonis-cli 6 | * 7 | * (c) Harminder Virk 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | const path = require('path') 14 | const debug = require('debug')('adonis:cli') 15 | 16 | const Commands = require('./src/Commands') 17 | const commandNames = [] 18 | const needProviders = ['repl', 'route:list', 'run:instructions'] 19 | 20 | const ace = require('./lib/ace') 21 | 22 | // register internal commands 23 | Object.keys(Commands).forEach((name) => { 24 | commandNames.push(name) 25 | ace.addCommand(Commands[name]) 26 | }) 27 | 28 | // require user project .ace file 29 | try { 30 | const command = process.argv[2] 31 | if (commandNames.indexOf(command) > -1 && needProviders.indexOf(command) <= -1) { 32 | debug('loading ace from cli') 33 | ace.wireUpWithCommander() 34 | ace.invoke(require('./package')) 35 | } else { 36 | debug('loading ace from project') 37 | require(path.join(process.cwd(), 'ace')) 38 | } 39 | } catch (error) { 40 | if (error.code !== 'ENOENT' && error.code !== 'MODULE_NOT_FOUND') { 41 | throw error 42 | } 43 | 44 | debug('loading ace as fallback from cli') 45 | ace.wireUpWithCommander() 46 | ace.invoke(require('./package')) 47 | } 48 | -------------------------------------------------------------------------------- /japaFile.js: -------------------------------------------------------------------------------- 1 | const { configure } = require('japa') 2 | configure({ 3 | files: ['test/**/*.spec.js'] 4 | }) 5 | -------------------------------------------------------------------------------- /lib/Steps.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const Steps = require('cli-step') 13 | 14 | /** 15 | * Raw steps are used when user want to disable all animations. 16 | * 17 | * @class RawStep 18 | */ 19 | class RawStep { 20 | constructor (total, counter, text, helpText) { 21 | this.total = total 22 | this.stepCounter = counter 23 | this.text = text 24 | this.helpText = helpText || '' 25 | } 26 | 27 | /** 28 | * Start step 29 | * 30 | * @method start 31 | * 32 | * @chainable 33 | */ 34 | start () { 35 | console.log(`Step ${this.stepCounter}/${this.total}`) 36 | console.log(` ├── ${this.text} (${this.helpText})`) 37 | return this 38 | } 39 | 40 | /** 41 | * Mark step as successful 42 | * 43 | * @method success 44 | * 45 | * @param {String} text 46 | * 47 | * @return {void} 48 | */ 49 | success (text) { 50 | console.log(` ├── SUCCESS: ${text || this.text} (${this.helpText})`) 51 | } 52 | 53 | /** 54 | * Mark step as errored 55 | * 56 | * @method error 57 | * 58 | * @param {String} text 59 | * 60 | * @return {void} 61 | */ 62 | error (text) { 63 | console.log(` ├── ERROR: ${text || this.text} (${this.helpText})`) 64 | } 65 | } 66 | 67 | /** 68 | * Raw steps is a collection of Raw step. The API has to be 69 | * compatible with `cli-step`. 70 | * 71 | * @class RawSteps 72 | */ 73 | class RawSteps { 74 | constructor (total) { 75 | this.counter = 0 76 | this.total = total 77 | } 78 | 79 | /** 80 | * Move to next step. Also the icon param is swalled, since raw output 81 | * doesn't display emojis. 82 | * 83 | * @method advance 84 | * 85 | * @param {String} text 86 | * @param {String} icon 87 | * @param {String} helpText 88 | * 89 | * @return {void} 90 | */ 91 | advance (text, icon, helpText) { 92 | this.counter++ 93 | return new RawStep(this.total, this.counter, text, helpText) 94 | } 95 | } 96 | 97 | module.exports = { RawSteps, Steps } 98 | -------------------------------------------------------------------------------- /lib/ace.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | let ace = null 14 | 15 | /** 16 | * Give preference to the user ace module if 17 | * command is executed in project root. 18 | */ 19 | try { 20 | ace = require(path.join(process.cwd(), 'node_modules/@adonisjs/ace')) 21 | } catch (error) { 22 | ace = require('@adonisjs/ace') 23 | } 24 | 25 | module.exports = ace 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@adonisjs/cli", 3 | "version": "4.0.13", 4 | "description": "Command line tool for Adonisjs", 5 | "keywords": [ 6 | "adonis", 7 | "adonisjs", 8 | "cli", 9 | "installer" 10 | ], 11 | "author": "Harminder Virk ", 12 | "contributors": [ 13 | "Romain Lanz " 14 | ], 15 | "license": "MIT", 16 | "main": "src/Commands/index.js", 17 | "bin": { 18 | "adonis": "index.js" 19 | }, 20 | "scripts": { 21 | "mrm": "mrm --preset=@adonisjs/mrm-preset", 22 | "pretest": "npm run lint", 23 | "test:local": "FORCE_COLOR=true node bin/index.js --local", 24 | "test": "nyc node japaFile.js", 25 | "coverage": "nyc report --reporter=text-lcov | coveralls", 26 | "commit": "git-cz", 27 | "lint": "standard", 28 | "snyk-protect": "snyk protect", 29 | "prepublish": "npm run snyk-protect" 30 | }, 31 | "dependencies": { 32 | "@adonisjs/ace": "^5.0.8", 33 | "@adonisjs/ignitor": "^2.0.8", 34 | "adonis-await-outside": "^1.0.0", 35 | "cli-step": "^1.0.2", 36 | "debug": "^4.1.0", 37 | "dotenv": "^8.0.0", 38 | "gradient-string": "^1.2.0", 39 | "is-git-url": "^1.0.0", 40 | "lodash": "^4.17.11", 41 | "marked": "^1.1.1", 42 | "nodemon": "^2.0.3", 43 | "opn": "^5.4.0", 44 | "pluralize": "^8.0.0", 45 | "randomstring": "^1.1.5", 46 | "semver": "^5.6.0", 47 | "snyk": "^1.231.0" 48 | }, 49 | "devDependencies": { 50 | "@adonisjs/fold": "^4.0.9", 51 | "@adonisjs/mrm-preset": "^2.0.3", 52 | "@adonisjs/sink": "^1.0.17", 53 | "clear-require": "^3.0.0", 54 | "commitizen": "^3.0.4", 55 | "coveralls": "^3.0.2", 56 | "cz-conventional-changelog": "^2.1.0", 57 | "fs-extra": "^8.1.0", 58 | "japa": "^2.0.6", 59 | "japa-cli": "^1.0.1", 60 | "mrm": "^1.2.1", 61 | "nyc": "^14.1.1", 62 | "pkg-ok": "^2.3.1", 63 | "standard": "^12.0.1" 64 | }, 65 | "repository": { 66 | "type": "git", 67 | "url": "git+https://github.com/adonisjs/adonis-cli.git" 68 | }, 69 | "bugs": { 70 | "url": "https://github.com/adonisjs/adonis-cli/issues" 71 | }, 72 | "config": { 73 | "commitizen": { 74 | "path": "cz-conventional-changelog" 75 | } 76 | }, 77 | "nyc": { 78 | "exclude": [ 79 | "test" 80 | ] 81 | }, 82 | "homepage": "https://github.com/adonisjs/adonis-cli#readme", 83 | "directories": { 84 | "lib": "lib", 85 | "test": "test" 86 | }, 87 | "snyk": true 88 | } 89 | -------------------------------------------------------------------------------- /src/Commands/Addon/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const BaseCommand = require('../Base') 14 | 15 | /** 16 | * This command performs a series of operations 17 | * to be create a new addon folder. 18 | * 19 | * @class NewAddon 20 | */ 21 | class NewAddon extends BaseCommand { 22 | /** 23 | * The command signature required by ace 24 | * 25 | * @attribute signature 26 | * @static 27 | * 28 | * @return {String} 29 | */ 30 | static get signature () { 31 | return ` 32 | addon 33 | { name : Name of the addon directory } 34 | { --skip-install : Do not install modules from npm } 35 | { --yarn : Use yarn over npm for modules installation } 36 | { --raw : Disable animations and colored output } 37 | { --dev: Install the dev blueprint } 38 | ` 39 | } 40 | 41 | /** 42 | * The command description required by ace 43 | * 44 | * @attribute description 45 | * 46 | * @return {String} 47 | */ 48 | static get description () { 49 | return 'Create a new AdonisJs addon' 50 | } 51 | 52 | /** 53 | * Ensure node version is correct, then make sure app path is 54 | * empty and finally clone the repo and remove `.git` dir. 55 | * 56 | * @method _setupProjectDirectory 57 | * 58 | * @param {Object} stepsCounter 59 | * @param {String} blueprint 60 | * @param {String} appPath 61 | * @param {Object} options 62 | * 63 | * @return {void} 64 | * 65 | * @private 66 | */ 67 | async _setupProjectDirectory (stepsCounter, blueprint, appPath, options) { 68 | await require('../../Services/check-node-version')(stepsCounter) 69 | await require('../../Services/verify-existing-folder')(appPath, stepsCounter) 70 | await require('../../Services/clone')(blueprint, appPath, stepsCounter, options.branch) 71 | await this.removeDir(path.join(appPath, '.git')) 72 | } 73 | 74 | /** 75 | * Prints a message after a new project has been created 76 | * 77 | * @method _onBoardForNewAddon 78 | * 79 | * @return {void} 80 | * 81 | * @private 82 | */ 83 | _onBoardForNewAddon () { 84 | const lines = [ 85 | '', 86 | '🚀 Addon created successfully', 87 | '👉 Get started by clicking the following link', 88 | '', 89 | `${this.chalk.blue('https://adonisjs.com/recipes/creating-addons')}`, 90 | '' 91 | ] 92 | lines.forEach((line) => (console.log(line))) 93 | } 94 | 95 | /** 96 | * Install dependencies when `skip-install` flag has not been 97 | * passed 98 | * 99 | * @method _installDependencies 100 | * 101 | * @param {Object} stepsCounter 102 | * @param {String} appPath 103 | * @param {Object} options 104 | * 105 | * @return {void} 106 | * 107 | * @private 108 | */ 109 | async _installDependencies (stepsCounter, appPath, options) { 110 | if (options.skipInstall) { 111 | return 112 | } 113 | await require('../../Services/install')(options.yarn ? 'yarn' : 'npm', stepsCounter) 114 | } 115 | 116 | /** 117 | * Invoked by ace 118 | * 119 | * @method handle 120 | * 121 | * @param {Object} args 122 | * @param {Object} options 123 | * 124 | * @return {void} 125 | */ 126 | async handle ({ name }, options) { 127 | const blueprint = 'adonisjs/adonis-addon' 128 | const addonPath = path.join(process.cwd(), name) 129 | const stepsCounter = this.initiateSteps(options.skipInstall ? 3 : 4, options) 130 | 131 | if (options.dev) { 132 | options.branch = 'develop' 133 | } 134 | 135 | await this.invoke(async () => { 136 | this.dumpAsciiLogo() 137 | 138 | await this._setupProjectDirectory(stepsCounter, blueprint, addonPath, options) 139 | process.chdir(addonPath) 140 | 141 | await this._installDependencies(stepsCounter, addonPath, options) 142 | this._onBoardForNewAddon() 143 | }) 144 | } 145 | } 146 | 147 | module.exports = NewAddon 148 | -------------------------------------------------------------------------------- /src/Commands/Base/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const gradient = require('gradient-string') 13 | const path = require('path') 14 | 15 | const ace = require('../../../lib/ace') 16 | 17 | class BaseCommand extends ace.Command { 18 | /** 19 | * Returns an instance of steps counter, based upon 20 | * command line flags 21 | * 22 | * @method initiateSteps 23 | * 24 | * @param {Number} count 25 | * @param {Object} options 26 | * 27 | * @return {Object} 28 | */ 29 | initiateSteps (count, options) { 30 | const { RawSteps, Steps } = require('../../../lib/Steps') 31 | return options.raw || process.env.DEBUG ? new RawSteps(count) : new Steps(count) 32 | } 33 | 34 | /** 35 | * Prints AdonisJs ascii art to the console 36 | * 37 | * @method dumpAsciiLogo 38 | * 39 | * @return {void} 40 | */ 41 | dumpAsciiLogo () { 42 | console.log(gradient.rainbow(" _ _ _ _ \n / \\ __| | ___ _ __ (_)___ | |___ \n / _ \\ / _` |/ _ \\| '_ \\| / __|_ | / __|\n / ___ \\ (_| | (_) | | | | \\__ \\ |_| \\__ \\\n/_/ \\_\\__,_|\\___/|_| |_|_|___/\\___/|___/\n")) 43 | } 44 | 45 | /** 46 | * Invokes a function, by automatically catching for errors 47 | * and printing them in a standard way 48 | * 49 | * @method invoke 50 | * 51 | * @param {Function} callback 52 | * 53 | * @return {void} 54 | */ 55 | async invoke (callback) { 56 | try { 57 | await callback() 58 | } catch (error) { 59 | this.printError(error) 60 | process.exit(1) 61 | } 62 | } 63 | 64 | /** 65 | * Prints error object to the console 66 | * 67 | * @method printError 68 | * 69 | * @param {Object} error 70 | * 71 | * @return {void} 72 | */ 73 | printError (error) { 74 | console.log(`\n ${this.chalk.bgRed(' ERROR ')} ${error.message}\n`) 75 | 76 | if (error.hint) { 77 | console.log(`\n ${this.chalk.bgRed(' HELP ')} ${error.hint}\n`) 78 | } 79 | } 80 | 81 | /** 82 | * Throws exception when user is not inside the project root 83 | * 84 | * @method ensureInProjectRoot 85 | * 86 | * @return {void} 87 | */ 88 | async ensureInProjectRoot () { 89 | const exists = await this.pathExists(path.join(process.cwd(), 'ace')) 90 | if (!exists) { 91 | throw new Error(`Make sure you are inside an adonisjs app to run the ${this.constructor.commandName} command`) 92 | } 93 | } 94 | 95 | /** 96 | * Throws error when NODE_ENV = production and `--force` flag 97 | * has not been passed. 98 | * 99 | * @method ensureCanRunInProduction 100 | * 101 | * @param {Object} options 102 | * 103 | * @return {void} 104 | */ 105 | ensureCanRunInProduction (options) { 106 | if (process.env.NODE_ENV === 'production' && !options.force) { 107 | throw new Error(`Cannot run ${this.constructor.commandName} command in production. Pass --force flag to continue`) 108 | } 109 | } 110 | 111 | /** 112 | * Calls a command registered with ace 113 | * 114 | * @method call 115 | * 116 | * @param {String} command 117 | * @param {Object} options 118 | * @param {Object} flags 119 | * 120 | * @return {void} 121 | */ 122 | call (command, options, flags) { 123 | return ace.call(command, options, flags) 124 | } 125 | } 126 | 127 | module.exports = BaseCommand 128 | -------------------------------------------------------------------------------- /src/Commands/Install/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const BaseCommand = require('../Base') 14 | 15 | class Install extends BaseCommand { 16 | constructor () { 17 | super() 18 | const FakeHelpers = require('@adonisjs/ignitor/src/Helpers') 19 | this.Helpers = new FakeHelpers(process.cwd()) 20 | } 21 | 22 | /** 23 | * The command signature 24 | * 25 | * @method signature 26 | * 27 | * @return {String} 28 | */ 29 | static get signature () { 30 | return ` 31 | install 32 | { module : Npm module name } 33 | { --as=@value : Name of the module, required when installing from github or local file system } 34 | { --yarn: Use yarn over npm for installation } 35 | { --cnpm: Use cnpm over npm for installation } 36 | { -s, --skip-instructions: Do not run post install instructions } 37 | { --raw : Disable animations and colored output } 38 | ` 39 | } 40 | 41 | /** 42 | * The command description 43 | * 44 | * @method description 45 | * 46 | * @return {String} 47 | */ 48 | static get description () { 49 | return 'Install Adonisjs provider from npm/yarn and run post install instructions' 50 | } 51 | 52 | async handle ({ module: packageName }, options) { 53 | const name = options.as || packageName 54 | const stepsCounter = this.initiateSteps(1, options) 55 | 56 | await this.invoke(async () => { 57 | await this.ensureInProjectRoot() 58 | await require('../../Services/install')(options.yarn ? 'yarn' : (options.cnpm ? 'cnpm' : 'npm'), stepsCounter, packageName) 59 | 60 | if (options.skipInstructions) { 61 | return 62 | } 63 | 64 | const directory = path.join(process.cwd(), 'node_modules', name) 65 | await this.call('run:instructions', { directory }, { name }) 66 | }) 67 | } 68 | } 69 | 70 | module.exports = Install 71 | -------------------------------------------------------------------------------- /src/Commands/Instructions/Context.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const _ = require('lodash') 14 | const ace = require('../../../lib/ace') 15 | 16 | class Context { 17 | constructor (command, helpers) { 18 | this.command = command 19 | this.helpers = helpers 20 | this.appDir = path.join(this.helpers.appRoot(), 'app') 21 | } 22 | 23 | /** 24 | * Make config file using a template 25 | * 26 | * @method makeConfig 27 | * @async 28 | * 29 | * @param {String} fileName 30 | * @param {String} templatePath 31 | * @param {Object} data 32 | * 33 | * @return {void} 34 | */ 35 | async makeConfig (fileName, templatePath, data) { 36 | const configFile = path.join(this.helpers.configPath(), fileName) 37 | const template = await this.command.readFile(templatePath, 'utf-8') 38 | await this.command.generateFile(configFile, template, data) 39 | } 40 | 41 | /** 42 | * Calls ace command 43 | * 44 | * @method callCommand 45 | * @async 46 | * 47 | * @param {String} name 48 | * @param {Object} args 49 | * @param {Object} options 50 | * 51 | * @return {void} 52 | */ 53 | callCommand (name, args, options) { 54 | return ace.call(name, args, options) 55 | } 56 | 57 | /** 58 | * Copy file from one destination to other 59 | * 60 | * @method copy 61 | * 62 | * @param {String} fromFile 63 | * @param {String} toFile 64 | * @param {Object} [options] 65 | * 66 | * @return {void} 67 | */ 68 | copy (fromFile, toFile, options) { 69 | return this.command.copy(fromFile, toFile, _.merge({}, { overwrite: false, errorOnExist: true }, options)) 70 | } 71 | } 72 | 73 | module.exports = Context 74 | -------------------------------------------------------------------------------- /src/Commands/Instructions/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const BaseCommand = require('../Base') 14 | 15 | class Instructions extends BaseCommand { 16 | constructor (Helpers) { 17 | super() 18 | const FakeHelpers = require('@adonisjs/ignitor/src/Helpers') 19 | this.Helpers = Helpers || new FakeHelpers(process.cwd()) 20 | } 21 | 22 | /** 23 | * Injecting dependencies 24 | * 25 | * @method inject 26 | * 27 | * @return {Array} 28 | */ 29 | static get inject () { 30 | return ['Adonis/Src/Helpers'] 31 | } 32 | 33 | /** 34 | * The command signature 35 | * 36 | * @method signature 37 | * 38 | * @return {String} 39 | */ 40 | static get signature () { 41 | return ` 42 | run:instructions 43 | { directory : Directory path for which to run instructions } 44 | { --as=@value: Name of the module } 45 | ` 46 | } 47 | 48 | /** 49 | * The command description 50 | * 51 | * @method description 52 | * 53 | * @return {String} 54 | */ 55 | static get description () { 56 | return 'Run instructions for a given module' 57 | } 58 | 59 | /** 60 | * Handle method executed by ace when command runs. It will 61 | * install a module and run post install instructions 62 | * 63 | * @method handle 64 | * 65 | * @return {void} 66 | */ 67 | async handle ({ directory }, options) { 68 | await this.invoke(async () => { 69 | const modulePath = path.isAbsolute(directory) ? directory : path.join(process.cwd(), directory) 70 | const name = options.name || path.basename(modulePath) 71 | const Context = require('./Context') 72 | const ctx = new Context(this, this.Helpers) 73 | 74 | await require('../../Services/run-instructions')(ctx, modulePath) 75 | await require('../../Services/render-instructions-md')(modulePath, name) 76 | }) 77 | } 78 | } 79 | 80 | module.exports = Instructions 81 | -------------------------------------------------------------------------------- /src/Commands/KeyGenerate/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const BaseCommand = require('../Base') 14 | 15 | /** 16 | * Generate unique application key 17 | * 18 | * @class KeyGenerate 19 | * @constructor 20 | */ 21 | class KeyGenerate extends BaseCommand { 22 | /** 23 | * The command signature used by ace 24 | * 25 | * @method signature 26 | * 27 | * @return {String} 28 | */ 29 | static get signature () { 30 | return ` 31 | key:generate 32 | { -f, --force: Forcefully generate the key in production environment } 33 | { --env=@value: .env file location } 34 | { -s, --size=@value: The key size which defaults to 32 characters } 35 | { --echo: Echo the key instead of writing to the file } 36 | ` 37 | } 38 | 39 | /** 40 | * The command description used by ace 41 | * 42 | * @method description 43 | * 44 | * @return {String} 45 | */ 46 | static get description () { 47 | return 'Generate secret key for the app' 48 | } 49 | 50 | /** 51 | * Reads the content of `.env` file and returns it as 52 | * an object 53 | * 54 | * @method getEnvContent 55 | * 56 | * @param {String} envPath 57 | * 58 | * @return {Object} 59 | */ 60 | async getEnvContent (envPath) { 61 | const dotEnvContents = await this.readFile(envPath) 62 | return require('dotenv').parse(dotEnvContents) 63 | } 64 | 65 | /** 66 | * Updates the `.env` file by converting the object back 67 | * to a valid string 68 | * 69 | * @method updateEnvContents 70 | * 71 | * @param {String} envPath 72 | * @param {Object} envHash 73 | * 74 | * @return {void} 75 | */ 76 | async updateEnvContents (envPath, envHash) { 77 | const updatedContents = Object.keys(envHash).map((key) => { 78 | return `${key}=${envHash[key]}` 79 | }).join('\n') 80 | 81 | await this.writeFile(envPath, updatedContents) 82 | } 83 | 84 | /** 85 | * Invoked by ace 86 | * 87 | * @method handle 88 | * 89 | * @param {Object} args 90 | * @param {Object} options 91 | * 92 | * @return {void} 93 | */ 94 | async handle (args, options) { 95 | const size = options.size ? Number(options.size) : 32 96 | const key = require('randomstring').generate(size) 97 | 98 | /** 99 | * Echo key to console when echo is set to true 100 | * and return 101 | */ 102 | if (options.echo) { 103 | console.log(`APP_KEY=${key}`) 104 | return 105 | } 106 | 107 | await this.invoke(async () => { 108 | this.ensureCanRunInProduction(options) 109 | await this.ensureInProjectRoot() 110 | 111 | const env = options.env || '.env' 112 | const pathToEnv = path.isAbsolute(env) ? env : path.join(process.cwd(), env) 113 | 114 | const envHash = await this.getEnvContent(pathToEnv) 115 | await this.updateEnvContents(pathToEnv, Object.assign(envHash, { APP_KEY: key })) 116 | 117 | this.completed('generated', 'unique APP_KEY') 118 | }) 119 | } 120 | } 121 | 122 | module.exports = KeyGenerate 123 | -------------------------------------------------------------------------------- /src/Commands/Make/Base.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const BaseCommand = require('../Base') 14 | const debug = require('debug')('adonis:cli') 15 | 16 | const options = { 17 | appDir: 'app', 18 | dirs: { 19 | httpControllers: 'Controllers/Http', 20 | wsControllers: 'Controllers/Ws', 21 | models: 'Models', 22 | traits: 'Models/Traits', 23 | hooks: 'Models/Hooks', 24 | listeners: 'Listeners', 25 | exceptions: 'Exceptions', 26 | middleware: 'Middleware', 27 | commands: 'Commands', 28 | views: 'resources/views', 29 | migrations: 'database/migrations', 30 | seeds: 'database/seeds', 31 | providers: 'providers' 32 | } 33 | } 34 | 35 | class MakeBase extends BaseCommand { 36 | /** 37 | * Generates the blueprint for a given resources 38 | * using pre-defined template 39 | * 40 | * @method generateBlueprint 41 | * 42 | * @param {String} templateFor 43 | * @param {String} name 44 | * @param {Object} flags 45 | * 46 | * @return {void} 47 | */ 48 | async generateBlueprint (templateFor, name, flags) { 49 | const generators = require('../../Generators') 50 | 51 | options.appRoot = options.appRoot || process.cwd() 52 | 53 | debug('blueprint options %j', options) 54 | 55 | const templateFile = path.join(__dirname, '../../Generators/templates', `${templateFor}.mustache`) 56 | 57 | const filePath = generators[templateFor].getFilePath(name, options) 58 | const data = generators[templateFor].getData(path.basename(name), flags) 59 | 60 | debug('blueprint file path %s', filePath) 61 | debug('blueprint data %j', data) 62 | 63 | const templateContents = await this.readFile(templateFile, 'utf-8') 64 | await this.generateFile(filePath, templateContents, data) 65 | 66 | const createdFile = filePath.replace(process.cwd(), '').replace(path.sep, '') 67 | console.log(`${this.icon('success')} ${this.chalk.green('create')} ${createdFile}`) 68 | 69 | return { file: createdFile, namespace: this.getNamespace(createdFile, templateFor) } 70 | } 71 | 72 | /** 73 | * Returns namespace for a given resource 74 | * 75 | * @method getNamespace 76 | * 77 | * @param {String} filePath 78 | * @param {String} namespaceFor 79 | * 80 | * @return {String} 81 | */ 82 | getNamespace (filePath, namespaceFor) { 83 | const dir = options.dirs[namespaceFor] || options.dirs[`${namespaceFor}s`] 84 | return `App/${dir}/${path.basename(filePath).replace('.js', '')}` 85 | } 86 | 87 | /** 88 | * Print lines to the console 89 | * 90 | * @method printInstructions 91 | * 92 | * @param {Array} lines 93 | * 94 | * @return {void} 95 | */ 96 | printInstructions (heading, steps) { 97 | console.log( 98 | ['', `👉 ${heading}`, ''] 99 | .concat(steps.map((line) => `${this.chalk.dim('→')} ${line}`)) 100 | .concat(['']) 101 | .join('\n') 102 | ) 103 | } 104 | } 105 | 106 | module.exports = MakeBase 107 | -------------------------------------------------------------------------------- /src/Commands/Make/Command.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Creates a new ace command 16 | * 17 | * @class MakeCommand 18 | * @constructor 19 | */ 20 | class MakeCommand extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:command 31 | { name: Name of the command } 32 | ` 33 | } 34 | 35 | /** 36 | * The command description 37 | * 38 | * @method description 39 | * 40 | * @return {String} 41 | */ 42 | static get description () { 43 | return 'Make a new ace command' 44 | } 45 | 46 | /** 47 | * Handle method executed by ace 48 | * 49 | * @method handle 50 | * 51 | * @param {String} options.name 52 | * @param {String} options.type 53 | * 54 | * @return {void} 55 | */ 56 | async handle ({ name }) { 57 | await this.invoke(async () => { 58 | await this.ensureInProjectRoot() 59 | const { namespace } = await this.generateBlueprint('command', name, {}) 60 | 61 | const steps = [ 62 | `Open ${this.chalk.cyan('start/app.js')}`, 63 | `Add ${this.chalk.cyan(namespace)} to commands array` 64 | ] 65 | 66 | this.printInstructions('Register command as follows', steps) 67 | }) 68 | } 69 | } 70 | 71 | module.exports = MakeCommand 72 | -------------------------------------------------------------------------------- /src/Commands/Make/Controller.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new HTTP or Ws controller 16 | * 17 | * @class MakeController 18 | * @constructor 19 | */ 20 | class MakeController extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:controller 31 | { name: Name of the controller } 32 | { --resource: Create resourceful methods on the controller } 33 | { --type=@value: The type can be http or ws } 34 | ` 35 | } 36 | 37 | /** 38 | * The command description 39 | * 40 | * @method description 41 | * 42 | * @return {String} 43 | */ 44 | static get description () { 45 | return 'Make a new HTTP or Websocket channel controller' 46 | } 47 | 48 | /** 49 | * Returns the resource type for the controller 50 | * 51 | * @method _getResourceType 52 | * 53 | * @param {String} type 54 | * 55 | * @return {String} 56 | * 57 | * @private 58 | */ 59 | async _getResourceType (type) { 60 | if (!type || ['ws', 'http'].indexOf(type) <= -1) { 61 | type = await this 62 | .on('validate', (value) => !!value) 63 | .choice('Select controller type', [ 64 | { 65 | value: 'http', 66 | name: 'For HTTP requests' 67 | }, 68 | { 69 | value: 'ws', 70 | name: 'For Websocket channel' 71 | } 72 | ]) 73 | } 74 | 75 | return type === 'ws' ? 'wsController' : 'httpController' 76 | } 77 | 78 | /** 79 | * Handle method executed by ace 80 | * 81 | * @method handle 82 | * 83 | * @param {String} options.name 84 | * @param {String} options.type 85 | * 86 | * @return {void} 87 | */ 88 | async handle ({ name }, { type, resource }) { 89 | await this.invoke(async () => { 90 | await this.ensureInProjectRoot() 91 | const resourceType = await this._getResourceType(type) 92 | await this.generateBlueprint(resourceType, name, { resource }) 93 | }) 94 | } 95 | } 96 | 97 | module.exports = MakeController 98 | -------------------------------------------------------------------------------- /src/Commands/Make/Exception.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new exception class 16 | * 17 | * @class MakeException 18 | * @constructor 19 | */ 20 | class MakeException extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:exception 31 | { name: Name of the exception } 32 | ` 33 | } 34 | 35 | /** 36 | * The command description 37 | * 38 | * @method description 39 | * 40 | * @return {String} 41 | */ 42 | static get description () { 43 | return 'Make a new exception' 44 | } 45 | 46 | /** 47 | * Handle method executed by ace 48 | * 49 | * @method handle 50 | * 51 | * @param {String} options.name 52 | * @param {String} options.type 53 | * 54 | * @return {void} 55 | */ 56 | async handle ({ name }) { 57 | await this.invoke(async () => { 58 | await this.ensureInProjectRoot() 59 | await this.generateBlueprint('exception', name, {}) 60 | }) 61 | } 62 | } 63 | 64 | module.exports = MakeException 65 | -------------------------------------------------------------------------------- /src/Commands/Make/ExceptionHandler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const BaseCommand = require('./Base') 14 | 15 | /** 16 | * Make a new global exception handler 17 | * 18 | * @class MakeExceptionHandler 19 | * @constructor 20 | */ 21 | class MakeExceptionHandler extends BaseCommand { 22 | /** 23 | * The command signature 24 | * 25 | * @method signature 26 | * 27 | * @return {String} 28 | */ 29 | static get signature () { 30 | return 'make:ehandler' 31 | } 32 | 33 | /** 34 | * The command description 35 | * 36 | * @method description 37 | * 38 | * @return {String} 39 | */ 40 | static get description () { 41 | return 'Make a new global exception handler' 42 | } 43 | 44 | /** 45 | * Handle method executed by ace 46 | * 47 | * @method handle 48 | * 49 | * @return {void} 50 | */ 51 | async handle () { 52 | await this.invoke(async () => { 53 | await this.ensureInProjectRoot() 54 | 55 | const packageFile = require(path.join(process.cwd(), 'package.json')) 56 | const version = packageFile['adonis-version'] || packageFile['version'] 57 | 58 | /** 59 | * The exceptions template is different for 4.0 and newer 60 | * versions. 61 | */ 62 | await this.generateBlueprint('exceptionHandler', '', { 63 | new: version !== '4.0.0' 64 | }) 65 | }) 66 | } 67 | } 68 | 69 | module.exports = MakeExceptionHandler 70 | -------------------------------------------------------------------------------- /src/Commands/Make/Hook.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new lucid model hook 16 | * 17 | * @class MakeModelHook 18 | * @constructor 19 | */ 20 | class MakeModelHook extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:hook 31 | { name: Name of the hook } 32 | { -m, --method=@value : The method to be created on hook } 33 | ` 34 | } 35 | 36 | /** 37 | * The command description 38 | * 39 | * @method description 40 | * 41 | * @return {String} 42 | */ 43 | static get description () { 44 | return 'Make a new lucid model hook' 45 | } 46 | 47 | /** 48 | * Handle method executed by ace 49 | * 50 | * @method handle 51 | * 52 | * @param {String} options.name 53 | * @param {String} options.type 54 | * 55 | * @return {void} 56 | */ 57 | async handle ({ name }, { method }) { 58 | await this.invoke(async () => { 59 | await this.ensureInProjectRoot() 60 | await this.generateBlueprint('hook', name, { method }) 61 | }) 62 | } 63 | } 64 | 65 | module.exports = MakeModelHook 66 | -------------------------------------------------------------------------------- /src/Commands/Make/Listener.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new redis or event listener 16 | * 17 | * @class MakeListener 18 | * @constructor 19 | */ 20 | class MakeListener extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:listener 31 | { name: Name of the listener } 32 | { -m, --method=@value : The method to be created on listener } 33 | ` 34 | } 35 | 36 | /** 37 | * The command description 38 | * 39 | * @method description 40 | * 41 | * @return {String} 42 | */ 43 | static get description () { 44 | return 'Make a new event or redis listener' 45 | } 46 | 47 | /** 48 | * Handle method executed by ace 49 | * 50 | * @method handle 51 | * 52 | * @param {String} options.name 53 | * @param {String} options.type 54 | * 55 | * @return {void} 56 | */ 57 | async handle ({ name }, { method }) { 58 | await this.invoke(async () => { 59 | await this.ensureInProjectRoot() 60 | await this.generateBlueprint('listener', name, { method }) 61 | }) 62 | } 63 | } 64 | 65 | module.exports = MakeListener 66 | -------------------------------------------------------------------------------- /src/Commands/Make/Middleware.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new HTTP or Ws middleware 16 | * 17 | * @class MakeMiddleware 18 | * @constructor 19 | */ 20 | class MakeMiddleware extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:middleware 31 | { name: Name of the middleware } 32 | { --type=@value: The type can be http, ws or both } 33 | ` 34 | } 35 | 36 | /** 37 | * The command description 38 | * 39 | * @method description 40 | * 41 | * @return {String} 42 | */ 43 | static get description () { 44 | return 'Make a new HTTP or Ws Middleware' 45 | } 46 | 47 | /** 48 | * Returns the resource type for the middleware 49 | * 50 | * @method _getResourceType 51 | * 52 | * @param {String} type 53 | * 54 | * @return {String} 55 | * 56 | * @private 57 | */ 58 | async _getResourceType (type) { 59 | if (!type || ['ws', 'http', 'both'].indexOf(type) <= -1) { 60 | type = await this 61 | .on('validate', (value) => !!value) 62 | .choice('Select middleware type', [ 63 | { 64 | name: 'For HTTP requests', 65 | value: 'http' 66 | }, 67 | { 68 | name: 'For Websocket requests', 69 | value: 'ws' 70 | }, 71 | { 72 | name: 'For both HTTP and Websocket requests', 73 | value: 'both' 74 | } 75 | ]) 76 | } 77 | 78 | return type 79 | } 80 | 81 | /** 82 | * Handle method executed by ace 83 | * 84 | * @method handle 85 | * 86 | * @param {String} options.name 87 | * @param {String} options.type 88 | * 89 | * @return {void} 90 | */ 91 | async handle ({ name }, { type }) { 92 | await this.invoke(async () => { 93 | await this.ensureInProjectRoot() 94 | 95 | const resourceType = await this._getResourceType(type) 96 | const { namespace } = await this.generateBlueprint('middleware', name, { type: resourceType }) 97 | 98 | const steps = [] 99 | 100 | /** 101 | * Push instructions for http if resource type was 102 | * http or both 103 | */ 104 | if (resourceType === 'both' || resourceType === 'http') { 105 | steps.push(`Open ${this.chalk.cyan('start/kernel.js')} file`) 106 | steps.push(`Register ${this.chalk.cyan(namespace)} under global or named middleware`) 107 | } 108 | 109 | /** 110 | * Push instructions for ws if resource type was 111 | * ws or both 112 | */ 113 | if (resourceType === 'both' || resourceType === 'ws') { 114 | steps.push(`Open ${this.chalk.cyan('start/ws.js')} file`) 115 | steps.push(`Register ${this.chalk.cyan(namespace)} under global or named middleware`) 116 | } 117 | 118 | this.printInstructions('Register middleware as follows', steps) 119 | }) 120 | } 121 | } 122 | 123 | module.exports = MakeMiddleware 124 | -------------------------------------------------------------------------------- /src/Commands/Make/Migration.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-lucid 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new migration file 16 | * 17 | * @class MakeMigration 18 | * @constructor 19 | */ 20 | class MakeMigration extends BaseCommand { 21 | /** 22 | * Command signature required by ace 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:migration 31 | { name: Name of migration file, current timestamp will be prepended to the name } 32 | { --action?=@value : Choose an action to \`create\` or \`select\` a table } 33 | ` 34 | } 35 | 36 | /** 37 | * Command description 38 | * 39 | * @method description 40 | * 41 | * @return {String} 42 | */ 43 | static get description () { 44 | return 'Create a new migration file' 45 | } 46 | 47 | /** 48 | * Returns the migration action 49 | * 50 | * @method _getActionType 51 | * 52 | * @param {String} action 53 | * 54 | * @return {String} 55 | */ 56 | async _getActionType (action) { 57 | if (!action || ['create', 'select'].indexOf(action) <= -1) { 58 | action = await this.choice('Choose an action', [ 59 | { 60 | value: 'create', 61 | name: 'Create table' 62 | }, 63 | { 64 | value: 'select', 65 | name: 'Select table' 66 | } 67 | ]) 68 | } 69 | 70 | return action 71 | } 72 | 73 | /** 74 | * Method to be called when this command is executed 75 | * 76 | * @method handle 77 | * 78 | * @param {String} options.name 79 | * @param {String} options.action 80 | * 81 | * @return {void|String} - Returns abs path to created file when command 82 | * is not executed by ace. 83 | */ 84 | async handle ({ name }, { action }) { 85 | await this.invoke(async () => { 86 | await this.ensureInProjectRoot() 87 | 88 | const actionType = await this._getActionType(action) 89 | await this.generateBlueprint('schema', name, { action: actionType }) 90 | }) 91 | } 92 | } 93 | 94 | module.exports = MakeMigration 95 | -------------------------------------------------------------------------------- /src/Commands/Make/Model.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new lucid model 16 | * 17 | * @class MakeModel 18 | * @constructor 19 | */ 20 | class MakeModel extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:model 31 | { name: Name of the model } 32 | { -m, --migration: Generate migration for the model } 33 | { -c, --controller: Generate resourceful controller for the model } 34 | ` 35 | } 36 | 37 | /** 38 | * The command description 39 | * 40 | * @method description 41 | * 42 | * @return {String} 43 | */ 44 | static get description () { 45 | return 'Make a new lucid model' 46 | } 47 | 48 | /** 49 | * Handle method executed by ace 50 | * 51 | * @method handle 52 | * 53 | * @param {String} options.name 54 | * @param {String} options.type 55 | * 56 | * @return {void} 57 | */ 58 | async handle ({ name }, { migration, controller }) { 59 | await this.invoke(async () => { 60 | await this.ensureInProjectRoot() 61 | await this.generateBlueprint('model', name, {}) 62 | 63 | if (migration) { 64 | await this.generateBlueprint('schema', name, { action: 'create' }) 65 | } 66 | 67 | if (controller) { 68 | await this.generateBlueprint('httpController', name, { resource: controller }) 69 | } 70 | }) 71 | } 72 | } 73 | 74 | module.exports = MakeModel 75 | -------------------------------------------------------------------------------- /src/Commands/Make/Provider.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new provider 16 | * 17 | * @class MakeProvider 18 | * @constructor 19 | */ 20 | class MakeProvider extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:provider 31 | { name: Name of the provider } 32 | ` 33 | } 34 | 35 | /** 36 | * The command description 37 | * 38 | * @method description 39 | * 40 | * @return {String} 41 | */ 42 | static get description () { 43 | return 'Make a new provider' 44 | } 45 | 46 | /** 47 | * Handle method executed by ace 48 | * 49 | * @method handle 50 | * 51 | * @param {String} options.name 52 | * @param {String} options.type 53 | * 54 | * @return {void} 55 | */ 56 | async handle ({ name }) { 57 | await this.invoke(async () => { 58 | await this.ensureInProjectRoot() 59 | await this.generateBlueprint('provider', name, {}) 60 | }) 61 | } 62 | } 63 | 64 | module.exports = MakeProvider 65 | -------------------------------------------------------------------------------- /src/Commands/Make/Seed.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-lucid 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new seed file 16 | * 17 | * @class MakeSeed 18 | * @constructor 19 | */ 20 | class MakeSeed extends BaseCommand { 21 | /** 22 | * Command signature required by ace 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:seed 31 | { name?=Database: Name of the seed file } 32 | ` 33 | } 34 | 35 | /** 36 | * Command description 37 | * 38 | * @method description 39 | * 40 | * @return {String} 41 | */ 42 | static get description () { 43 | return 'Create a database seeder' 44 | } 45 | 46 | /** 47 | * Method to be called when this command is executed 48 | * 49 | * @method handle 50 | * 51 | * @param {String} options.name 52 | */ 53 | async handle ({ name }) { 54 | await this.invoke(async () => { 55 | await this.ensureInProjectRoot() 56 | await this.generateBlueprint('seed', name) 57 | }) 58 | } 59 | } 60 | 61 | module.exports = MakeSeed 62 | -------------------------------------------------------------------------------- /src/Commands/Make/Trait.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new lucid trait 16 | * 17 | * @class MakeTrait 18 | * @constructor 19 | */ 20 | class MakeTrait extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:trait 31 | { name: Name of the trait } 32 | ` 33 | } 34 | 35 | /** 36 | * The command description 37 | * 38 | * @method description 39 | * 40 | * @return {String} 41 | */ 42 | static get description () { 43 | return 'Make a new lucid trait' 44 | } 45 | 46 | /** 47 | * Handle method executed by ace 48 | * 49 | * @method handle 50 | * 51 | * @param {String} options.name 52 | * 53 | * @return {void} 54 | */ 55 | async handle ({ name }) { 56 | await this.invoke(async () => { 57 | await this.ensureInProjectRoot() 58 | await this.generateBlueprint('trait', name, {}) 59 | }) 60 | } 61 | } 62 | 63 | module.exports = MakeTrait 64 | -------------------------------------------------------------------------------- /src/Commands/Make/View.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('./Base') 13 | 14 | /** 15 | * Make a new edge view 16 | * 17 | * @class MakeView 18 | * @constructor 19 | */ 20 | class MakeView extends BaseCommand { 21 | /** 22 | * The command signature 23 | * 24 | * @method signature 25 | * 26 | * @return {String} 27 | */ 28 | static get signature () { 29 | return ` 30 | make:view 31 | { name: Name of the view } 32 | { -l, --layout=@value: Define a layout to extend } 33 | ` 34 | } 35 | 36 | /** 37 | * The command description 38 | * 39 | * @method description 40 | * 41 | * @return {String} 42 | */ 43 | static get description () { 44 | return 'Make a view file' 45 | } 46 | 47 | /** 48 | * Handle method executed by ace 49 | * 50 | * @method handle 51 | * 52 | * @param {String} options.name 53 | * @param {String} options.type 54 | * 55 | * @return {void} 56 | */ 57 | async handle ({ name }, { layout }) { 58 | await this.invoke(async () => { 59 | await this.ensureInProjectRoot() 60 | await this.generateBlueprint('view', name, { layout }) 61 | }) 62 | } 63 | } 64 | 65 | module.exports = MakeView 66 | -------------------------------------------------------------------------------- /src/Commands/New/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const BaseCommand = require('../Base') 14 | 15 | /** 16 | * This command performs a series of operations 17 | * to be create a new Adonisjs application. 18 | * 19 | * @class NewApp 20 | */ 21 | class NewApp extends BaseCommand { 22 | /** 23 | * The command signature required by ace 24 | * 25 | * @attribute signature 26 | * @static 27 | * 28 | * @return {String} 29 | */ 30 | static get signature () { 31 | return ` 32 | new 33 | { name : Name of the project directory } 34 | { --api-only : Scaffold project for api server } 35 | { --api: Scaffold project for api server } 36 | { --slim : Scaffold smallest possible Adonisjs application } 37 | { --blueprint?=@value : Path to github project blueprint } 38 | { --branch?=@value : Specify git branch for project blueprint } 39 | { --skip-install : Do not install modules from npm } 40 | { --yarn : Use yarn over npm for modules installation } 41 | { --cnpm: Use cnpm over npm for installation } 42 | { --raw : Disable animations and colored output } 43 | ` 44 | } 45 | 46 | /** 47 | * The command description required by ace 48 | * 49 | * @attribute description 50 | * 51 | * @return {String} 52 | */ 53 | static get description () { 54 | return 'Create a new AdonisJs application' 55 | } 56 | 57 | /** 58 | * Returns the actual blueprint to be used for 59 | * cloning the repo. It will go over the cli 60 | * options and returns the most appropriate 61 | * one. 62 | * 63 | * @method _getBluePrint 64 | * 65 | * @param {Object} options 66 | * 67 | * @return {String} 68 | * 69 | * @private 70 | */ 71 | _getBluePrint (options) { 72 | /** 73 | * Use the explicitly defined blueprint 74 | * over any other options. 75 | */ 76 | if (options.blueprint) { 77 | return options.blueprint 78 | } 79 | 80 | /** 81 | * If we used the flag --api-only or --api we want 82 | * to fetch the API blueprint. 83 | */ 84 | if (options.apiOnly || options.api) { 85 | return 'adonisjs/adonis-api-app' 86 | } 87 | 88 | /** 89 | * If we used the flag --slim we want to fetch 90 | * the SLIM blueprint. 91 | */ 92 | if (options.slim) { 93 | return 'adonisjs/adonis-slim-app' 94 | } 95 | 96 | /** 97 | * If none flag has been defiend we fallbacke 98 | * to the Fullstack blueprint. 99 | */ 100 | return 'adonisjs/adonis-fullstack-app' 101 | } 102 | 103 | /** 104 | * Ensure node version is correct, then make sure app path is 105 | * empty and finally clone the repo and remove `.git` dir. 106 | * 107 | * @method _setupProjectDirectory 108 | * 109 | * @param {Object} stepsCounter 110 | * @param {String} appPath 111 | * @param {Object} options 112 | * 113 | * @return {void} 114 | * 115 | * @private 116 | */ 117 | async _setupProjectDirectory (stepsCounter, appPath, options) { 118 | await require('../../Services/check-node-version')(stepsCounter) 119 | await require('../../Services/verify-existing-folder')(appPath, stepsCounter) 120 | await require('../../Services/clone')(this._getBluePrint(options), appPath, stepsCounter, options.branch) 121 | await this.removeDir(path.join(appPath, '.git')) 122 | } 123 | 124 | /** 125 | * Install dependencies when `skip-install` flag has not been 126 | * passed 127 | * 128 | * @method _installDependencies 129 | * 130 | * @param {Object} stepsCounter 131 | * @param {String} appPath 132 | * @param {Object} options 133 | * 134 | * @return {void} 135 | * 136 | * @private 137 | */ 138 | async _installDependencies (stepsCounter, appPath, options) { 139 | if (options.skipInstall) { 140 | return 141 | } 142 | await require('../../Services/install')(options.yarn ? 'yarn' : (options.cnpm ? 'cnpm' : 'npm'), stepsCounter) 143 | } 144 | 145 | /** 146 | * Copy the `.env` file and generate the app key after installation 147 | * of modules have been done. 148 | * 149 | * @method _postInstallation 150 | * 151 | * @param {Object} stepsCounter 152 | * @param {String} appPath 153 | * 154 | * @return {void} 155 | * 156 | * @private 157 | */ 158 | async _postInstallation (stepsCounter, appPath) { 159 | await require('../../Services/copy-env-file')(appPath, stepsCounter) 160 | await require('../../Services/generate-app-key')(stepsCounter) 161 | } 162 | 163 | /** 164 | * Prints a message after a new project has been created 165 | * 166 | * @method _onBoardForNewProject 167 | * 168 | * @param {String} appName 169 | * 170 | * @return {void} 171 | * 172 | * @private 173 | */ 174 | _onBoardForNewProject (appName) { 175 | const lines = [ 176 | '', 177 | '🚀 Successfully created project', 178 | '👉 Get started with the following commands', 179 | '', 180 | `${this.chalk.dim('$')} ${this.chalk.cyan(`cd ${appName}`)}`, 181 | `${this.chalk.dim('$')} ${this.chalk.cyan('adonis serve --dev')}`, 182 | '' 183 | ] 184 | 185 | lines.forEach((line) => { 186 | console.log(line) 187 | }) 188 | } 189 | 190 | /** 191 | * Handle method executed by ace to setup a new app 192 | * 193 | * @method handle 194 | * 195 | * @param {String} options.name 196 | * @param {Object} options 197 | * 198 | * @return {void} 199 | */ 200 | async handle ({ name }, options) { 201 | const appPath = path.join(process.cwd(), name) 202 | const stepsCounter = this.initiateSteps(options.skipInstall ? 5 : 6, options) 203 | 204 | this.invoke(async () => { 205 | this.dumpAsciiLogo() 206 | await this._setupProjectDirectory(stepsCounter, appPath, options) 207 | 208 | process.chdir(appPath) 209 | 210 | await this._installDependencies(stepsCounter, appPath, options) 211 | await this._postInstallation(stepsCounter, appPath) 212 | this._onBoardForNewProject(name) 213 | }) 214 | } 215 | } 216 | 217 | module.exports = NewApp 218 | -------------------------------------------------------------------------------- /src/Commands/Repl/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const fs = require('fs') 13 | const os = require('os') 14 | const path = require('path') 15 | const { Command } = require('../../../lib/ace') 16 | 17 | const historyFile = path.join(os.homedir(), '/.adonis_repl_history') 18 | 19 | /** 20 | * Start the repl server session 21 | * 22 | * @class Repl 23 | * @constructor 24 | */ 25 | class Repl extends Command { 26 | /** 27 | * The command signature used by ace 28 | * 29 | * @method signature 30 | * 31 | * @return {String} 32 | */ 33 | static get signature () { 34 | return 'repl' 35 | } 36 | 37 | /** 38 | * The command description used by ace 39 | * 40 | * @method description 41 | * 42 | * @return {String} 43 | */ 44 | static get description () { 45 | return 'Start a new repl session' 46 | } 47 | 48 | /** 49 | * Reads the history file 50 | * 51 | * @param {Object} repl 52 | * 53 | * @private 54 | */ 55 | _readHistoryFile (repl) { 56 | try { 57 | fs.statSync(historyFile) 58 | } catch (error) { 59 | fs.closeSync(fs.openSync(historyFile, 'w')) 60 | } 61 | 62 | repl.rli.history = fs.readFileSync(historyFile, 'utf-8').split('\n').reverse() 63 | repl.rli.history.shift() 64 | repl.rli.historyIndex = -1 65 | } 66 | 67 | /** 68 | * Save the history to the history file. 69 | * 70 | * @param {Object} repl 71 | * 72 | * @private 73 | */ 74 | _addHistorySaveListener (repl) { 75 | const fd = fs.openSync(historyFile, 'a') 76 | repl.rli.addListener('line', (code) => { 77 | if (code && code !== '.history') { 78 | fs.write(fd, `${code}\n`, (error) => { if (error) console.log(error) }) 79 | return 80 | } 81 | repl.rli.historyIndex++ 82 | repl.rli.history.pop() 83 | }) 84 | 85 | process.on('exit', function () { 86 | fs.closeSync(fd) 87 | }) 88 | } 89 | 90 | /** 91 | * Method executed by ace to start the command line 92 | * repl 93 | * 94 | * @method handle 95 | * 96 | * @return {void} 97 | */ 98 | async handle () { 99 | const awaitOutside = require('adonis-await-outside') 100 | const server = require('repl').start() 101 | 102 | if (typeof (global.use) === 'undefined') { 103 | this.info('You are running repl outside of Adonisjs app') 104 | } else { 105 | server.context.use = global.use 106 | server.context.make = global.make 107 | } 108 | 109 | this._readHistoryFile(server) 110 | this._addHistorySaveListener(server) 111 | awaitOutside.addAwaitOutsideToReplServer(server) 112 | } 113 | } 114 | 115 | module.exports = Repl 116 | -------------------------------------------------------------------------------- /src/Commands/RouteList/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const BaseCommand = require('../Base') 13 | 14 | /** 15 | * Start the repl server session 16 | * 17 | * @class RouteList 18 | * @constructor 19 | */ 20 | class RouteList extends BaseCommand { 21 | static get inject () { 22 | return ['Adonis/Src/Route'] 23 | } 24 | 25 | /** 26 | * The command signature used by ace 27 | * 28 | * @method signature 29 | * 30 | * @return {String} 31 | */ 32 | static get signature () { 33 | return 'route:list' 34 | } 35 | 36 | /** 37 | * The command description used by ace 38 | * 39 | * @method description 40 | * 41 | * @return {String} 42 | */ 43 | static get description () { 44 | return 'List all registered routes' 45 | } 46 | 47 | constructor (Route) { 48 | super() 49 | this.Route = Route 50 | } 51 | 52 | /** 53 | * Returns stringfied version of a function 54 | * 55 | * @method _toString 56 | * 57 | * @param {Function} fn 58 | * 59 | * @return {String} 60 | * 61 | * @private 62 | */ 63 | _toString (fn) { 64 | return typeof (fn) === 'string' ? fn : 'Closure' 65 | } 66 | 67 | /** 68 | * Returns the route row for the table 69 | * 70 | * @method _getRow 71 | * 72 | * @param {Object} route 73 | * 74 | * @return {Array} 75 | */ 76 | _getRow (route) { 77 | const routeJson = route.toJSON() 78 | 79 | return [ 80 | routeJson.route, 81 | routeJson.verbs.join(','), 82 | this._toString(routeJson.handler), 83 | routeJson.middleware.map((middleware) => this._toString(middleware)).join(','), 84 | routeJson.name, 85 | routeJson.domain || '' 86 | ] 87 | } 88 | 89 | /** 90 | * Method executed by ace to list all routes 91 | * 92 | * @method handle 93 | * 94 | * @return {void} 95 | */ 96 | async handle () { 97 | this.invoke(async () => { 98 | await this.ensureInProjectRoot() 99 | 100 | this.table( 101 | ['Route', 'Verb(s)', 'Handler', 'Middleware', 'Name', 'Domain'], 102 | this.Route.list().map(this._getRow.bind(this)) 103 | ) 104 | }) 105 | } 106 | } 107 | 108 | module.exports = RouteList 109 | -------------------------------------------------------------------------------- /src/Commands/Serve/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const { Command } = require('../../../lib/ace') 14 | 15 | /** 16 | * Serve the application using forever 17 | * 18 | * @class Serve 19 | * @constructor 20 | */ 21 | class Serve extends Command { 22 | /** 23 | * The command signature used by ace 24 | * 25 | * @method signature 26 | * 27 | * @return {String} 28 | */ 29 | static get signature () { 30 | return ` 31 | serve 32 | { --dev : Start development server } 33 | { -w, --watch=@value : A custom set of only files to watch }, 34 | { -e, --ext=@value : A custom set of extensions to watch. In development, they will be merged with the default .js and .json }, 35 | { -i, --ignore=@value : A custom set of folders to ignore watching }, 36 | { -p, --polling : Use polling to find file changes. Also required when using Docker } 37 | { --debug?=@value: Start server in debug mode } 38 | ` 39 | } 40 | 41 | /** 42 | * The command description used by ace 43 | * 44 | * @method description 45 | * 46 | * @return {String} 47 | */ 48 | static get description () { 49 | return 'Start Http server' 50 | } 51 | 52 | /** 53 | * Console message when server started 54 | * 55 | * @method started 56 | * 57 | * @package {Boolean} dev 58 | * 59 | * @return {void} 60 | */ 61 | started (dev, debug) { 62 | console.log('') 63 | console.log(`${this.chalk.bgGreen.black(' SERVER STARTED ')}`) 64 | if (debug) { 65 | console.log(`> Visit chrome://inspect to debug your app`) 66 | } 67 | if (dev) { 68 | console.log(`> Watching files for changes...`) 69 | } 70 | console.log('') 71 | } 72 | 73 | /** 74 | * This method is executed when nodemon restarts 75 | * 76 | * @method onRestart 77 | * 78 | * @param {Array} files 79 | * 80 | * @return {void} 81 | */ 82 | onRestart (files) { 83 | if (files.length > 1) { 84 | console.log(this.chalk.magenta('File(s) changed')) 85 | files.forEach((file) => console.log(file.replace(process.cwd(), '').replace(path.sep, ''))) 86 | } else { 87 | const fileName = files[0].replace(process.cwd(), '').replace(path.sep, '') 88 | console.log(`${this.chalk.magenta('changed')} ${fileName}`) 89 | } 90 | } 91 | 92 | /** 93 | * Message to log on crash 94 | * 95 | * @method onCrash 96 | * 97 | * @return {void} 98 | */ 99 | onCrash () { 100 | this.error('Application crashed, make sure to kill all related running process, fix the issue and re-run the app') 101 | } 102 | 103 | /** 104 | * Listening for on quite event 105 | * 106 | * @method onQuit 107 | * 108 | * @param {String} domain 109 | * 110 | * @return {void} 111 | */ 112 | onQuit () { 113 | process.exit(0) 114 | } 115 | 116 | /** 117 | * Method executed by ace to start the HTTP server 118 | * 119 | * @method handle 120 | * 121 | * @param {Object} args 122 | * @param {Boolean} options.dev 123 | * 124 | * @return {void} 125 | */ 126 | async handle (args, { dev, watch, debug, ignore, polling, ext }) { 127 | const acePath = path.join(process.cwd(), 'ace') 128 | const appFile = path.join(process.cwd(), 'server.js') 129 | const exists = await this.pathExists(acePath) 130 | 131 | if (!exists) { 132 | this.error('Make sure you are inside an adonisjs app to start the server') 133 | return 134 | } 135 | 136 | /** 137 | * If user has defined files to watch, then switch to 138 | * dev version automatically 139 | */ 140 | if (watch && typeof (watch) === 'string') { 141 | watch = watch.split(',').map((item) => item.trim()) 142 | dev = true 143 | } 144 | 145 | /** 146 | * The file extensions only when dev mode 147 | * is true 148 | */ 149 | if (dev) { 150 | ext = `${ext || ''} js json` 151 | } else { 152 | ext = ext || 'null' 153 | } 154 | 155 | /** 156 | * Directories to watch 157 | */ 158 | const watchDirs = watch || (dev ? [process.cwd(), '.env'] : []) 159 | 160 | /** 161 | * Custom debug port 162 | */ 163 | let execJsCommand = 'node' 164 | if (debug) { 165 | execJsCommand += ' --inspect' 166 | if (typeof (debug) === 'string') { 167 | execJsCommand += '=' + debug 168 | } 169 | } 170 | 171 | const nodemon = require('nodemon') 172 | 173 | nodemon({ 174 | script: appFile, 175 | execMap: { 176 | js: execJsCommand 177 | }, 178 | ext: ext, 179 | legacyWatch: !!polling, 180 | ignore: ['/tmp/*', '/resources/*', '/public/*'].concat(ignore || []).map((folder) => `${process.cwd()}/${folder}`), 181 | watch: watchDirs, 182 | stdin: false 183 | }) 184 | 185 | this.started(dev, debug) 186 | 187 | /** 188 | * Listeners 189 | */ 190 | nodemon 191 | .on('restart', this.onRestart.bind(this)) 192 | .on('crash', this.onCrash.bind(this)) 193 | .on('quit', () => (this.onQuit())) 194 | } 195 | } 196 | 197 | module.exports = Serve 198 | -------------------------------------------------------------------------------- /src/Commands/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * Exporting a list of internal commands 14 | * 15 | * @type {Array} 16 | */ 17 | module.exports = { 18 | new: require('./New'), 19 | addon: require('./Addon'), 20 | install: require('./Install'), 21 | serve: require('./Serve'), 22 | 'key:generate': require('./KeyGenerate'), 23 | 'make:controller': require('./Make/Controller'), 24 | 'make:model': require('./Make/Model'), 25 | 'make:trait': require('./Make/Trait'), 26 | 'make:view': require('./Make/View'), 27 | 'make:middleware': require('./Make/Middleware'), 28 | 'make:command': require('./Make/Command'), 29 | 'make:exception': require('./Make/Exception'), 30 | 'make:hook': require('./Make/Hook'), 31 | 'make:migration': require('./Make/Migration'), 32 | 'make:listener': require('./Make/Listener'), 33 | 'make:provider': require('./Make/Provider'), 34 | 'repl': require('./Repl'), 35 | 'make:ehandler': require('./Make/ExceptionHandler'), 36 | 'make:seed': require('./Make/Seed'), 37 | 'route:list': require('./RouteList'), 38 | 'run:instructions': require('./Instructions') 39 | } 40 | -------------------------------------------------------------------------------- /src/Generators/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const _ = require('lodash') 14 | const pluralize = require('pluralize') 15 | const generators = exports = module.exports = {} 16 | 17 | generators.provider = { 18 | /** 19 | * Returns the data to be sent to the provider 20 | * template 21 | * 22 | * @method getData 23 | * 24 | * @param {String} name 25 | * @param {Object} flags 26 | * 27 | * @return {Object} 28 | */ 29 | getData (name, flags) { 30 | return { 31 | name: this.getFileName(name) 32 | } 33 | }, 34 | 35 | /** 36 | * Returns file name for provider. 37 | * 38 | * @method getFileName 39 | * 40 | * @param {String} name 41 | * 42 | * @return {String} 43 | */ 44 | getFileName (name) { 45 | name = name.replace(/provider/ig, '') 46 | return `${pluralize.singular(_.upperFirst(_.camelCase(name)))}Provider` 47 | }, 48 | 49 | /** 50 | * Returns path to the provider file 51 | * 52 | * @method getFilePath 53 | * 54 | * @param {String} name 55 | * @param {Object} options 56 | * 57 | * @return {String} 58 | */ 59 | getFilePath (name, options) { 60 | const baseName = path.basename(name) 61 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 62 | return path.join(options.appRoot, options.dirs.providers, normalizedName) + '.js' 63 | } 64 | } 65 | 66 | generators.httpController = { 67 | /** 68 | * Returns the data to be sent to the controller 69 | * template 70 | * 71 | * @method getData 72 | * 73 | * @param {String} name 74 | * @param {Object} flags 75 | * 76 | * @return {Object} 77 | */ 78 | getData (name, flags) { 79 | return { 80 | name: this.getFileName(name), 81 | resource: !!flags.resource, 82 | resourceName: this.getResourceName(name), 83 | resourceNamePlural: pluralize(this.getResourceName(name)) 84 | } 85 | }, 86 | 87 | /** 88 | * Returns file name for controller. 89 | * 90 | * @method getFileName 91 | * 92 | * @param {String} name 93 | * 94 | * @return {String} 95 | */ 96 | getFileName (name) { 97 | name = name.replace(/controller/ig, '') 98 | return `${pluralize.singular(_.upperFirst(_.camelCase(name)))}Controller` 99 | }, 100 | 101 | /** 102 | * Returns name of resource from controller name. 103 | * 104 | * @method getResourceName 105 | * 106 | * @param {String} name 107 | * 108 | * @return {String} 109 | */ 110 | getResourceName (name) { 111 | return this.getFileName(name).replace('Controller', '').toLowerCase() 112 | }, 113 | 114 | /** 115 | * Returns path to the controller file 116 | * 117 | * @method getFilePath 118 | * 119 | * @param {String} name 120 | * @param {Object} options 121 | * 122 | * @return {String} 123 | */ 124 | getFilePath (name, options) { 125 | const baseName = path.basename(name) 126 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 127 | return path.join(options.appRoot, options.appDir, options.dirs.httpControllers, normalizedName) + '.js' 128 | } 129 | } 130 | 131 | generators.model = { 132 | /** 133 | * Returns data object for the model 134 | * template file 135 | * 136 | * @method getData 137 | * 138 | * @param {String} name 139 | * 140 | * @return {Object} 141 | */ 142 | getData (name) { 143 | return { 144 | name: this.getFileName(name) 145 | } 146 | }, 147 | 148 | /** 149 | * Returns the model file name 150 | * 151 | * @method getFileName 152 | * 153 | * @param {String} name 154 | * 155 | * @return {String} 156 | */ 157 | getFileName (name, appPath) { 158 | name = name.replace(/model/ig, '') 159 | return `${pluralize.singular(_.upperFirst(_.camelCase(name)))}` 160 | }, 161 | 162 | /** 163 | * Returns file path to the model file 164 | * 165 | * @method getFilePath 166 | * 167 | * @param {String} name 168 | * @param {Object} options 169 | * 170 | * @return {String} 171 | */ 172 | getFilePath (name, options) { 173 | const baseName = path.basename(name) 174 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 175 | return path.join(options.appRoot, options.appDir, options.dirs.models, normalizedName) + '.js' 176 | } 177 | } 178 | 179 | generators.trait = { 180 | /** 181 | * Returns data object for the trait 182 | * template file 183 | * 184 | * @method getData 185 | * 186 | * @param {String} name 187 | * 188 | * @return {Object} 189 | */ 190 | getData (name) { 191 | return { 192 | name: this.getFileName(name) 193 | } 194 | }, 195 | 196 | /** 197 | * Returns the trait file name 198 | * 199 | * @method getFileName 200 | * 201 | * @param {String} name 202 | * 203 | * @return {String} 204 | */ 205 | getFileName (name, appPath) { 206 | name = name.replace(/trait/ig, '') 207 | return `${pluralize.singular(_.upperFirst(_.camelCase(name)))}` 208 | }, 209 | 210 | /** 211 | * Returns file path to the trait file 212 | * 213 | * @method getFilePath 214 | * 215 | * @param {String} name 216 | * @param {Object} options 217 | * 218 | * @return {String} 219 | */ 220 | getFilePath (name, options) { 221 | const baseName = path.basename(name) 222 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 223 | return path.join(options.appRoot, options.appDir, options.dirs.traits, normalizedName) + '.js' 224 | } 225 | } 226 | 227 | generators.middleware = { 228 | /** 229 | * Returns data for the middleware template 230 | * 231 | * @method getData 232 | * 233 | * @param {String} name 234 | * 235 | * @return {Object} 236 | */ 237 | getData (name, flags) { 238 | return { 239 | name: this.getFileName(name), 240 | http: flags.type === 'http' || flags.type === 'both', 241 | ws: flags.type === 'ws' || flags.type === 'both' 242 | } 243 | }, 244 | 245 | /** 246 | * Returns file name for the middleware file 247 | * 248 | * @method getFileName 249 | * 250 | * @param {String} name 251 | * 252 | * @return {String} 253 | */ 254 | getFileName (name, appPath) { 255 | name = name.replace(/middleware/ig, '') 256 | return `${pluralize.singular(_.upperFirst(_.camelCase(name)))}` 257 | }, 258 | 259 | /** 260 | * Returns file path for the middleware file 261 | * 262 | * @method getFilePath 263 | * 264 | * @param {String} name 265 | * @param {Object} options 266 | * 267 | * @return {String} 268 | */ 269 | getFilePath (name, options) { 270 | const baseName = path.basename(name) 271 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 272 | return path.join(options.appRoot, options.appDir, options.dirs.middleware, normalizedName) + '.js' 273 | } 274 | } 275 | 276 | generators.hook = { 277 | /** 278 | * Returns data for the hook template 279 | * 280 | * @method getData 281 | * 282 | * @param {String} name 283 | * @param {Object} flags 284 | * 285 | * @return {Object} 286 | */ 287 | getData (name, flags) { 288 | return { 289 | name: this.getFileName(name), 290 | method: flags.method && typeof (flags.method) === 'string' ? flags.method : 'method' 291 | } 292 | }, 293 | 294 | /** 295 | * Returns file name for the hook file 296 | * 297 | * @method getFileName 298 | * 299 | * @param {String} name 300 | * 301 | * @return {String} 302 | */ 303 | getFileName (name, appPath) { 304 | name = name.replace(/hook/ig, '') 305 | return `${pluralize.singular(_.upperFirst(_.camelCase(name)))}Hook` 306 | }, 307 | 308 | /** 309 | * Returns file path for the hook file 310 | * 311 | * @method getFilePath 312 | * 313 | * @param {String} name 314 | * @param {Object} options 315 | * 316 | * @return {String} 317 | */ 318 | getFilePath (name, options) { 319 | const baseName = path.basename(name) 320 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 321 | return path.join(options.appRoot, options.appDir, options.dirs.hooks, normalizedName) + '.js' 322 | } 323 | } 324 | 325 | generators.view = { 326 | /** 327 | * Returns data for the view template 328 | * 329 | * @method getData 330 | * 331 | * @param {String} name 332 | * @param {Object} flags 333 | * 334 | * @return {Object} 335 | */ 336 | getData (name, flags) { 337 | return { 338 | layout: flags.layout && typeof (flags.layout) === 'string' ? flags.layout : null 339 | } 340 | }, 341 | 342 | /** 343 | * Returns file name for the view file 344 | * 345 | * @method getFileName 346 | * 347 | * @param {String} name 348 | * 349 | * @return {String} 350 | */ 351 | getFileName (name, appPath) { 352 | return _.toLower(name).replace(/view/ig, '').replace(/\./g, '/') 353 | }, 354 | 355 | /** 356 | * Returns file path for the hook file 357 | * 358 | * @method getFilePath 359 | * 360 | * @param {String} name 361 | * @param {Object} options 362 | * 363 | * @return {String} 364 | */ 365 | getFilePath (name, options) { 366 | return path.join(options.appRoot, options.dirs.views, this.getFileName(name)) + '.edge' 367 | } 368 | } 369 | 370 | generators.command = { 371 | /** 372 | * Returns data for the command template 373 | * 374 | * @method getData 375 | * 376 | * @param {String} name 377 | * @param {Object} flags 378 | * 379 | * @return {Object} 380 | */ 381 | getData (name, flags) { 382 | return { 383 | name: this.getFileName(name), 384 | commandName: _.snakeCase(this.getFileName(name)).replace(/_/g, ':') 385 | } 386 | }, 387 | 388 | /** 389 | * Returns file name for the command file 390 | * 391 | * @method getFileName 392 | * 393 | * @param {String} name 394 | * 395 | * @return {String} 396 | */ 397 | getFileName (name, appPath) { 398 | name = name.replace(/command/ig, '') 399 | return pluralize.singular(_.upperFirst(_.camelCase(name))) 400 | }, 401 | 402 | /** 403 | * Returns file path for the command file 404 | * 405 | * @method getFilePath 406 | * 407 | * @param {String} name 408 | * @param {Object} options 409 | * 410 | * @return {String} 411 | */ 412 | getFilePath (name, options) { 413 | const baseName = path.basename(name) 414 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 415 | return path.join(options.appRoot, options.appDir, options.dirs.commands, normalizedName) + '.js' 416 | } 417 | } 418 | 419 | generators.schema = { 420 | /** 421 | * Returns data for the migration schema template 422 | * 423 | * @method getData 424 | * 425 | * @param {String} name 426 | * @param {Object} flags 427 | * 428 | * @return {Object} 429 | */ 430 | getData (name, flags) { 431 | name = this.getFileName(name) 432 | return { 433 | create: flags.action === 'create', 434 | table: _.snakeCase(pluralize(name.replace('Schema', ''))), 435 | name: name 436 | } 437 | }, 438 | 439 | /** 440 | * Returns file name for the schema migration file 441 | * 442 | * @method getFileName 443 | * 444 | * @param {String} name 445 | * 446 | * @return {String} 447 | */ 448 | getFileName (name, appPath) { 449 | name = name.replace(/schema|table/ig, '') 450 | return `${_.upperFirst(_.camelCase(name))}Schema` 451 | }, 452 | 453 | /** 454 | * Returns file path for the schema migration file 455 | * 456 | * @method getFilePath 457 | * 458 | * @param {String} name 459 | * @param {Object} options 460 | * 461 | * @return {String} 462 | */ 463 | getFilePath (name, options) { 464 | const fileName = `${new Date().getTime()}_${_.snakeCase(this.getFileName(name))}` 465 | return path.join(options.appRoot, options.dirs.migrations, fileName) + '.js' 466 | } 467 | } 468 | 469 | generators.listener = { 470 | /** 471 | * Returns data for the listener template 472 | * 473 | * @method getData 474 | * 475 | * @param {String} name 476 | * @param {Object} flags 477 | * 478 | * @return {Object} 479 | */ 480 | getData (name, flags) { 481 | return { 482 | name: this.getFileName(name), 483 | method: flags.method && typeof (flags.method) === 'string' ? flags.method : 'method' 484 | } 485 | }, 486 | 487 | /** 488 | * Returns file name for the listener file 489 | * 490 | * @method getFileName 491 | * 492 | * @param {String} name 493 | * 494 | * @return {String} 495 | */ 496 | getFileName (name, appPath) { 497 | name = name.replace(/listener/ig, '') 498 | return `${_.upperFirst(_.camelCase(name))}` 499 | }, 500 | 501 | /** 502 | * Returns file path for the hook file 503 | * 504 | * @method getFilePath 505 | * 506 | * @param {String} name 507 | * @param {Object} options 508 | * 509 | * @return {String} 510 | */ 511 | getFilePath (name, options) { 512 | const baseName = path.basename(name) 513 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 514 | return path.join(options.appRoot, options.appDir, options.dirs.listeners, normalizedName) + '.js' 515 | } 516 | } 517 | 518 | generators.exceptionHandler = { 519 | /** 520 | * Returns data for the exception handler template 521 | * 522 | * @method getData 523 | * 524 | * @return {Object} 525 | */ 526 | getData (name, flags) { 527 | return flags || {} 528 | }, 529 | 530 | /** 531 | * Returns file name for the exception handler file 532 | * 533 | * @return {String} 534 | */ 535 | getFileName () { 536 | return 'Handler' 537 | }, 538 | 539 | /** 540 | * Returns file path for the exception handler file 541 | * 542 | * @method getFilePath 543 | * 544 | * @param {String} name 545 | * @param {Object} options 546 | * 547 | * @return {String} 548 | */ 549 | getFilePath (name, options) { 550 | const baseName = path.basename(name) 551 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 552 | return path.join(options.appRoot, options.appDir, options.dirs.exceptions, normalizedName) + '.js' 553 | } 554 | } 555 | 556 | generators.seed = { 557 | /** 558 | * Returns data object for the seed 559 | * template file 560 | * 561 | * @method getData 562 | * 563 | * @param {String} name 564 | * 565 | * @return {Object} 566 | */ 567 | getData (name) { 568 | return { 569 | name: this.getFileName(name) 570 | } 571 | }, 572 | 573 | /** 574 | * Returns the seed file name 575 | * 576 | * @method getFileName 577 | * 578 | * @param {String} name 579 | * 580 | * @return {String} 581 | */ 582 | getFileName (name, appPath) { 583 | name = name.replace(/seed(er)?/ig, '') 584 | return `${pluralize.singular(_.upperFirst(_.camelCase(name)))}Seeder` 585 | }, 586 | 587 | /** 588 | * Returns file path to the model file 589 | * 590 | * @method getFilePath 591 | * 592 | * @param {String} name 593 | * @param {Object} options 594 | * 595 | * @return {String} 596 | */ 597 | getFilePath (name, options) { 598 | const baseName = path.basename(name) 599 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 600 | return path.join(options.appRoot, options.dirs.seeds, normalizedName) + '.js' 601 | } 602 | } 603 | 604 | generators.wsController = { 605 | /** 606 | * Returns the data to be sent to the controller 607 | * template 608 | * 609 | * @method getData 610 | * 611 | * @param {String} name 612 | * 613 | * @return {Object} 614 | */ 615 | getData (name) { 616 | return { 617 | name: this.getFileName(name) 618 | } 619 | }, 620 | 621 | /** 622 | * Returns file name for controller. 623 | * 624 | * @method getFileName 625 | * 626 | * @param {String} name 627 | * 628 | * @return {String} 629 | */ 630 | getFileName (name) { 631 | name = name.replace(/controller/ig, '') 632 | return `${pluralize.singular(_.upperFirst(_.camelCase(name)))}Controller` 633 | }, 634 | 635 | /** 636 | * Returns path to the controller file 637 | * 638 | * @method getFilePath 639 | * 640 | * @param {String} name 641 | * @param {Object} options 642 | * 643 | * @return {String} 644 | */ 645 | getFilePath (name, options) { 646 | const baseName = path.basename(name) 647 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 648 | return path.join(options.appRoot, options.appDir, options.dirs.wsControllers, normalizedName) + '.js' 649 | } 650 | } 651 | 652 | generators.exception = { 653 | /** 654 | * Returns the data to be sent to the exception 655 | * template 656 | * 657 | * @method getData 658 | * 659 | * @param {String} name 660 | * @param {Object} flags 661 | * 662 | * @return {Object} 663 | */ 664 | getData (name, flags) { 665 | return { 666 | name: this.getFileName(name) 667 | } 668 | }, 669 | 670 | /** 671 | * Returns file name for exception class. 672 | * 673 | * @method getFileName 674 | * 675 | * @param {String} name 676 | * 677 | * @return {String} 678 | */ 679 | getFileName (name) { 680 | name = name.replace(/exception/ig, '') 681 | return `${pluralize.singular(_.upperFirst(_.camelCase(name)))}Exception` 682 | }, 683 | 684 | /** 685 | * Returns path to the exception file 686 | * 687 | * @method getFilePath 688 | * 689 | * @param {String} name 690 | * @param {Object} options 691 | * 692 | * @return {String} 693 | */ 694 | getFilePath (name, options) { 695 | const baseName = path.basename(name) 696 | const normalizedName = name.replace(baseName, this.getFileName(baseName)) 697 | return path.join(options.appRoot, options.appDir, options.dirs.exceptions, normalizedName) + '.js' 698 | } 699 | } 700 | -------------------------------------------------------------------------------- /src/Generators/templates/command.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const { Command } = require('@adonisjs/ace') 4 | 5 | class {{name}} extends Command { 6 | static get signature () { 7 | return '{{commandName}}' 8 | } 9 | 10 | static get description () { 11 | return 'Tell something helpful about this command' 12 | } 13 | 14 | async handle (args, options) { 15 | this.info('Dummy implementation for {{commandName}} command') 16 | } 17 | } 18 | 19 | module.exports = {{name}} 20 | -------------------------------------------------------------------------------- /src/Generators/templates/exception.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const { LogicalException } = require('@adonisjs/generic-exceptions') 4 | 5 | class {{ name }} extends LogicalException { 6 | /** 7 | * Handle this exception by itself 8 | */ 9 | // handle () {} 10 | } 11 | 12 | module.exports = {{ name }} 13 | -------------------------------------------------------------------------------- /src/Generators/templates/exceptionHandler.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | {{#new}} 4 | const BaseExceptionHandler = use('BaseExceptionHandler') 5 | 6 | /** 7 | * This class handles all exceptions thrown during 8 | * the HTTP request lifecycle. 9 | * 10 | * @class ExceptionHandler 11 | */ 12 | class ExceptionHandler extends BaseExceptionHandler { 13 | /** 14 | * Handle exception thrown during the HTTP lifecycle 15 | * 16 | * @method handle 17 | * 18 | * @param {Object} error 19 | * @param {Object} options.request 20 | * @param {Object} options.response 21 | * 22 | * @return {void} 23 | */ 24 | async handle (error, { request, response }) { 25 | response.status(error.status).send(error.message) 26 | } 27 | 28 | /** 29 | * Report exception for logging or debugging. 30 | * 31 | * @method report 32 | * 33 | * @param {Object} error 34 | * @param {Object} options.request 35 | * 36 | * @return {void} 37 | */ 38 | async report (error, { request }) { 39 | } 40 | } 41 | {{/new}} 42 | {{^new}} 43 | /** 44 | * This class handles all exceptions thrown during 45 | * the HTTP request lifecycle. 46 | * 47 | * @class ExceptionHandler 48 | */ 49 | class ExceptionHandler { 50 | /** 51 | * Handle exception thrown during the HTTP lifecycle 52 | * 53 | * @method handle 54 | * 55 | * @param {Object} error 56 | * @param {Object} options.request 57 | * @param {Object} options.response 58 | * 59 | * @return {void} 60 | */ 61 | async handle (error, { request, response }) { 62 | response.status(error.status).send(error.message) 63 | } 64 | 65 | /** 66 | * Report exception for logging or debugging. 67 | * 68 | * @method report 69 | * 70 | * @param {Object} error 71 | * @param {Object} options.request 72 | * 73 | * @return {void} 74 | */ 75 | async report (error, { request }) { 76 | } 77 | } 78 | {{/new}} 79 | 80 | module.exports = ExceptionHandler 81 | -------------------------------------------------------------------------------- /src/Generators/templates/hook.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const {{name}} = exports = module.exports = {} 4 | 5 | {{name}}.{{method}} = async (modelInstance) => { 6 | } 7 | -------------------------------------------------------------------------------- /src/Generators/templates/httpController.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | {{#resource}} 4 | /** @typedef {import('@adonisjs/framework/src/Request')} Request */ 5 | /** @typedef {import('@adonisjs/framework/src/Response')} Response */ 6 | /** @typedef {import('@adonisjs/framework/src/View')} View */ 7 | 8 | /** 9 | * Resourceful controller for interacting with {{resourceNamePlural}} 10 | */ 11 | {{/resource}} 12 | class {{name}} { 13 | {{#resource}} 14 | /** 15 | * Show a list of all {{resourceNamePlural}}. 16 | * GET {{resourceNamePlural}} 17 | * 18 | * @param {object} ctx 19 | * @param {Request} ctx.request 20 | * @param {Response} ctx.response 21 | * @param {View} ctx.view 22 | */ 23 | async index ({ request, response, view }) { 24 | } 25 | 26 | /** 27 | * Render a form to be used for creating a new {{resourceName}}. 28 | * GET {{resourceNamePlural}}/create 29 | * 30 | * @param {object} ctx 31 | * @param {Request} ctx.request 32 | * @param {Response} ctx.response 33 | * @param {View} ctx.view 34 | */ 35 | async create ({ request, response, view }) { 36 | } 37 | 38 | /** 39 | * Create/save a new {{resourceName}}. 40 | * POST {{resourceNamePlural}} 41 | * 42 | * @param {object} ctx 43 | * @param {Request} ctx.request 44 | * @param {Response} ctx.response 45 | */ 46 | async store ({ request, response }) { 47 | } 48 | 49 | /** 50 | * Display a single {{resourceName}}. 51 | * GET {{resourceNamePlural}}/:id 52 | * 53 | * @param {object} ctx 54 | * @param {Request} ctx.request 55 | * @param {Response} ctx.response 56 | * @param {View} ctx.view 57 | */ 58 | async show ({ params, request, response, view }) { 59 | } 60 | 61 | /** 62 | * Render a form to update an existing {{resourceName}}. 63 | * GET {{resourceNamePlural}}/:id/edit 64 | * 65 | * @param {object} ctx 66 | * @param {Request} ctx.request 67 | * @param {Response} ctx.response 68 | * @param {View} ctx.view 69 | */ 70 | async edit ({ params, request, response, view }) { 71 | } 72 | 73 | /** 74 | * Update {{resourceName}} details. 75 | * PUT or PATCH {{resourceNamePlural}}/:id 76 | * 77 | * @param {object} ctx 78 | * @param {Request} ctx.request 79 | * @param {Response} ctx.response 80 | */ 81 | async update ({ params, request, response }) { 82 | } 83 | 84 | /** 85 | * Delete a {{resourceName}} with id. 86 | * DELETE {{resourceNamePlural}}/:id 87 | * 88 | * @param {object} ctx 89 | * @param {Request} ctx.request 90 | * @param {Response} ctx.response 91 | */ 92 | async destroy ({ params, request, response }) { 93 | } 94 | {{/resource}} 95 | } 96 | 97 | module.exports = {{name}} 98 | -------------------------------------------------------------------------------- /src/Generators/templates/listener.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const {{name}} = exports = module.exports = {} 4 | 5 | {{name}}.{{method}} = async () => { 6 | } 7 | -------------------------------------------------------------------------------- /src/Generators/templates/middleware.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** @typedef {import('@adonisjs/framework/src/Request')} Request */ 3 | /** @typedef {import('@adonisjs/framework/src/Response')} Response */ 4 | /** @typedef {import('@adonisjs/framework/src/View')} View */ 5 | 6 | class {{name}} { 7 | {{#http}} 8 | /** 9 | * @param {object} ctx 10 | * @param {Request} ctx.request 11 | * @param {Function} next 12 | */ 13 | async handle ({ request }, next) { 14 | // call next to advance the request 15 | await next() 16 | } 17 | {{/http}} 18 | {{#ws}} 19 | 20 | /** 21 | * @param {object} ctx 22 | * @param {Request} ctx.request 23 | * @param {Function} next 24 | */ 25 | async wsHandle ({ request }, next) { 26 | // call next to advance the request 27 | await next() 28 | } 29 | {{/ws}} 30 | } 31 | 32 | module.exports = {{name}} 33 | -------------------------------------------------------------------------------- /src/Generators/templates/model.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 4 | const Model = use('Model') 5 | 6 | class {{name}} extends Model { 7 | } 8 | 9 | module.exports = {{name}} 10 | -------------------------------------------------------------------------------- /src/Generators/templates/provider.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const { ServiceProvider } = require('@adonisjs/fold') 4 | 5 | class {{name}} extends ServiceProvider { 6 | /** 7 | * Register namespaces to the IoC container 8 | * 9 | * @method register 10 | * 11 | * @return {void} 12 | */ 13 | register () { 14 | // 15 | } 16 | 17 | /** 18 | * Attach context getter when all providers have 19 | * been registered 20 | * 21 | * @method boot 22 | * 23 | * @return {void} 24 | */ 25 | boot () { 26 | // 27 | } 28 | } 29 | 30 | module.exports = {{name}} 31 | -------------------------------------------------------------------------------- /src/Generators/templates/schema.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** @type {import('@adonisjs/lucid/src/Schema')} */ 4 | const Schema = use('Schema') 5 | 6 | class {{ name }} extends Schema { 7 | {{#create}} 8 | up () { 9 | this.create('{{ table }}', (table) => { 10 | table.increments() 11 | table.timestamps() 12 | }) 13 | } 14 | 15 | down () { 16 | this.drop('{{ table }}') 17 | } 18 | {{/create}} 19 | {{^create}} 20 | up () { 21 | this.table('{{ table }}', (table) => { 22 | // alter table 23 | }) 24 | } 25 | 26 | down () { 27 | this.table('{{ table }}', (table) => { 28 | // reverse alternations 29 | }) 30 | } 31 | {{/create}} 32 | } 33 | 34 | module.exports = {{ name }} 35 | -------------------------------------------------------------------------------- /src/Generators/templates/seed.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | {{name}} 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Make use of the Factory instance to seed database with dummy data or 9 | | make use of Lucid models directly. 10 | | 11 | */ 12 | 13 | /** @type {import('@adonisjs/lucid/src/Factory')} */ 14 | const Factory = use('Factory') 15 | 16 | class {{name}} { 17 | async run () { 18 | } 19 | } 20 | 21 | module.exports = {{name}} 22 | -------------------------------------------------------------------------------- /src/Generators/templates/trait.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | class {{name}} { 4 | register (Model, customOptions = {}) { 5 | const defaultOptions = {} 6 | const options = Object.assign(defaultOptions, customOptions) 7 | } 8 | } 9 | 10 | module.exports = {{name}} 11 | -------------------------------------------------------------------------------- /src/Generators/templates/view.mustache: -------------------------------------------------------------------------------- 1 | {{#layout}} 2 | @layout('{{layout}}') 3 | {{/layout}} 4 | -------------------------------------------------------------------------------- /src/Generators/templates/wsController.mustache: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | class {{name}} { 4 | constructor ({ socket, request }) { 5 | this.socket = socket 6 | this.request = request 7 | } 8 | } 9 | 10 | module.exports = {{name}} 11 | -------------------------------------------------------------------------------- /src/Services/check-node-version.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const semver = require('semver') 13 | const requiredNodeVersion = '>=8.0.0' 14 | const requiredNodeVersionNumber = 8 15 | const requiredNpmVersion = '>=3.0.0' 16 | const requiredNpmVersionNumber = 3 17 | 18 | /** 19 | * This step checks the Node.js and npm version 20 | * installed on user machine. It will print 21 | * some messages on the console but also 22 | * throws an exception to abort the 23 | * process 24 | * 25 | * @async 26 | * 27 | * @param {Object} stepsCounter 28 | * 29 | * @return {void} 30 | */ 31 | module.exports = async function (stepsCounter) { 32 | const step = stepsCounter.advance('Verifying requirements', 'microscope', 'node & npm') 33 | step.start() 34 | 35 | /** 36 | * Verify Node.js version. 37 | * 38 | * Uses `semver.parse` instead of `semver.satisfies` to support prereleases 39 | * version of Node.js. 40 | */ 41 | const nodeVersion = process.version 42 | if (semver.parse(nodeVersion).major < requiredNodeVersionNumber) { 43 | step.error('Unsupported Node.js version', 'x') 44 | throw new Error(`Unsatisfied Node.js version ${nodeVersion}. Please update Node.js to ${requiredNodeVersion} before you continue`) 45 | } 46 | 47 | /** 48 | * Verify npm version. 49 | * 50 | * Uses `semver.parse` instead of `semver.satisfies` to support prereleases 51 | * version of npm. 52 | */ 53 | const npmVersion = (await require('./exec')('npm -v')).trim() 54 | if (semver.parse(npmVersion).major < requiredNpmVersionNumber) { 55 | step.error('Unsupported npm version', 'x') 56 | throw new Error(`Unsatisfied npm version ${npmVersion}. Please update npm to ${requiredNpmVersion} before you continue`) 57 | } 58 | 59 | step.success('Requirements matched') 60 | } 61 | -------------------------------------------------------------------------------- /src/Services/clone.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const debug = require('debug')('adonis:cli') 13 | const isGitUrl = require('is-git-url') 14 | 15 | /** 16 | * This module clones a given github repo and branch. 17 | * 18 | * @method 19 | * 20 | * @param {String} blueprint 21 | * @param {String} appPath 22 | * @param {Object} stepsCounter 23 | * @param {String} [branch = null] 24 | * 25 | * @return {void} 26 | */ 27 | module.exports = async function (blueprint, appPath, stepsCounter, branch = null) { 28 | const step = stepsCounter.advance('Cloning project blueprint', 'inbox_tray', blueprint) 29 | step.start() 30 | 31 | let cloneCommand = 'git clone --depth=1' 32 | 33 | /** 34 | * Add branch flag when branch is defined 35 | */ 36 | if (branch) { 37 | cloneCommand = `${cloneCommand} --branch ${branch}` 38 | } 39 | 40 | // complete the clone command 41 | // check if ths a full .git path 42 | if (isGitUrl(blueprint)) { 43 | cloneCommand = `${cloneCommand} ${blueprint} "${appPath}"` 44 | } else { 45 | cloneCommand = `${cloneCommand} https://github.com/${blueprint}.git "${appPath}"` 46 | } 47 | debug('clone command %s', cloneCommand) 48 | 49 | try { 50 | await require('./exec')(cloneCommand) 51 | step.success('Cloned') 52 | } catch (error) { 53 | step.error('Unable to clone repo', 'x') 54 | throw error 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Services/copy-env-file.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const fs = require('fs-extra') 14 | 15 | /** 16 | * This module copies the `.env.example` file to `.env`. 17 | * 18 | * @method 19 | * 20 | * @param {String} appPath 21 | * @param {Function} copy 22 | * @param {Object} stepsCounter 23 | * 24 | * @return {void} 25 | */ 26 | module.exports = async function (appPath, stepsCounter) { 27 | const step = stepsCounter.advance('Copying default environment variables', 'open_book', '.env') 28 | step.start() 29 | 30 | try { 31 | await fs.copy(path.join(appPath, '.env.example'), path.join(appPath, '.env')) 32 | step.success('Environment variables copied') 33 | } catch (error) { 34 | step.error('Unable to copy environment variables', 'x') 35 | throw error 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Services/exec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const exec = require('util').promisify(require('child_process').exec) 13 | 14 | module.exports = async function (command) { 15 | const { stdout } = await exec(command) 16 | return stdout 17 | } 18 | -------------------------------------------------------------------------------- /src/Services/generate-app-key.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * Generates the app key by executing key:generate 14 | * ace comamnd. 15 | * 16 | * @method 17 | * 18 | * @param {Object} stepsCounter 19 | * 20 | * @return {void} 21 | */ 22 | module.exports = async function (stepsCounter) { 23 | const step = stepsCounter.advance('Generating APP_KEY', 'key', 'adonis key:generate') 24 | step.start() 25 | 26 | try { 27 | await require('./exec')('adonis key:generate') 28 | step.success('Key generated') 29 | } catch (error) { 30 | step.error('Unable to generate key', 'x') 31 | error.hint = 'You can continue manually by running adonis key:generate' 32 | throw error 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Services/install.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * Install dependencies from npm or yarn. The installation 14 | * tool must be installed on user machine 15 | * 16 | * @method 17 | * 18 | * @param {String} via 19 | * @param {Object} stepsCounter 20 | * @param {String} [packageName = ''] 21 | * 22 | * @return {void} 23 | */ 24 | module.exports = async function (via, stepsCounter, packageName) { 25 | const command = via === 'npm' 26 | ? (packageName ? `npm i --save ${packageName}@legacy` : 'npm install') 27 | : (packageName ? `yarn add ${packageName}@legacy` : 'yarn') 28 | 29 | const message = packageName ? `${via}: Installing` : `${via}: Installing project dependencies` 30 | const step = stepsCounter.advance(message, 'package', packageName) 31 | 32 | step.start() 33 | 34 | try { 35 | await require('./exec')(command) 36 | step.success('Dependencies installed') 37 | } catch (error) { 38 | step.error('Installation failed', 'x') 39 | error.hint = `You can manually install dependencies by running ${command}` 40 | throw error 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Services/render-instructions-md.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const os = require('os') 14 | const opn = require('opn') 15 | const fs = require('fs-extra') 16 | const marked = require('marked') 17 | const debug = require('debug')('adonis:cli') 18 | 19 | const css = `.markdown-body hr::after,.markdown-body::after{clear:both}body{box-sizing:border-box;min-width:200px;max-width:980px;margin:0 auto;padding:45px}.markdown-body{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;color:#24292e;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:16px;line-height:1.5;word-wrap:break-word}.markdown-body .pl-c{color:#6a737d}.markdown-body .pl-c1,.markdown-body .pl-s .pl-v{color:#005cc5}.markdown-body .pl-e,.markdown-body .pl-en{color:#6f42c1}.markdown-body .pl-s .pl-s1,.markdown-body .pl-smi{color:#24292e}.markdown-body .pl-ent{color:#22863a}.markdown-body .pl-k{color:#d73a49}.markdown-body .pl-pds,.markdown-body .pl-s,.markdown-body .pl-s .pl-pse .pl-s1,.markdown-body .pl-sr,.markdown-body .pl-sr .pl-cce,.markdown-body .pl-sr .pl-sra,.markdown-body .pl-sr .pl-sre{color:#032f62}.markdown-body .pl-smw,.markdown-body .pl-v{color:#e36209}.markdown-body .pl-bu{color:#b31d28}.markdown-body .pl-ii{color:#fafbfc;background-color:#b31d28}.markdown-body .pl-c2{color:#fafbfc;background-color:#d73a49}.markdown-body .pl-sr .pl-cce{font-weight:700;color:#22863a}.markdown-body .pl-ml{color:#735c0f}.markdown-body .pl-mh,.markdown-body .pl-mh .pl-en,.markdown-body .pl-ms{font-weight:700;color:#005cc5}.markdown-body .pl-mi{font-style:italic;color:#24292e}.markdown-body .pl-mb{font-weight:700;color:#24292e}.markdown-body .pl-md{color:#b31d28;background-color:#ffeef0}.markdown-body .pl-mi1{color:#22863a;background-color:#f0fff4}.markdown-body .pl-mc{color:#e36209;background-color:#ffebda}.markdown-body .pl-mi2{color:#f6f8fa;background-color:#005cc5}.markdown-body .pl-mdr{font-weight:700;color:#6f42c1}.markdown-body .pl-ba{color:#586069}.markdown-body .pl-sg{color:#959da5}.markdown-body .pl-corl{text-decoration:underline;color:#032f62}.markdown-body .octicon{display:inline-block;fill:currentColor;vertical-align:text-bottom}.markdown-body hr::after,.markdown-body hr::before,.markdown-body::after,.markdown-body::before{display:table;content:""}.markdown-body a{background-color:transparent;-webkit-text-decoration-skip:objects;color:#0366d6;text-decoration:none}.markdown-body a:active,.markdown-body a:hover{outline-width:0}.markdown-body h1{margin:.67em 0}.markdown-body img{border-style:none}.markdown-body svg:not(:root){overflow:hidden}.markdown-body hr{box-sizing:content-box}.markdown-body input{font:inherit;margin:0;overflow:visible;font-family:inherit;font-size:inherit;line-height:inherit}.markdown-body [type=checkbox]{box-sizing:border-box;padding:0}.markdown-body *{box-sizing:border-box}.markdown-body a:hover{text-decoration:underline}.markdown-body strong{font-weight:600}.markdown-body td,.markdown-body th{padding:0}.markdown-body blockquote{margin:0}.markdown-body ol ol,.markdown-body ul ol{list-style-type:lower-roman}.markdown-body ol ol ol,.markdown-body ol ul ol,.markdown-body ul ol ol,.markdown-body ul ul ol{list-style-type:lower-alpha}.markdown-body dd{margin-left:0}.markdown-body code{font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace}.markdown-body pre{font:12px SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;word-wrap:normal}.markdown-body .pl-0{padding-left:0!important}.markdown-body .pl-1{padding-left:4px!important}.markdown-body .pl-2{padding-left:8px!important}.markdown-body .pl-3{padding-left:16px!important}.markdown-body .pl-4{padding-left:24px!important}.markdown-body .pl-5{padding-left:32px!important}.markdown-body .pl-6{padding-left:40px!important}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .anchor{float:left;padding-right:4px;margin-left:-20px;line-height:1}.markdown-body .anchor:focus{outline:0}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:16px}.markdown-body hr{overflow:hidden;background:#e1e4e8;height:.25em;padding:0;margin:24px 0;border:0}.markdown-body blockquote{padding:0 1em;color:#6a737d;border-left:.25em solid #dfe2e5}.markdown-body h1,.markdown-body h2{padding-bottom:.3em;border-bottom:1px solid #eaecef}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:24px;margin-bottom:16px;font-weight:600;line-height:1.25}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#1b1f23;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1{font-size:2em}.markdown-body h2{font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{font-size:.85em;color:#6a737d}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{margin-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:600}.markdown-body dl dd{padding:0 16px;margin-bottom:16px}.markdown-body table{border-spacing:0;border-collapse:collapse;display:block;width:100%;overflow:auto}.markdown-body table th{font-weight:600}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid #dfe2e5}.markdown-body table tr{background-color:#fff;border-top:1px solid #c6cbd1}.markdown-body table tr:nth-child(2n){background-color:#f6f8fa}.markdown-body img{max-width:100%;box-sizing:content-box;background-color:#fff}.markdown-body code{padding:.2em 0;margin:0;font-size:85%;background-color:rgba(27,31,35,.05);border-radius:3px}.markdown-body code::after,.markdown-body code::before{letter-spacing:-.2em}.markdown-body pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f6f8fa;border-radius:3px}.markdown-body pre code{display:inline;max-width:auto;padding:0;margin:0;overflow:visible;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown-body pre code::after,.markdown-body pre code::before{content:normal}.markdown-body .full-commit .btn-outline:not(:disabled):hover{color:#005cc5;border-color:#005cc5}.markdown-body kbd{display:inline-block;padding:3px 5px;font:11px SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;line-height:10px;color:#444d56;vertical-align:middle;background-color:#fafbfc;border:1px solid #d1d5da;border-bottom-color:#c6cbd1;border-radius:3px;box-shadow:inset 0 -1px 0 #c6cbd1}.markdown-body :checked+.radio-label{position:relative;z-index:1;border-color:#0366d6}.markdown-body .task-list-item{list-style-type:none}.markdown-body .task-list-item+.task-list-item{margin-top:3px}.markdown-body .task-list-item input{margin:0 .2em .25em -1.6em;vertical-align:middle}.markdown-body hr{border-bottom-color:#eee}` 20 | 21 | /** 22 | * Returns the html to be saved inside tmp file 23 | * and show it to the user 24 | * 25 | * @method html 26 | * 27 | * @param {String} css 28 | * @param {String} moduleName 29 | * @param {String} content 30 | * 31 | * @return {String} 32 | */ 33 | const html = function (css, moduleName, content) { 34 | return ` 35 | 36 | 37 | 38 | 39 |
40 |

Setup instructions for 41 | ${moduleName} 42 |

43 | ${content} 44 |
45 | 46 | 47 | ` 48 | } 49 | 50 | /** 51 | * Render instructions.md file by converting it to 52 | * HTML and serving by tmp dir. 53 | * 54 | * @method 55 | * 56 | * @param {String} modulePath 57 | * @param {String} moduleName 58 | * 59 | * @return {void} 60 | */ 61 | module.exports = async function (modulePath, moduleName) { 62 | try { 63 | const instructions = await fs.readFile(path.join(modulePath, 'instructions.md'), 'utf-8') 64 | debug('found instructions.md file for %s', modulePath) 65 | 66 | /** 67 | * Converting instructions markdown to html 68 | */ 69 | const content = marked(instructions) 70 | 71 | /** 72 | * Creating html document 73 | */ 74 | const htmlDocument = html(css, moduleName, content) 75 | 76 | /** 77 | * Generating path to tmp file 78 | */ 79 | const tmpFile = path.join(os.tmpdir(), `${new Date().getTime()}.html`) 80 | 81 | /** 82 | * Writing to tmp file 83 | */ 84 | await fs.outputFile(tmpFile, htmlDocument) 85 | 86 | /** 87 | * Opening file 88 | */ 89 | await opn(tmpFile, { wait: false }) 90 | } catch (error) { 91 | // ignore error since it's not helpful for enduser 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Services/run-instructions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const fs = require('fs-extra') 14 | const debug = require('debug')('adonis:cli') 15 | 16 | /** 17 | * Executes the instructions file only if it 18 | * exists 19 | * 20 | * @method 21 | * @async 22 | * 23 | * @param {Object} ctx 24 | * @param {String} modulePath 25 | * 26 | * @return {void} 27 | */ 28 | module.exports = async function (ctx, modulePath) { 29 | const instructionsFilePath = path.join(modulePath, 'instructions.js') 30 | 31 | const hasInstructionsFile = await fs.pathExists(instructionsFilePath) 32 | if (!hasInstructionsFile) { 33 | return 34 | } 35 | 36 | try { 37 | debug('found instructions.js file for %s', modulePath) 38 | const instructions = require(instructionsFilePath) 39 | if (typeof (instructions) === 'function') { 40 | await instructions(ctx) 41 | } 42 | } catch (error) { 43 | error.message = `instructions.js: ${error.message}` 44 | throw error 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Services/verify-existing-folder.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const readDir = require('util').promisify(require('fs').readdir) 14 | 15 | /** 16 | * Verifies that the installation folder is empty 17 | * or should not exists. Otherwise throws an 18 | * exception 19 | * 20 | * @method 21 | * 22 | * @param {String} appPath 23 | * @param {Object} stepsCounter 24 | * 25 | * @return {void} 26 | */ 27 | module.exports = async function (appPath, stepsCounter) { 28 | const name = path.basename(appPath) 29 | 30 | const step = stepsCounter.advance('Ensuring project directory is clean', 'flashlight', name) 31 | step.start() 32 | 33 | try { 34 | const files = await readDir(appPath) 35 | if (files.length > 0) { 36 | step.error('Directory is not empty', 'x') 37 | throw new Error(`Cannot override contents of [${name}]. Make sure to delete it or specify a new path`) 38 | } 39 | } catch (error) { 40 | if (error.code !== 'ENOENT') { 41 | throw error 42 | } 43 | } 44 | 45 | step.success() 46 | } 47 | -------------------------------------------------------------------------------- /test/clone.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const test = require('japa') 13 | const path = require('path') 14 | const fs = require('fs-extra') 15 | const Steps = require('cli-step') 16 | const clone = require('../src/Services/clone') 17 | 18 | test.group('New | Steps | clone', (group) => { 19 | group.after(async () => { 20 | await fs.remove(path.join(__dirname, './yardstick-app')) 21 | await fs.remove(path.join(__dirname, './yardstick')) 22 | }) 23 | 24 | test('throw error when cannot clone repo', async (assert) => { 25 | const appPath = path.join(__dirname, './yardstick') 26 | assert.plan(1) 27 | const stepsCounter = new Steps(1) 28 | 29 | try { 30 | process.env.GIT_TERMINAL_PROMPT = 0 31 | await clone('adonisjs/foo-app', appPath, stepsCounter) 32 | } catch ({ message }) { 33 | assert.isDefined(message) 34 | } 35 | }).timeout(0) 36 | 37 | test('clone repo when it exists', async (assert) => { 38 | const appPath = path.join(__dirname, './yardstick') 39 | const stepsCounter = new Steps(1) 40 | 41 | await clone('adonisjs/adonis-app', appPath, stepsCounter) 42 | await fs.pathExists(appPath) 43 | await fs.remove(appPath) 44 | }).timeout(0) 45 | 46 | test('clone repo with specific branch', async (assert) => { 47 | const appPath = path.join(__dirname, './yardstick-app') 48 | const stepsCounter = new Steps(1) 49 | 50 | await clone('adonisjs/adonis-app', appPath, stepsCounter, 'develop') 51 | 52 | await fs.pathExists(appPath) 53 | process.chdir(appPath) 54 | 55 | const branch = await require('../src/Services/exec')('git branch') 56 | assert.equal(branch.replace('*', '').trim(), 'develop') 57 | process.chdir(__dirname) 58 | }).timeout(0) 59 | }) 60 | -------------------------------------------------------------------------------- /test/copy-env-file.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const test = require('japa') 13 | const path = require('path') 14 | const fs = require('fs-extra') 15 | const Steps = require('cli-step') 16 | const copyEnvFile = require('../src/Services/copy-env-file') 17 | 18 | test.group('New | Steps | copy env file', (group) => { 19 | group.after(async () => { 20 | await fs.remove(path.join(__dirname, './yardstick-app')) 21 | await fs.remove(path.join(__dirname, './yardstick')) 22 | }) 23 | 24 | test('Copy env.example to .env', async (assert) => { 25 | const appPath = path.join(__dirname, './yardstick') 26 | await fs.ensureFile(path.join(appPath, '.env.example')) 27 | const stepsCounter = new Steps(1) 28 | 29 | process.chdir(appPath) 30 | await copyEnvFile(appPath, stepsCounter) 31 | 32 | await fs.pathExists(path.join(appPath, '.env')) 33 | await fs.remove(path.join(appPath, '.env')) 34 | await fs.remove(path.join(appPath, '.env.example')) 35 | 36 | process.chdir(__dirname) 37 | }).timeout(0) 38 | }) 39 | -------------------------------------------------------------------------------- /test/generators.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-auth 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const path = require('path') 13 | const test = require('japa') 14 | const generators = require('../src/Generators') 15 | const OPTS = { 16 | appRoot: __dirname, 17 | appDir: 'app', 18 | dirs: { 19 | httpControllers: 'Controllers/Http', 20 | wsControllers: 'Controllers/Ws', 21 | models: 'Models', 22 | traits: 'Models/Traits', 23 | hooks: 'Models/Hooks', 24 | listeners: 'Listeners', 25 | exceptions: 'Exceptions', 26 | middleware: 'Middleware', 27 | commands: 'Commands', 28 | views: 'resources/views', 29 | migrations: 'database/migrations', 30 | seeds: 'database/seeds', 31 | providers: 'providers' 32 | } 33 | } 34 | 35 | test.group('Generators', () => { 36 | test('get path to the provider file', (assert) => { 37 | const filePath = generators.provider.getFilePath('Event', OPTS) 38 | assert.equal(filePath, path.join(__dirname, 'providers', 'EventProvider.js')) 39 | }) 40 | 41 | test('make provider file singular', (assert) => { 42 | const filePath = generators.provider.getFilePath('Events', OPTS) 43 | assert.equal(filePath, path.join(__dirname, 'providers', 'EventProvider.js')) 44 | }) 45 | 46 | test('normalize provider keyword', (assert) => { 47 | const filePath = generators.provider.getFilePath('EventProvider', OPTS) 48 | assert.equal(filePath, path.join(__dirname, 'providers', 'EventProvider.js')) 49 | }) 50 | 51 | test('get path to the controller file', (assert) => { 52 | const filePath = generators.httpController.getFilePath('User', OPTS) 53 | assert.equal(filePath, path.join(__dirname, 'app/Controllers/Http', 'UserController.js')) 54 | }) 55 | 56 | test('make controller file singular', (assert) => { 57 | const filePath = generators.httpController.getFilePath('Users', OPTS) 58 | assert.equal(filePath, path.join(__dirname, 'app/Controllers/Http', 'UserController.js')) 59 | }) 60 | 61 | test('normalize controller keyword', (assert) => { 62 | const filePath = generators.httpController.getFilePath('UsersController', OPTS) 63 | assert.equal(filePath, path.join(__dirname, 'app/Controllers/Http', 'UserController.js')) 64 | }) 65 | 66 | test('get data for the controller', (assert) => { 67 | const data = generators.httpController.getData('User', {}) 68 | assert.deepEqual(data, { name: 'UserController', resource: false, resourceName: 'user', resourceNamePlural: 'users' }) 69 | }) 70 | 71 | test('get path to the model file', (assert) => { 72 | const filePath = generators.model.getFilePath('User', OPTS) 73 | assert.equal(filePath, path.join(__dirname, 'app/Models', 'User.js')) 74 | }) 75 | 76 | test('singularize model name', (assert) => { 77 | const filePath = generators.model.getFilePath('Users', OPTS) 78 | assert.equal(filePath, path.join(__dirname, 'app/Models', 'User.js')) 79 | }) 80 | 81 | test('normalize model name', (assert) => { 82 | const filePath = generators.model.getFilePath('UsersModel', OPTS) 83 | assert.equal(filePath, path.join(__dirname, 'app/Models', 'User.js')) 84 | }) 85 | 86 | test('get data for model', (assert) => { 87 | const data = generators.model.getData('UsersModel', {}) 88 | assert.deepEqual(data, { name: 'User' }) 89 | }) 90 | 91 | test('get path to the trait file', (assert) => { 92 | const filePath = generators.trait.getFilePath('Attachable', OPTS) 93 | assert.equal(filePath, path.join(__dirname, 'app/Models/Traits', 'Attachable.js')) 94 | }) 95 | 96 | test('singularize trait name', (assert) => { 97 | const filePath = generators.trait.getFilePath('Attachables', OPTS) 98 | assert.equal(filePath, path.join(__dirname, 'app/Models/Traits', 'Attachable.js')) 99 | }) 100 | 101 | test('normalize trait name', (assert) => { 102 | const filePath = generators.trait.getFilePath('AttachablesTrait', OPTS) 103 | assert.equal(filePath, path.join(__dirname, 'app/Models/Traits', 'Attachable.js')) 104 | }) 105 | 106 | test('get data for trait', (assert) => { 107 | const data = generators.trait.getData('AttachablesTrait', {}) 108 | assert.deepEqual(data, { name: 'Attachable' }) 109 | }) 110 | 111 | test('get path to the middleware file', (assert) => { 112 | const filePath = generators.middleware.getFilePath('User', OPTS) 113 | assert.equal(filePath, path.join(__dirname, 'app/Middleware', 'User.js')) 114 | }) 115 | 116 | test('keep middleware singular', (assert) => { 117 | const filePath = generators.middleware.getFilePath('Users', OPTS) 118 | assert.equal(filePath, path.join(__dirname, 'app/Middleware', 'User.js')) 119 | }) 120 | 121 | test('normalize middleware name', (assert) => { 122 | const filePath = generators.middleware.getFilePath('UsersMiddleware', OPTS) 123 | assert.equal(filePath, path.join(__dirname, 'app/Middleware', 'User.js')) 124 | }) 125 | 126 | test('get middleware data', (assert) => { 127 | const data = generators.middleware.getData('UsersMiddleware', {}) 128 | assert.deepEqual(data, { name: 'User', http: false, ws: false }) 129 | }) 130 | 131 | test('get path to the hooks file', (assert) => { 132 | const filePath = generators.hook.getFilePath('User', OPTS) 133 | assert.equal(filePath, path.join(__dirname, 'app/Models/Hooks', 'UserHook.js')) 134 | }) 135 | 136 | test('keep hook name singular', (assert) => { 137 | const filePath = generators.hook.getFilePath('Users', OPTS) 138 | assert.equal(filePath, path.join(__dirname, 'app/Models/Hooks', 'UserHook.js')) 139 | }) 140 | 141 | test('normalize hook name', (assert) => { 142 | const filePath = generators.hook.getFilePath('Users_Hook', OPTS) 143 | assert.equal(filePath, path.join(__dirname, 'app/Models/Hooks', 'UserHook.js')) 144 | }) 145 | 146 | test('get data for hook', (assert) => { 147 | const data = generators.hook.getData('Users_Hook', {}) 148 | assert.deepEqual(data, { name: 'UserHook', method: 'method' }) 149 | }) 150 | 151 | test('use method name passed to flags', (assert) => { 152 | const data = generators.hook.getData('Users_Hook', { method: 'validatePassword' }) 153 | assert.deepEqual(data, { name: 'UserHook', method: 'validatePassword' }) 154 | }) 155 | 156 | test('get path to the view file', (assert) => { 157 | const filePath = generators.view.getFilePath('User', OPTS) 158 | assert.equal(filePath, path.join(__dirname, 'resources/views', 'user.edge')) 159 | }) 160 | 161 | test('get path to nested view file', (assert) => { 162 | const filePath = generators.view.getFilePath('users.list', OPTS) 163 | assert.equal(filePath, path.join(__dirname, 'resources/views', 'users/list.edge')) 164 | }) 165 | 166 | test('get data for the view', (assert) => { 167 | const data = generators.view.getData('users.list', {}) 168 | assert.deepEqual(data, { layout: null }) 169 | }) 170 | 171 | test('set layout on data', (assert) => { 172 | const data = generators.view.getData('users.list', { layout: 'master' }) 173 | assert.deepEqual(data, { layout: 'master' }) 174 | }) 175 | 176 | test('get path to the command file', (assert) => { 177 | const filePath = generators.command.getFilePath('makeTemplate', OPTS) 178 | assert.equal(filePath, path.join(__dirname, 'app/Commands', 'MakeTemplate.js')) 179 | }) 180 | 181 | test('keep command name singular', (assert) => { 182 | const filePath = generators.command.getFilePath('makeTemplates', OPTS) 183 | assert.equal(filePath, path.join(__dirname, 'app/Commands', 'MakeTemplate.js')) 184 | }) 185 | 186 | test('normalize command name', (assert) => { 187 | const filePath = generators.command.getFilePath('makeTemplateCommand', OPTS) 188 | assert.equal(filePath, path.join(__dirname, 'app/Commands', 'MakeTemplate.js')) 189 | }) 190 | 191 | test('get data for command', (assert) => { 192 | const data = generators.command.getData('makeTemplate', {}) 193 | assert.deepEqual(data, { name: 'MakeTemplate', commandName: 'make:template' }) 194 | }) 195 | 196 | test('get path to the schema file', (assert) => { 197 | const filePath = generators.schema.getFilePath('users', OPTS) 198 | assert.include(filePath, '_users_schema.js') 199 | }) 200 | 201 | test('get data for schema', (assert) => { 202 | const data = generators.schema.getData('users', {}) 203 | assert.deepEqual(data, { create: false, table: 'users', name: 'UsersSchema' }) 204 | }) 205 | 206 | test('pluralize table name', (assert) => { 207 | const data = generators.schema.getData('user', {}) 208 | assert.deepEqual(data, { create: false, table: 'users', name: 'UserSchema' }) 209 | }) 210 | 211 | test('snake case table name', (assert) => { 212 | const data = generators.schema.getData('UserProfile', {}) 213 | assert.deepEqual(data, { create: false, table: 'user_profiles', name: 'UserProfileSchema' }) 214 | }) 215 | 216 | test('get path to the listener file', (assert) => { 217 | const filePath = generators.listener.getFilePath('Http', OPTS) 218 | assert.equal(filePath, path.join(__dirname, 'app/Listeners', 'Http.js')) 219 | }) 220 | 221 | test('normalize listener name', (assert) => { 222 | const filePath = generators.listener.getFilePath('on_http', OPTS) 223 | assert.equal(filePath, path.join(__dirname, 'app/Listeners', 'OnHttp.js')) 224 | }) 225 | 226 | test('get data for listener', (assert) => { 227 | const data = generators.listener.getData('on_http', { method: 'start' }) 228 | assert.deepEqual(data, { name: 'OnHttp', method: 'start' }) 229 | }) 230 | 231 | test('get path to the seed file', (assert) => { 232 | const filePath = generators.seed.getFilePath('Database', OPTS) 233 | assert.equal(filePath, path.join(__dirname, 'database/seeds', 'DatabaseSeeder.js')) 234 | }) 235 | 236 | test('normalize seeder name', (assert) => { 237 | const filePath = generators.seed.getFilePath('DatabaseSeeder', OPTS) 238 | assert.equal(filePath, path.join(__dirname, 'database/seeds', 'DatabaseSeeder.js')) 239 | }) 240 | 241 | test('get data for seed', (assert) => { 242 | const data = generators.seed.getData('DatabaseSeeder', {}) 243 | assert.deepEqual(data, { name: 'DatabaseSeeder' }) 244 | }) 245 | 246 | test('get path to nested controller file', (assert) => { 247 | const filePath = generators.httpController.getFilePath('Admin/UserController', OPTS) 248 | assert.equal(filePath, path.join(__dirname, 'app/Controllers/Http/Admin', 'UserController.js')) 249 | }) 250 | 251 | test('get path to exception file', (assert) => { 252 | const filePath = generators.exception.getFilePath('Validation', OPTS) 253 | assert.equal(filePath, path.join(__dirname, 'app/Exceptions', 'ValidationException.js')) 254 | }) 255 | 256 | test('normalize exception file path', (assert) => { 257 | const filePath = generators.exception.getFilePath('ValidationException', OPTS) 258 | assert.equal(filePath, path.join(__dirname, 'app/Exceptions', 'ValidationException.js')) 259 | }) 260 | }) 261 | -------------------------------------------------------------------------------- /test/install.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const test = require('japa') 13 | const path = require('path') 14 | const fs = require('fs-extra') 15 | const Steps = require('cli-step') 16 | 17 | const BASE_PATH = path.join(__dirname, 'dummyProject') 18 | 19 | if (process.platform !== 'win32') { 20 | test.group('Install | Command', (group) => { 21 | group.before(async () => { 22 | await fs.ensureDir(BASE_PATH) 23 | await fs.outputJSON(path.join(BASE_PATH, 'package.json'), { 24 | name: 'dummy-project' 25 | }) 26 | }) 27 | 28 | group.afterEach(async () => { 29 | await fs.emptyDir(BASE_PATH) 30 | }) 31 | 32 | group.after(async () => { 33 | await fs.remove(BASE_PATH) 34 | }) 35 | 36 | test('install a package from npm', async (assert) => { 37 | process.chdir(BASE_PATH) 38 | const stepsCounter = new Steps(1) 39 | 40 | await require('../src/Services/install')('npm', stepsCounter, '@adonisjs/session') 41 | const exists = await fs.exists(path.join(BASE_PATH, 'node_modules/@adonisjs/session')) 42 | assert.isTrue(exists) 43 | }).timeout(0) 44 | 45 | test('throw exception when unable to install package', async (assert) => { 46 | assert.plan(2) 47 | process.chdir(BASE_PATH) 48 | 49 | const stepsCounter = new Steps(1) 50 | 51 | try { 52 | await require('../src/Services/install')('npm', stepsCounter, '@adonisjs/foo') 53 | } catch (error) { 54 | const exists = await fs.exists(path.join(BASE_PATH, 'node_modules/@adonisjs/foo')) 55 | assert.isFalse(exists) 56 | assert.include(error.message, 'npm ERR! code E404') 57 | } 58 | }).timeout(0) 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /test/new.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const test = require('japa') 13 | const path = require('path') 14 | const ace = require('@adonisjs/ace') 15 | const fs = require('fs-extra') 16 | const NewCommand = require('../src/Commands/New') 17 | 18 | /** 19 | * Ignoring tests in windows, since appveyor has 20 | * weird file permission issues 21 | */ 22 | test.group('New | Command', (group) => { 23 | group.before(() => { 24 | process.chdir(__dirname) 25 | }) 26 | 27 | group.after(async () => { 28 | await fs.remove(path.join(__dirname, './yardstick-app')) 29 | await fs.remove(path.join(__dirname, './yardstick')) 30 | }) 31 | 32 | group.beforeEach(() => { 33 | ace.commands = {} 34 | }) 35 | 36 | test('set default blueprint to fullstack app', async (assert) => { 37 | const newCommand = new NewCommand() 38 | assert.equal(newCommand._getBluePrint({}), 'adonisjs/adonis-fullstack-app') 39 | }) 40 | 41 | test('update blueprint when --api-only flag is defined', async (assert) => { 42 | const newCommand = new NewCommand() 43 | assert.equal(newCommand._getBluePrint({ apiOnly: true }), 'adonisjs/adonis-api-app') 44 | }) 45 | 46 | test('update blueprint when --slim flag is defined', async (assert) => { 47 | const newCommand = new NewCommand() 48 | assert.equal(newCommand._getBluePrint({ slim: true }), 'adonisjs/adonis-slim-app') 49 | }) 50 | 51 | test('give priority to api-only over slim', async (assert) => { 52 | const newCommand = new NewCommand() 53 | assert.equal(newCommand._getBluePrint({ slim: true, apiOnly: true }), 'adonisjs/adonis-api-app') 54 | }) 55 | 56 | test('give priority to blueprint over everything', async (assert) => { 57 | const newCommand = new NewCommand() 58 | assert.equal(newCommand._getBluePrint({ slim: true, apiOnly: true, 'blueprint': 'adonuxt' }), 'adonuxt') 59 | }) 60 | }) 61 | -------------------------------------------------------------------------------- /test/run-instructions.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-cli 3 | * 4 | * (c) Harminder Virk 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | const test = require('japa') 11 | const path = require('path') 12 | const ace = require('../lib/ace') 13 | const { Helpers, setupResolver } = require('@adonisjs/sink') 14 | const fs = require('fs-extra') 15 | const clearRequire = require('clear-require') 16 | 17 | const BASE_PATH = path.join(__dirname, 'dummyProject') 18 | const Context = require('../src/Commands/Instructions/Context') 19 | 20 | /** 21 | * Writes the instructions file to the `BASE_PATH`. 22 | * @param {String} contents 23 | */ 24 | const writeInstructionsJs = function (contents) { 25 | return fs.writeFile(path.join(BASE_PATH, 'instructions.js'), contents) 26 | } 27 | 28 | /** 29 | * Gives a new instance of contents 30 | * 31 | * @returns Context 32 | */ 33 | const getContext = function () { 34 | const command = new ace.Command() 35 | return new Context(command, new Helpers(BASE_PATH)) 36 | } 37 | 38 | if (process.platform !== 'win32') { 39 | test.group('Run instructions', (group) => { 40 | group.before(async () => { 41 | setupResolver() 42 | await fs.ensureDir(BASE_PATH) 43 | }) 44 | 45 | group.afterEach(async () => { 46 | clearRequire(path.join(BASE_PATH, 'instructions.js')) 47 | await fs.emptyDir(BASE_PATH) 48 | }) 49 | 50 | group.after(async () => { 51 | await fs.remove(BASE_PATH) 52 | }) 53 | 54 | group.beforeEach(() => { 55 | process.chdir(BASE_PATH) 56 | ace.commands = {} 57 | }) 58 | 59 | test('run instructions', async (assert) => { 60 | await writeInstructionsJs(` 61 | module.exports = async function (cli) { 62 | cli.executed = true 63 | }`) 64 | 65 | const ctx = getContext() 66 | await require('../src/Services/run-instructions')(ctx, BASE_PATH) 67 | assert.isTrue(ctx.executed) 68 | }).timeout(0) 69 | 70 | test('save config file via instructions', async (assert) => { 71 | const sessionTemplate = ` 72 | module.exports = { 73 | driver: 'cookie' 74 | } 75 | ` 76 | await fs.writeFile(path.join(BASE_PATH, 'session.mustache'), sessionTemplate) 77 | 78 | await writeInstructionsJs(` 79 | const path = require('path') 80 | module.exports = async function (cli) { 81 | await cli.makeConfig('session.js', path.join(__dirname, './session.mustache')) 82 | } 83 | `) 84 | 85 | await require('../src/Services/run-instructions')(getContext(), BASE_PATH) 86 | 87 | require(path.join(BASE_PATH, 'config/session.js')) 88 | }).timeout(0) 89 | 90 | test('throw exceptions of instructions file', async (assert) => { 91 | assert.plan(1) 92 | 93 | await writeInstructionsJs(` 94 | const path = require('path') 95 | module.exports = async function (cli) { 96 | cli.foo() 97 | }`) 98 | 99 | try { 100 | await require('../src/Services/run-instructions')(getContext(), BASE_PATH) 101 | } catch ({ message }) { 102 | assert.equal(message, 'instructions.js: cli.foo is not a function') 103 | } 104 | }).timeout(0) 105 | 106 | test('instructions call ace commands', async (assert) => { 107 | await writeInstructionsJs(` 108 | module.exports = async function (cli) { 109 | await cli.callCommand('make:model', { name: 'User' }) 110 | } 111 | `) 112 | 113 | await fs.writeFile(path.join(BASE_PATH, 'ace'), '') 114 | ace.addCommand(require('../src/Commands')['make:model']) 115 | 116 | await require('../src/Services/run-instructions')(getContext(), BASE_PATH) 117 | const exists = await fs.exists(path.join(BASE_PATH, 'app/Models/User.js')) 118 | assert.isTrue(exists) 119 | }).timeout(0) 120 | 121 | test('instructions copy files', async (assert) => { 122 | await writeInstructionsJs(` 123 | const path = require('path') 124 | 125 | module.exports = async function (cli) { 126 | await cli.copy(path.join(__dirname, './foo.js'), cli.helpers.tmpPath('./foo.js')) 127 | }`) 128 | 129 | await fs.writeFile(path.join(BASE_PATH, 'foo.js'), '') 130 | await require('../src/Services/run-instructions')(getContext(), BASE_PATH) 131 | require(path.join(BASE_PATH, 'tmp/foo.js')) 132 | }).timeout(0) 133 | 134 | test('ignore when instructions.js file does not exists', async (assert) => { 135 | await require('../src/Services/run-instructions')(getContext(), BASE_PATH) 136 | }).timeout(0) 137 | 138 | test('ignore when instructions.md file does not exists', async (assert) => { 139 | await require('../src/Services/render-instructions-md')(BASE_PATH, '@adonisjs/session') 140 | }).timeout(0) 141 | }) 142 | } 143 | -------------------------------------------------------------------------------- /test/verify-existing-folder.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* 4 | * adonis-cli 5 | * 6 | * (c) Harminder Virk 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | const test = require('japa') 13 | const path = require('path') 14 | const fs = require('fs-extra') 15 | const Steps = require('cli-step') 16 | const verifyExistingFolder = require('../src/Services/verify-existing-folder') 17 | 18 | test.group('Verify Existing Folder', (group) => { 19 | group.after(async () => { 20 | await fs.remove(path.join(__dirname, './yardstick-app')) 21 | await fs.remove(path.join(__dirname, './yardstick')) 22 | }) 23 | 24 | test('throw error when app dir exists and not empty', async (assert) => { 25 | const appPath = path.join(__dirname, './yardstick') 26 | await fs.ensureFile(path.join(appPath, 'package.json')) 27 | const stepsCounter = new Steps(1) 28 | 29 | assert.plan(1) 30 | 31 | try { 32 | await verifyExistingFolder(appPath, stepsCounter) 33 | } catch ({ message }) { 34 | assert.include(message, 'Cannot override contents of [yardstick]') 35 | await fs.remove(appPath) 36 | } 37 | }) 38 | 39 | test('work fine with directory exists but is empty', async (assert) => { 40 | const appPath = path.join(__dirname, './yardstick') 41 | await fs.ensureDir(appPath) 42 | const stepsCounter = new Steps(1) 43 | 44 | await verifyExistingFolder(appPath, stepsCounter) 45 | await fs.remove(appPath) 46 | }) 47 | 48 | test('ignore when directory doesn\'t exists', async (assert) => { 49 | const appPath = path.join(__dirname, './yardstick') 50 | const stepsCounter = new Steps(1) 51 | 52 | await verifyExistingFolder(appPath, stepsCounter) 53 | }) 54 | }) 55 | --------------------------------------------------------------------------------