├── .circleci └── config.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github ├── COMMIT_CONVENTION.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── lock.yml └── stale.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── assets └── create-adonis-ts-app.gif ├── bin └── run.ts ├── config.json ├── index.ts ├── japaFile.js ├── package-lock.json ├── package.json ├── src ├── Chalk │ ├── art.ts │ ├── greet.ts │ └── help.ts ├── Contracts │ └── index.ts ├── Helpers │ └── index.ts └── schematics │ └── packages.ts ├── tasks ├── ConfigureEncore │ └── index.ts ├── ConfigurePackages │ └── index.ts ├── ConfigureTests │ └── index.ts ├── FormatSource │ └── index.ts ├── GenerateManifest │ └── index.ts ├── InstallDependencies │ └── index.ts ├── Scaffold │ ├── copyTemplates.ts │ ├── createEditorConfig.ts │ ├── createGitIgnore.ts │ ├── createRcFile.ts │ ├── createTsConfig.ts │ ├── setupEslint.ts │ └── setupPrettier.ts └── index.ts ├── templates ├── api │ ├── ace │ ├── app │ │ └── Exceptions │ │ │ └── Handler.txt │ ├── commands │ │ └── index.txt │ ├── env.txt │ ├── providers │ │ └── AppProvider.txt │ ├── server.txt │ └── start │ │ ├── kernel.txt │ │ └── routes.txt ├── slim │ ├── ace │ ├── app │ │ └── Exceptions │ │ │ └── Handler.txt │ ├── commands │ │ └── index.txt │ ├── env.txt │ ├── providers │ │ └── AppProvider.txt │ ├── server.txt │ └── start │ │ ├── kernel.txt │ │ └── routes.txt ├── stubs │ ├── css │ │ └── app.css │ └── js │ │ └── app.js └── web │ ├── ace │ ├── app │ └── Exceptions │ │ └── Handler.txt │ ├── commands │ └── index.txt │ ├── env.txt │ ├── providers │ └── AppProvider.txt │ ├── public │ └── favicon.ico │ ├── resources │ └── views │ │ ├── errors │ │ ├── not-found.edge │ │ ├── server-error.edge │ │ └── unauthorized.edge │ │ └── welcome.edge │ ├── server.txt │ └── start │ ├── kernel.txt │ └── routes.txt └── tsconfig.json /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build_14.15.4: 4 | docker: 5 | - image: circleci/node:14.15.4 6 | working_directory: ~/app 7 | steps: 8 | - checkout 9 | - restore_cache: 10 | keys: 11 | - v1-dependencies-{{ checksum "package.json" }} 12 | - v1-dependencies- 13 | - run: npm install 14 | - save_cache: 15 | paths: 16 | - node_modules 17 | key: v1-dependencies-{{ checksum "package.json" }} 18 | - run: npm test 19 | build_latest: 20 | docker: 21 | - image: circleci/node:latest 22 | working_directory: ~/app 23 | steps: 24 | - checkout 25 | - restore_cache: 26 | keys: 27 | - v1-dependencies-{{ checksum "package.json" }} 28 | - v1-dependencies- 29 | - run: npm install 30 | - save_cache: 31 | paths: 32 | - node_modules 33 | key: v1-dependencies-{{ checksum "package.json" }} 34 | - run: npm test 35 | workflows: 36 | version: 2 37 | workflow: 38 | jobs: 39 | - build_14.15.4 40 | - build_latest 41 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.json] 12 | insert_final_newline = ignore 13 | 14 | [**.min.js] 15 | indent_style = ignore 16 | insert_final_newline = ignore 17 | 18 | [MakeFile] 19 | indent_style = space 20 | 21 | [*.md] 22 | trim_trailing_whitespace = false 23 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "plugin:adonis/typescriptPackage", 4 | "prettier" 5 | ], 6 | "plugins": [ 7 | "prettier" 8 | ], 9 | "rules": { 10 | "prettier/prettier": [ 11 | "error", 12 | { 13 | "endOfLine": "auto" 14 | } 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/COMMIT_CONVENTION.md: -------------------------------------------------------------------------------- 1 | ## Git Commit Message Convention 2 | 3 | > This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular). 4 | 5 | Using conventional commit messages, we can automate the process of generating the CHANGELOG file. All commits messages will automatically be validated against the following regex. 6 | 7 | ``` js 8 | /^(revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|ci|chore|types|build|improvement)((.+))?: .{1,50}/ 9 | ``` 10 | 11 | ## Commit Message Format 12 | A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**: 13 | 14 | > The **scope** is optional 15 | 16 | ``` 17 | feat(router): add support for prefix 18 | 19 | Prefix makes it easier to append a path to a group of routes 20 | ``` 21 | 22 | 1. `feat` is type. 23 | 2. `router` is scope and is optional 24 | 3. `add support for prefix` is the subject 25 | 4. The **body** is followed by a blank line. 26 | 5. The optional **footer** can be added after the body, followed by a blank line. 27 | 28 | ## Types 29 | Only one type can be used at a time and only following types are allowed. 30 | 31 | - feat 32 | - fix 33 | - docs 34 | - style 35 | - refactor 36 | - perf 37 | - test 38 | - workflow 39 | - ci 40 | - chore 41 | - types 42 | - build 43 | 44 | If a type is `feat`, `fix` or `perf`, then the commit will appear in the CHANGELOG.md file. However if there is any BREAKING CHANGE, the commit will always appear in the changelog. 45 | 46 | ### Revert 47 | If the commit reverts a previous commit, it should begin with `revert:`, followed by the header of the reverted commit. In the body it should say: `This reverts commit `., where the hash is the SHA of the commit being reverted. 48 | 49 | ## Scope 50 | The scope could be anything specifying place of the commit change. For example: `router`, `view`, `querybuilder`, `database`, `model` and so on. 51 | 52 | ## Subject 53 | The subject contains succinct description of the change: 54 | 55 | - use the imperative, present tense: "change" not "changed" nor "changes". 56 | - don't capitalize first letter 57 | - no dot (.) at the end 58 | 59 | ## Body 60 | 61 | Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes". 62 | The body should include the motivation for the change and contrast this with previous behavior. 63 | 64 | ## Footer 65 | 66 | The footer should contain any information about **Breaking Changes** and is also the place to 67 | reference GitHub issues that this commit **Closes**. 68 | 69 | **Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this. 70 | 71 | -------------------------------------------------------------------------------- /.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/AdonisCommunity/create-adonis-ts-app/blob/master/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 | -------------------------------------------------------------------------------- /.github/lock.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Lock Threads - https://github.com/dessant/lock-threads-app 2 | 3 | # Number of days of inactivity before a closed issue or pull request is locked 4 | daysUntilLock: 60 5 | 6 | # Skip issues and pull requests created before a given timestamp. Timestamp must 7 | # follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable 8 | skipCreatedBefore: false 9 | 10 | # Issues and pull requests with these labels will be ignored. Set to `[]` to disable 11 | exemptLabels: ['Type: Security'] 12 | 13 | # Label to add before locking, such as `outdated`. Set to `false` to disable 14 | lockLabel: false 15 | 16 | # Comment to post before locking. Set to `false` to disable 17 | lockComment: > 18 | This thread has been automatically locked since there has not been 19 | any recent activity after it was closed. Please open a new issue for 20 | related bugs. 21 | 22 | # Assign `resolved` as the reason for locking. Set to `false` to disable 23 | setLockReason: false 24 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | 4 | # Number of days of inactivity before a stale issue is closed 5 | daysUntilClose: 7 6 | 7 | # Issues with these labels will never be considered stale 8 | exemptLabels: 9 | - 'Type: Security' 10 | 11 | # Label to use when marking an issue as stale 12 | staleLabel: 'Status: Abandoned' 13 | 14 | # Comment to post when marking an issue as stale. Set to `false` to disable 15 | markComment: > 16 | This issue has been automatically marked as stale because it has not had 17 | recent activity. It will be closed if no further activity occurs. Thank you 18 | for your contributions. 19 | 20 | # Comment to post when closing a stale issue. Set to `false` to disable 21 | closeComment: false 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .DS_STORE 4 | .nyc_output 5 | .idea 6 | .vscode/ 7 | *.sublime-project 8 | *.sublime-workspace 9 | *.log 10 | build 11 | dist 12 | yarn.lock 13 | shrinkwrap.yaml 14 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | message="chore(release): %s" 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | build 2 | docs 3 | *.md 4 | config.json 5 | .eslintrc.json 6 | package.json 7 | *.html 8 | *.txt 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "semi": false, 4 | "singleQuote": true, 5 | "useTabs": false, 6 | "quoteProps": "consistent", 7 | "bracketSpacing": true, 8 | "arrowParens": "always", 9 | "printWidth": 100 10 | } 11 | -------------------------------------------------------------------------------- /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 2020 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 |
2 | 3 |
4 | 5 |
6 | 7 |
8 | 9 | [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url] [![synk-image]][synk-url] 10 | 11 |
12 | 13 |
14 | 15 | 16 | # Create AdonisJS App 17 | > AdonisJS Typescript starter template 18 | 19 | This is the official starter template to create AdonisJS applications. You can choose between one of the following boilerplates 20 | 21 | - **api**: Project structure + dependencies tailored for creating a REST API server. 22 | - **web**: Traditional web application with server rendered templates and pre-configured support for sessions. 23 | - **slim**: A smallest possible AdonisJS application. Still way powerful and feature rich than an Express application. 24 | 25 | ## Creating a new app 26 | 27 | ```sh 28 | npm init adonis-ts-app hello-world 29 | ``` 30 | 31 | Yarn users 32 | 33 | ```sh 34 | yarn create adonis-ts-app hello-world 35 | ``` 36 | 37 | ![](assets/create-adonis-ts-app.gif) 38 | 39 | ## Options 40 | 41 | Execute the following command to see the help output and available options 42 | 43 | ```sh 44 | npm init adonis-ts-app 45 | ``` 46 | 47 | ``` 48 | _ _ _ _ 49 | / \ __| | ___ _ __ (_)___ | |___ 50 | / _ \ / _` |/ _ \| '_ \| / __|_ | / __| 51 | / ___ \ (_| | (_) | | | | \__ \ |_| \__ \ 52 | /_/ \_\__,_|\___/|_| |_|_|___/\___/|___/ 53 | 54 | npm init adonis-ts-app 55 | 56 | Options 57 | --boilerplate [api, web, slim] Select the project boilerplate 58 | --name Specify application name 59 | --eslint Enable/disable eslint setup 60 | --prettier Enable/disable prettier setup 61 | --encore Enable/disable encore setup 62 | --debug Turn on the debug mode 63 | ``` 64 | 65 | #### boilerplate 66 | 67 | Choose the boilerplate by passing the flag 68 | 69 | ```sh 70 | npm init adonis-ts-app hello-world -- --boilerplate=web 71 | ``` 72 | 73 | #### name 74 | 75 | Define the application name. The `name` property inside the `package.json` file will reflect this value 76 | 77 | ```sh 78 | npm init adonis-ts-app hello-world -- --name=my-app 79 | ``` 80 | 81 | #### eslint 82 | 83 | Configure eslint 84 | 85 | ```sh 86 | npm init adonis-ts-app hello-world -- --eslint 87 | ``` 88 | 89 | #### prettier 90 | 91 | Configure prettier 92 | 93 | ```sh 94 | npm init adonis-ts-app hello-world -- --prettier 95 | ``` 96 | 97 | #### encore 98 | 99 | Configure encore 100 | 101 | ```sh 102 | npm init adonis-ts-app hello-world -- --encore 103 | ``` 104 | 105 | #### debug 106 | 107 | Debug the project creation process. This flag will use the verbose output for better debugging experience. 108 | 109 | ```sh 110 | npm init adonis-ts-app hello-world -- --debug 111 | ``` 112 | 113 |
114 | Built with ❤︎ by Harminder Virk 115 |
116 | 117 | [npm-image]: https://img.shields.io/npm/v/create-adonis-ts-app/latest.svg?style=for-the-badge&logo=npm 118 | [npm-url]: https://www.npmjs.com/package/create-adonis-ts-app/v/alpha "npm" 119 | 120 | [typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript 121 | 122 | [license-url]: LICENSE.md 123 | [license-image]: https://img.shields.io/github/license/adonisjs-community/create-adonis-ts-app?style=for-the-badge 124 | 125 | [synk-image]: https://img.shields.io/snyk/vulnerabilities/github/adonisjs-community/create-adonis-ts-app?label=Synk%20Vulnerabilities&style=for-the-badge 126 | [synk-url]: https://snyk.io/test/github/adonisjs-community/create-adonis-ts-app?targetFile=package.json "synk" 127 | -------------------------------------------------------------------------------- /assets/create-adonis-ts-app.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adonisjs-community/create-adonis-ts-app/0d6a1d6d4149d647fe04ccc1b8a7939a2fdb464e/assets/create-adonis-ts-app.gif -------------------------------------------------------------------------------- /bin/run.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { runTasks } from '../index' 4 | runTasks(process.argv.slice(2)) 5 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "core": true, 3 | "license": "MIT", 4 | "services": [ 5 | "circleci" 6 | ], 7 | "minNodeVersion": "14.15.4", 8 | "probotApps": [ 9 | "stale", 10 | "lock" 11 | ] 12 | } -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * create-adonis-ts-app 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 | import getops from 'getopts' 11 | import { removeSync } from 'fs-extra' 12 | import { Application } from '@adonisjs/application' 13 | import { utils, logger, tasksUi } from '@adonisjs/sink' 14 | 15 | import { tasks } from './tasks' 16 | import { greet } from './src/Chalk/greet' 17 | import { showArt } from './src/Chalk/art' 18 | import { getHelp } from './src/Chalk/help' 19 | import { getState } from './src/Helpers' 20 | 21 | /** 22 | * Running all the tasks to create a new project. 23 | */ 24 | export async function runTasks(args: string[]) { 25 | showArt() 26 | 27 | /** 28 | * Setup command line arguments 29 | */ 30 | const argv = getops(args, { 31 | string: ['boilerplate', 'name'], 32 | boolean: ['eslint', 'debug', 'prettier', 'encore'], 33 | default: { 34 | eslint: null, 35 | debug: false, 36 | prettier: null, 37 | encore: null, 38 | }, 39 | }) 40 | 41 | /** 42 | * Show help when no arguments are passed 43 | */ 44 | if (!argv._.length) { 45 | console.log(getHelp(utils.getPackageManager(process.cwd()))) 46 | return 47 | } 48 | 49 | /** 50 | * First argument is the project path 51 | */ 52 | const projectPath = argv._[0].trim() 53 | 54 | console.log('') 55 | console.log(logger.colors.green('CUSTOMIZE PROJECT')) 56 | 57 | /** 58 | * Setup state 59 | */ 60 | const state = await getState(projectPath, { 61 | client: utils.getPackageManager(projectPath), 62 | projectName: argv.name, 63 | debug: argv.debug, 64 | boilerplate: argv.boilerplate, 65 | eslint: argv.eslint, 66 | prettier: argv.prettier, 67 | encore: argv.encore, 68 | }) 69 | 70 | /** 71 | * Return when directory is not empty 72 | */ 73 | if (!utils.isEmptyDir(state.absPath)) { 74 | const errors = [ 75 | `Cannot overwrite contents of {${projectPath}} directory.`, 76 | 'Make sure to define path to an empty directory', 77 | ] 78 | 79 | console.log('') 80 | logger.error(errors.join(' ')) 81 | return 82 | } 83 | 84 | /** 85 | * Setup application 86 | */ 87 | const application = new Application(state.absPath, 'console', { 88 | typescript: true, 89 | }) 90 | 91 | /** 92 | * Decide the ui renderer to use 93 | */ 94 | const tasksManager = state.debug ? tasksUi.verbose() : tasksUi() 95 | 96 | /** 97 | * Execute all tasks 98 | */ 99 | tasks(state).forEach(({ title, actions }) => { 100 | tasksManager.add(title, async (taskLogger, task) => { 101 | for (let action of actions) { 102 | await action(application, taskLogger, state) 103 | } 104 | await task.complete() 105 | }) 106 | }) 107 | 108 | console.log('') 109 | console.log(logger.colors.green('RUNNING TASKS')) 110 | 111 | /** 112 | * Run tasks 113 | */ 114 | try { 115 | await tasksManager.run() 116 | } catch (error) { 117 | tasksManager.state = 'failed' 118 | tasksManager.error = error 119 | } 120 | 121 | console.log('') 122 | 123 | /** 124 | * Notify about failure 125 | */ 126 | if (tasksManager.state === 'failed') { 127 | logger.error('Unable to create project. Cleaning up') 128 | removeSync(state.absPath) 129 | return 130 | } 131 | 132 | /** 133 | * Greet the user to get started 134 | */ 135 | logger.success('Project created successfully') 136 | greet(state) 137 | } 138 | -------------------------------------------------------------------------------- /japaFile.js: -------------------------------------------------------------------------------- 1 | require('@adonisjs/require-ts/build/register') 2 | 3 | const { configure } = require('japa') 4 | configure({ 5 | files: ['test/**/*.spec.ts'], 6 | }) 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-adonis-ts-app", 3 | "version": "4.2.7", 4 | "description": "Boilerplate to create a new AdonisJs typescript project", 5 | "main": "build/index.js", 6 | "files": [ 7 | "build/bin", 8 | "build/src", 9 | "build/Tasks", 10 | "build/tasks", 11 | "build/templates", 12 | "build/index.d.ts", 13 | "build/index.js" 14 | ], 15 | "scripts": { 16 | "mrm": "mrm --preset=@adonisjs/mrm-preset", 17 | "pretest": "npm run lint", 18 | "test": "node japaFile.js", 19 | "lint": "eslint . --ext=.ts", 20 | "clean": "del build", 21 | "compile": "npm run lint && npm run clean && tsc && copyfiles \"templates/**/*\" build", 22 | "build": "npm run compile", 23 | "commit": "git-cz", 24 | "release": "np", 25 | "version": "npm run build", 26 | "sync-labels": "github-label-sync --labels ./node_modules/@adonisjs/mrm-preset/gh-labels.json adonisjs-community/create-adonis-ts-app", 27 | "format": "prettier --write .", 28 | "prepublishOnly": "npm run build" 29 | }, 30 | "author": "virk,adonisjs", 31 | "license": "MIT", 32 | "devDependencies": { 33 | "@adonisjs/mrm-preset": "^5.0.3", 34 | "@adonisjs/require-ts": "^2.0.13", 35 | "@types/node": "^18.15.1", 36 | "commitizen": "^4.3.0", 37 | "copyfiles": "^2.4.1", 38 | "cz-conventional-changelog": "^3.3.0", 39 | "del-cli": "^5.0.0", 40 | "doctoc": "^2.2.1", 41 | "eslint": "^8.36.0", 42 | "eslint-config-prettier": "^8.7.0", 43 | "eslint-plugin-adonis": "^2.1.1", 44 | "eslint-plugin-prettier": "^4.2.1", 45 | "github-label-sync": "^2.3.1", 46 | "husky": "^8.0.3", 47 | "japa": "^4.0.0", 48 | "mrm": "^4.1.14", 49 | "np": "^7.6.3", 50 | "prettier": "^2.8.4", 51 | "typescript": "^4.9.5" 52 | }, 53 | "nyc": { 54 | "exclude": [ 55 | "test" 56 | ], 57 | "extension": [ 58 | ".ts" 59 | ] 60 | }, 61 | "husky": { 62 | "hooks": { 63 | "commit-msg": "node ./node_modules/@adonisjs/mrm-preset/validateCommit/conventional/validate.js" 64 | } 65 | }, 66 | "config": { 67 | "commitizen": { 68 | "path": "cz-conventional-changelog" 69 | } 70 | }, 71 | "bin": { 72 | "create-adonis-ts-app": "build/bin/run.js" 73 | }, 74 | "publishConfig": { 75 | "access": "public", 76 | "tag": "latest" 77 | }, 78 | "dependencies": { 79 | "@adonisjs/application": "^5.3.0", 80 | "@adonisjs/sink": "^5.4.3", 81 | "@poppinss/prompts": "^2.0.2", 82 | "@poppinss/utils": "^5.0.0", 83 | "@types/fs-extra": "^9.0.13", 84 | "cli-width": "^3.0.0", 85 | "execa": "^5.1.1", 86 | "fs-extra": "^10.1.0", 87 | "getopts": "^2.3.0", 88 | "gradient-string": "^2.0.2" 89 | }, 90 | "repository": { 91 | "type": "git", 92 | "url": "git+https://github.com/AdonisCommunity/adonis-ts-boilerplate.git" 93 | }, 94 | "keywords": [ 95 | "adonisjs", 96 | "typescript" 97 | ], 98 | "bugs": { 99 | "url": "https://github.com/AdonisCommunity/adonis-ts-boilerplate/issues" 100 | }, 101 | "homepage": "https://github.com/AdonisCommunity/adonis-ts-boilerplate#readme", 102 | "np": { 103 | "contents": ".", 104 | "anyBranch": false 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Chalk/art.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * create-adonis-ts-app 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 | import gradient from 'gradient-string' 11 | 12 | const art = Buffer.from( 13 | 'CiAgICAgXyAgICAgICBfICAgICAgICAgICAgIF8gICAgICAgICBfIF9fX18gIAogICAgLyBcICAgX198IHwgX19fICBfIF9fIChfKV9fXyAgICB8IC8gX19ffCAKICAgLyBfIFwgLyBfYCB8LyBfIFx8ICdfIFx8IC8gX198XyAgfCBcX19fIFwgCiAgLyBfX18gXCAoX3wgfCAoXykgfCB8IHwgfCBcX18gXCB8X3wgfF9fXykgfAogL18vICAgXF9cX18sX3xcX19fL3xffCB8X3xffF9fXy9cX19fL3xfX19fLyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCg==', 14 | 'base64' 15 | ).toString() 16 | 17 | export const showArt = () => console.log(gradient.pastel.multiline(art)) 18 | -------------------------------------------------------------------------------- /src/Chalk/greet.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * create-adonis-ts-app 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 | import { instructions, logger } from '@adonisjs/sink' 11 | import { CliState } from '../Contracts' 12 | 13 | /** 14 | * Greet post creation 15 | */ 16 | export const greet = ({ baseName }: CliState) => { 17 | console.log('') 18 | 19 | instructions() 20 | .heading(logger.colors.dim('Run following commands to get started')) 21 | .add(logger.colors.cyan(`cd ${baseName}`)) 22 | .add(logger.colors.cyan('node ace serve --watch')) 23 | .render() 24 | 25 | console.log('') 26 | } 27 | -------------------------------------------------------------------------------- /src/Chalk/help.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * create-adonis-ts-app 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 | import { logger } from '@adonisjs/sink' 11 | 12 | /** 13 | * Text to show on the help screen. Its simple and hence writing it 14 | * by hand is fine 15 | */ 16 | export const getHelp = (packageManager: 'npm' | 'pnpm' | 'yarn') => { 17 | const runSentence = 18 | packageManager === 'yarn' 19 | ? 'yarn create adonis-ts-app' 20 | : packageManager === 'pnpm' 21 | ? 'pnpm init adonis-ts-app' 22 | : 'npm init adonis-ts-app' 23 | 24 | return `${logger.colors.green(runSentence)} ${logger.colors.dim('')} 25 | 26 | ${logger.colors.yellow().bold('Options')} 27 | ${logger.colors.green('--boilerplate')} ${logger.colors.dim( 28 | '[api, web, slim]' 29 | )} ${logger.colors.dim('Select the project boilerplate')} 30 | ${logger.colors.green('--name')} ${logger.colors.dim( 31 | '' 32 | )} ${logger.colors.dim('Specify application name')} 33 | ${logger.colors.green('--eslint')} ${logger.colors.dim( 34 | '' 35 | )} ${logger.colors.dim('Enable/disable eslint setup')} 36 | ${logger.colors.green('--prettier')} ${logger.colors.dim( 37 | '' 38 | )} ${logger.colors.dim('Enable/disable prettier setup')} 39 | ${logger.colors.green('--encore')} ${logger.colors.dim( 40 | '' 41 | )} ${logger.colors.dim('Enable/disable encore setup')} 42 | ${logger.colors.green('--debug')} ${logger.colors.dim( 43 | '' 44 | )} ${logger.colors.dim('Turn on the debug mode')}` 45 | } 46 | -------------------------------------------------------------------------------- /src/Contracts/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * create-adonis-ts-app 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 | import { logger as sinkLogger, files } from '@adonisjs/sink' 11 | import { ApplicationContract } from '@ioc:Adonis/Core/Application' 12 | 13 | /** 14 | * Shape of task functions 15 | */ 16 | export type TaskFn = ( 17 | application: ApplicationContract, 18 | logger: typeof sinkLogger, 19 | state: CliState 20 | ) => void | Promise 21 | 22 | /** 23 | * CLI state 24 | */ 25 | export type CliState = { 26 | baseName: string 27 | absPath: string 28 | debug: boolean 29 | client: 'npm' | 'pnpm' | 'yarn' 30 | boilerplate: 'web' | 'api' | 'slim' 31 | projectName: string 32 | eslint: boolean 33 | prettier: boolean 34 | encore: boolean 35 | pkg: files.PackageJsonFile 36 | } 37 | -------------------------------------------------------------------------------- /src/Helpers/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * create-adonis-ts-app 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 | import cliWidth from 'cli-width' 11 | import { isAbsolute, join, basename } from 'path' 12 | import { files, getPrompt } from '@adonisjs/sink' 13 | 14 | import { CliState } from '../Contracts' 15 | import { ensureDirSync } from 'fs-extra' 16 | 17 | /** 18 | * Getting width of the stdout to put log messages in one line 19 | */ 20 | const WIDTH = cliWidth() 21 | 22 | /** 23 | * Returns the state for creating project 24 | */ 25 | export async function getState( 26 | projectRoot: string, 27 | options: { 28 | debug?: boolean 29 | boilerplate?: 'web' | 'api' | 'slim' 30 | projectName?: string 31 | eslint?: boolean 32 | prettier?: boolean 33 | client: 'npm' | 'pnpm' | 'yarn' 34 | encore?: boolean 35 | } 36 | ): Promise { 37 | /** 38 | * If project root is not absolute, then we derive it from the current 39 | * working directory 40 | */ 41 | const absPath = isAbsolute(projectRoot) ? projectRoot : join(process.cwd(), projectRoot) 42 | 43 | /** 44 | * Prompt for boilerplate 45 | */ 46 | if (!options.boilerplate) { 47 | try { 48 | options.boilerplate = await getPrompt().choice('Select the project structure', [ 49 | { 50 | name: 'api', 51 | message: 'api', 52 | hint: ' (Tailored for creating a REST API server)', 53 | }, 54 | { 55 | name: 'web', 56 | message: 'web', 57 | hint: ' (Traditional web application with server rendered templates)', 58 | }, 59 | { 60 | name: 'slim', 61 | message: 'slim', 62 | hint: ' (A smallest possible AdonisJS application)', 63 | }, 64 | ]) 65 | } catch (_) { 66 | process.exit(1) 67 | } 68 | } 69 | 70 | /** 71 | * Ask for the project name 72 | */ 73 | if (!options.projectName) { 74 | try { 75 | options.projectName = await getPrompt().ask('Enter the project name', { 76 | default: basename(absPath), 77 | }) 78 | } catch (_) { 79 | process.exit(1) 80 | } 81 | } 82 | 83 | /** 84 | * Prompt for ESLINT 85 | */ 86 | if (options.eslint === null) { 87 | try { 88 | options.eslint = await getPrompt().confirm('Setup eslint?') 89 | } catch (_) { 90 | process.exit(1) 91 | } 92 | } 93 | 94 | /** 95 | * Prompt for Prettier. Only when accepted to use prettier 96 | */ 97 | if (options.prettier === null && options.eslint) { 98 | try { 99 | options.prettier = await getPrompt().confirm('Setup prettier?') 100 | } catch (_) { 101 | process.exit(1) 102 | } 103 | } 104 | 105 | /** 106 | * Prompt for Webpack encore. We only do it during the web 107 | * boilerplate. For others, a user can define it using 108 | * the flag 109 | */ 110 | if (options.encore === null && options.boilerplate === 'web') { 111 | try { 112 | options.encore = await getPrompt().confirm( 113 | 'Configure webpack encore for compiling frontend assets?' 114 | ) 115 | } catch (_) { 116 | process.exit(1) 117 | } 118 | } 119 | 120 | /** 121 | * Create project root 122 | */ 123 | ensureDirSync(absPath) 124 | 125 | const pkg = new files.PackageJsonFile(absPath, options.debug ? 'inherit' : undefined) 126 | pkg.set('name', options.projectName) 127 | pkg.set('version', '1.0.0') 128 | pkg.set('private', true) 129 | pkg.setScript('dev', 'node ace serve --watch') 130 | pkg.setScript('build', 'node ace build --production') 131 | pkg.setScript('start', 'node server.js') 132 | pkg.setScript('test', 'node ace test') 133 | 134 | /** 135 | * Set environment variables that can be used by the packages 136 | * to tweak their setup behavior 137 | */ 138 | process.env['ADONIS_CREATE_APP_NAME'] = options.projectName! 139 | process.env['ADONIS_CREATE_ESLINT'] = String(options.eslint) 140 | process.env['ADONIS_CREATE_PRETTIER'] = String(options.prettier) 141 | process.env['ADONIS_CREATE_APP_CLIENT'] = options.client 142 | process.env['ADONIS_CREATE_APP_BOILERPLATE'] = options.boilerplate 143 | process.env['ADONIS_CREATE_APP_ENCORE'] = String(options.encore) 144 | 145 | return { 146 | baseName: projectRoot, 147 | absPath: absPath, 148 | boilerplate: options.boilerplate!, 149 | pkg: pkg, 150 | projectName: options.projectName!, 151 | eslint: options.eslint!, 152 | prettier: options.prettier!, 153 | client: options.client, 154 | encore: options.encore!, 155 | debug: !!options.debug, 156 | } 157 | } 158 | 159 | /** 160 | * Log installing dependencies message 161 | */ 162 | export function getInstallMessage(list: string[]): string { 163 | const dependencies: string[] = [] 164 | const spaceBetweenDependencies = 2 165 | 166 | /** 167 | * Since the log message is indented, we need to leave certain columns 168 | */ 169 | let widthConsumed = 17 + 20 170 | 171 | for (let dependency of list) { 172 | if (widthConsumed + dependency.length + spaceBetweenDependencies > WIDTH) { 173 | break 174 | } 175 | 176 | /** 177 | * Increase the width consumed 178 | */ 179 | widthConsumed += dependency.length + spaceBetweenDependencies 180 | 181 | /** 182 | * Add dependency to the named dependencies 183 | */ 184 | dependencies.push(dependency) 185 | } 186 | 187 | /** 188 | * Total number of out of bound dependencies 189 | */ 190 | const outOfBounds = list.length - dependencies.length 191 | 192 | if (outOfBounds === 1 && list[list.length - 1].length <= 13) { 193 | dependencies.push(list[list.length - 1]) 194 | } else if (outOfBounds > 0) { 195 | dependencies.push(`and ${outOfBounds} other${outOfBounds !== 1 ? 's' : ''}`) 196 | } 197 | 198 | return dependencies.join(', ') 199 | } 200 | -------------------------------------------------------------------------------- /src/schematics/packages.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import { CliState } from '../Contracts' 11 | 12 | export const packages: { 13 | [K in CliState['boilerplate']]: { 14 | [pkg: string]: { version: string } 15 | } 16 | } = { 17 | web: { 18 | '@adonisjs/core': { 19 | version: '^5.8.0', 20 | }, 21 | '@adonisjs/repl': { 22 | version: '^3.1.0', 23 | }, 24 | '@adonisjs/session': { 25 | version: '^6.2.0', 26 | }, 27 | '@adonisjs/view': { 28 | version: '^6.1.0', 29 | }, 30 | '@adonisjs/shield': { 31 | version: '^7.0.0', 32 | }, 33 | }, 34 | api: { 35 | '@adonisjs/core': { 36 | version: '^5.8.0', 37 | }, 38 | '@adonisjs/repl': { 39 | version: '^3.1.0', 40 | }, 41 | }, 42 | slim: { 43 | '@adonisjs/core': { 44 | version: '^5.8.0', 45 | }, 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /tasks/ConfigureEncore/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import execa from 'execa' 11 | import { join } from 'path' 12 | import { files, logger as SinkLogger } from '@adonisjs/sink' 13 | import { TaskFn } from '../../src/Contracts' 14 | 15 | /** 16 | * Creates the CSS entrypoint 17 | */ 18 | function createCssEntryPoint(absPath: string, logger: typeof SinkLogger) { 19 | const template = join(__dirname, '..', '..', 'templates/stubs/css/app.css') 20 | const outFile = 'resources/css/app.css' 21 | 22 | const cssFile = new files.MustacheFile(absPath, outFile, template).apply({}) 23 | cssFile.overwrite = true 24 | cssFile.commit() 25 | logger.action('create').succeeded(outFile) 26 | } 27 | 28 | /** 29 | * Creates the JS entrypoint 30 | */ 31 | function createJsEntryPoint(absPath: string, logger: typeof SinkLogger) { 32 | const template = join(__dirname, '..', '..', 'templates/stubs/js/app.js') 33 | const outFile = 'resources/js/app.js' 34 | 35 | const jsFile = new files.MustacheFile(absPath, outFile, template).apply({}) 36 | jsFile.overwrite = true 37 | jsFile.commit() 38 | logger.action('create').succeeded(outFile) 39 | } 40 | 41 | /** 42 | * Setup webpack encore inside the project 43 | */ 44 | const task: TaskFn = async (_, logger, { absPath, debug }) => { 45 | let spinner: ReturnType | undefined 46 | if (!debug) { 47 | spinner = logger.await( 48 | `installing @symfony/webpack-core ${logger.colors.yellow('(usually takes longer)')}` 49 | ) 50 | } 51 | 52 | try { 53 | await execa('node', ['ace', 'configure', 'encore'], { 54 | cwd: absPath, 55 | ...(debug ? { stdio: 'inherit' } : {}), 56 | }) 57 | spinner && spinner.stop() 58 | 59 | createCssEntryPoint(absPath, logger) 60 | createJsEntryPoint(absPath, logger) 61 | } catch (error) { 62 | spinner && spinner.stop() 63 | throw error 64 | } 65 | } 66 | 67 | export default task 68 | -------------------------------------------------------------------------------- /tasks/ConfigurePackages/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * create-adonis-ts-app 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 | import { tasks } from '@adonisjs/sink' 11 | import { TaskFn } from '../../src/Contracts' 12 | import { packages } from '../../src/schematics/packages' 13 | 14 | /** 15 | * Configure installed packages by running `node ace invoke instructions` 16 | * on all of them in sequence 17 | */ 18 | const task: TaskFn = async (application, logger, { boilerplate, absPath }) => { 19 | let instructionsError: Error | null = null 20 | 21 | /** 22 | * Executing instructions in sequence. Do not convert this block to 23 | * parallel execution, since two instructions touching the same 24 | * file may lead to race conditions. 25 | */ 26 | try { 27 | for (let pkg of Object.keys(packages[boilerplate])) { 28 | await new tasks.Instructions(pkg, absPath, application, false).useLogger(logger).execute() 29 | } 30 | } catch (error) { 31 | instructionsError = error 32 | } 33 | 34 | /** 35 | * Handle error 36 | */ 37 | if (instructionsError) { 38 | logger.fatal(instructionsError) 39 | throw instructionsError 40 | } 41 | } 42 | 43 | export default task 44 | -------------------------------------------------------------------------------- /tasks/ConfigureTests/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import execa from 'execa' 11 | import { TaskFn } from '../../src/Contracts' 12 | 13 | /** 14 | * Configure tests 15 | */ 16 | const task: TaskFn = async (_, logger, { absPath, debug }) => { 17 | let spinner: ReturnType | undefined 18 | if (!debug) { 19 | spinner = logger.await('Configuring tests') 20 | } 21 | 22 | try { 23 | await execa('node', ['ace', 'configure', 'tests'], { 24 | cwd: absPath, 25 | ...(debug ? { stdio: 'inherit' } : {}), 26 | }) 27 | spinner && spinner.stop() 28 | } catch (error) { 29 | spinner && spinner.stop() 30 | throw error 31 | } 32 | } 33 | 34 | export default task 35 | -------------------------------------------------------------------------------- /tasks/FormatSource/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * create-adonis-ts-app 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 | import execa from 'execa' 11 | import { TaskFn } from '../../src/Contracts' 12 | 13 | /** 14 | * Format source files using prettier 15 | */ 16 | const task: TaskFn = async (_, __, { absPath, prettier, debug }) => { 17 | if (!prettier) { 18 | return 19 | } 20 | 21 | /** 22 | * Formatting source files is a secondary action and errors can be 23 | * ignored 24 | */ 25 | try { 26 | await execa('npm', ['run', 'format'], { 27 | cwd: absPath, 28 | ...(debug ? { stdio: 'inherit' } : {}), 29 | }) 30 | } catch {} 31 | } 32 | 33 | export default task 34 | -------------------------------------------------------------------------------- /tasks/GenerateManifest/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * create-adonis-ts-app 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 | import execa from 'execa' 11 | import { TaskFn } from '../../src/Contracts' 12 | 13 | /** 14 | * Generate manifest file by running `node ace generate:manifest` file 15 | */ 16 | const task: TaskFn = async (_, __, { absPath, debug }) => { 17 | /** 18 | * Generating ace-manifest file is a secondary action and errors 19 | * can be ignored 20 | */ 21 | try { 22 | await execa('node', ['ace', 'generate:manifest'], { 23 | cwd: absPath, 24 | ...(debug ? { stdio: 'inherit' } : {}), 25 | }) 26 | } catch {} 27 | } 28 | 29 | export default task 30 | -------------------------------------------------------------------------------- /tasks/InstallDependencies/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import { TaskFn } from '../../src/Contracts' 11 | import { getInstallMessage } from '../../src/Helpers' 12 | import { packages } from '../../src/schematics/packages' 13 | 14 | /** 15 | * Creates the `package.json` file in the project root and installs 16 | * required dependencies 17 | */ 18 | const task: TaskFn = async (_, logger, { pkg, client, boilerplate, debug }) => { 19 | /** 20 | * Set the wanted client 21 | */ 22 | if (client !== 'npm') { 23 | pkg.useClient(client) 24 | } 25 | 26 | /** 27 | * Install adonisjs packages for the selected boilerplate 28 | */ 29 | const boilerPlatePackages = packages[boilerplate] 30 | Object.keys(boilerPlatePackages).forEach((pkgName) => { 31 | pkg.install(pkgName, boilerPlatePackages[pkgName].version, false) 32 | }) 33 | 34 | /** 35 | * Required dependencies for all projects 36 | */ 37 | pkg.install('proxy-addr', 'latest', false) 38 | pkg.install('reflect-metadata', 'latest', false) 39 | pkg.install('source-map-support', 'latest', false) 40 | 41 | /** 42 | * Required dev dependencies 43 | */ 44 | pkg.install('typescript', '~4.6') 45 | pkg.install('youch') 46 | pkg.install('youch-terminal') 47 | pkg.install('pino-pretty') 48 | pkg.install('adonis-preset-ts') 49 | pkg.install('@adonisjs/assembler@5.9.6') 50 | pkg.install('@types/source-map-support') 51 | pkg.install('@types/proxy-addr') 52 | 53 | /** 54 | * Displaying a spinner, since install packages takes 55 | * a while 56 | */ 57 | let spinner: ReturnType | undefined 58 | 59 | /** 60 | * Start spinner when not in debug mode 61 | */ 62 | if (!debug) { 63 | pkg.beforeInstall((list, dev) => { 64 | /** 65 | * The callback is invoked twice. First for dev dependencies 66 | * and then for prod depdencies and hence we should stop 67 | * the old spinner before starting a new one 68 | */ 69 | if (spinner) { 70 | spinner.stop() 71 | } 72 | 73 | spinner = logger.await(getInstallMessage(list), undefined, dev ? 'dev' : 'prod') 74 | }) 75 | } 76 | 77 | /** 78 | * Commit mutations 79 | */ 80 | const response = debug ? pkg.commit() : await pkg.commitAsync() 81 | spinner && spinner.stop() 82 | 83 | if (response && response.status === 1) { 84 | const errorMessage = 85 | client === 'yarn' 86 | ? 'yarn install failed' 87 | : client === 'pnpm' 88 | ? 'pnpm install failed' 89 | : 'npm install failed' 90 | const error = new Error(errorMessage) 91 | error['stack'] = response.stderr.toString() 92 | throw error 93 | } else { 94 | logger.action('create').succeeded('package.json') 95 | } 96 | } 97 | 98 | export default task 99 | -------------------------------------------------------------------------------- /tasks/Scaffold/copyTemplates.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import { join } from 'path' 11 | import { utils, files } from '@adonisjs/sink' 12 | import { fsReadAll } from '@poppinss/utils/build/helpers' 13 | 14 | import { TaskFn } from '../../src/Contracts' 15 | 16 | /** 17 | * Copy boilerplate files to the destination 18 | */ 19 | const task: TaskFn = (_, logger, state) => { 20 | const baseDir = join(__dirname, '..', '..', 'templates', state.boilerplate) 21 | const templateFiles = fsReadAll(baseDir, () => true) 22 | 23 | templateFiles.forEach((name: string) => { 24 | if (name.endsWith('.ico')) { 25 | utils.copyFiles(baseDir, state.absPath, [name]).forEach((file) => { 26 | const action = logger.action('create') 27 | file.state === 'copied' ? action.succeeded(file.filePath) : action.skipped(file.filePath) 28 | }) 29 | return 30 | } 31 | 32 | const outputFileName = name.replace(/\.txt$/, '.ts') 33 | const src = join(baseDir, name) 34 | new files.MustacheFile(state.absPath, outputFileName, src).apply(state).commit() 35 | logger.action('create').succeeded(outputFileName) 36 | }) 37 | } 38 | 39 | export default task 40 | -------------------------------------------------------------------------------- /tasks/Scaffold/createEditorConfig.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import { files } from '@adonisjs/sink' 11 | import { TaskFn } from '../../src/Contracts' 12 | 13 | /** 14 | * Create `.editorconfig` inside destination 15 | */ 16 | const task: TaskFn = (_, logger, { absPath }) => { 17 | const editorConfig = new files.IniFile(absPath, '.editorconfig') 18 | 19 | editorConfig.set('_global', { 20 | root: true, 21 | }) 22 | 23 | /** 24 | * All files 25 | */ 26 | editorConfig.set('*', { 27 | indent_style: 'space', 28 | indent_size: 2, 29 | end_of_line: 'lf', 30 | charset: 'utf-8', 31 | trim_trailing_whitespace: true, 32 | insert_final_newline: true, 33 | }) 34 | 35 | /** 36 | * JSON file 37 | */ 38 | editorConfig.set('*.json', { 39 | insert_final_newline: false, 40 | }) 41 | 42 | /** 43 | * Markdown files 44 | */ 45 | editorConfig.set('*.md', { 46 | trim_trailing_whitespace: false, 47 | }) 48 | 49 | editorConfig.commit() 50 | logger.action('create').succeeded('.editorconfig') 51 | } 52 | 53 | export default task 54 | -------------------------------------------------------------------------------- /tasks/Scaffold/createGitIgnore.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import { files } from '@adonisjs/sink' 11 | import { TaskFn } from '../../src/Contracts' 12 | 13 | /** 14 | * Creates `.gitignore` file inside destination 15 | */ 16 | const task: TaskFn = (_, logger, { absPath }) => { 17 | const gitignore = new files.NewLineFile(absPath, '.gitignore') 18 | 19 | gitignore.add('node_modules') 20 | gitignore.add('build') 21 | gitignore.add('coverage') 22 | gitignore.add('.vscode') 23 | gitignore.add('.DS_STORE') 24 | gitignore.add('.env') 25 | gitignore.add('tmp') 26 | gitignore.add('npm-debug.log*') 27 | gitignore.add('yarn-debug.log*') 28 | gitignore.add('yarn-error.log*') 29 | gitignore.add('lerna-debug.log*') 30 | gitignore.add('.pnpm-debug.log*') 31 | gitignore.add('logs') 32 | gitignore.add('*.log') 33 | gitignore.add('.yarn/cache') 34 | gitignore.add('.yarn/unplugged') 35 | gitignore.add('.yarn/build-state.yml') 36 | gitignore.add('.yarn/install-state.gz') 37 | gitignore.add('.pnp.*') 38 | gitignore.add('.yarn-integrity') 39 | 40 | gitignore.commit() 41 | logger.action('create').succeeded('.gitignore') 42 | } 43 | 44 | export default task 45 | -------------------------------------------------------------------------------- /tasks/Scaffold/createRcFile.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import { files } from '@adonisjs/sink' 11 | import { TaskFn } from '../../src/Contracts' 12 | 13 | /** 14 | * Creates the `.adonisrc.json` inside destination 15 | */ 16 | const task: TaskFn = (_, logger, { absPath }) => { 17 | const rcFile = new files.AdonisRcFile(absPath) 18 | 19 | /** 20 | * Yes, it is a typescript project 21 | */ 22 | rcFile.set('typescript', true) 23 | 24 | /** 25 | * Application level commands 26 | */ 27 | rcFile.addCommand('./commands') 28 | 29 | /** 30 | * The exception handler to handle HTTP exceptions 31 | */ 32 | rcFile.setExceptionHandler('App/Exceptions/Handler') 33 | 34 | /** 35 | * Aliases the app will use 36 | */ 37 | rcFile.setAlias('App', 'app') 38 | rcFile.setAlias('Config', 'config') 39 | rcFile.setAlias('Database', 'database') 40 | rcFile.setAlias('Contracts', 'contracts') 41 | 42 | /** 43 | * Files to preload 44 | */ 45 | rcFile.setPreload('./start/routes') 46 | rcFile.setPreload('./start/kernel') 47 | 48 | /** 49 | * Application level provider 50 | */ 51 | rcFile.addProvider('./providers/AppProvider') 52 | 53 | /** 54 | * Create .adonisrc.json file 55 | */ 56 | rcFile.commit() 57 | logger.action('create').succeeded('.adonisrc.json') 58 | } 59 | 60 | export default task 61 | -------------------------------------------------------------------------------- /tasks/Scaffold/createTsConfig.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import { files } from '@adonisjs/sink' 11 | import { TaskFn } from '../../src/Contracts' 12 | 13 | /** 14 | * Creates `tsconfig.json` file inside destination 15 | */ 16 | const task: TaskFn = (_, logger, { absPath }) => { 17 | const tsconfig = new files.JsonFile(absPath, 'tsconfig.json') 18 | 19 | /** 20 | * Use a base config file 21 | */ 22 | tsconfig.set('extends', 'adonis-preset-ts/tsconfig.json') 23 | 24 | /** 25 | * Include everything 26 | */ 27 | tsconfig.set('include', ['**/*']) 28 | 29 | /** 30 | * Except "node_modules" and the "build" folder 31 | */ 32 | tsconfig.set('exclude', ['node_modules', 'build']) 33 | 34 | /** 35 | * Define compiler options 36 | */ 37 | tsconfig.set('compilerOptions', { 38 | outDir: 'build', 39 | rootDir: './', 40 | baseUrl: './', 41 | sourceMap: true, 42 | paths: { 43 | 'App/*': ['./app/*'], 44 | 'Config/*': ['./config/*'], 45 | 'Contracts/*': ['./contracts/*'], 46 | 'Database/*': ['./database/*'], 47 | }, 48 | }) 49 | 50 | /** 51 | * Create tsconfig file 52 | */ 53 | tsconfig.commit() 54 | logger.action('create').succeeded('tsconfig.json') 55 | } 56 | 57 | export default task 58 | -------------------------------------------------------------------------------- /tasks/Scaffold/setupEslint.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import { TaskFn } from '../../src/Contracts' 11 | 12 | /** 13 | * Setup eslint inside the project 14 | */ 15 | const task: TaskFn = (_, __, { prettier, eslint, pkg }) => { 16 | if (!eslint) { 17 | return 18 | } 19 | 20 | /** 21 | * Setup config for prettier 22 | */ 23 | if (prettier) { 24 | pkg.set('eslintConfig.extends', ['plugin:adonis/typescriptApp', 'prettier']) 25 | pkg.set('eslintConfig.plugins', ['prettier']) 26 | pkg.set('eslintConfig.rules', { 27 | 'prettier/prettier': ['error'], 28 | }) 29 | pkg.set('eslintIgnore', ['build']) 30 | } else { 31 | // or setup without prettier 32 | pkg.set('eslintConfig.extends', ['plugin:adonis/typescriptApp']) 33 | pkg.set('eslintIgnore', ['build']) 34 | } 35 | 36 | /** 37 | * Install packages and configure lint script 38 | */ 39 | pkg.install('eslint') 40 | pkg.install('eslint-plugin-adonis') 41 | pkg.setScript('lint', 'eslint . --ext=.ts') 42 | } 43 | 44 | export default task 45 | -------------------------------------------------------------------------------- /tasks/Scaffold/setupPrettier.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import { files } from '@adonisjs/sink' 11 | import { TaskFn } from '../../src/Contracts' 12 | 13 | /** 14 | * Setup prettier inside the project 15 | */ 16 | const task: TaskFn = (_, logger, { absPath, prettier, eslint, pkg }) => { 17 | if (!eslint || !prettier) { 18 | return 19 | } 20 | 21 | /** 22 | * Create prettierrc file 23 | */ 24 | pkg.set('prettier.trailingComma', 'es5') 25 | pkg.set('prettier.semi', false) 26 | pkg.set('prettier.singleQuote', true) 27 | pkg.set('prettier.useTabs', false) 28 | pkg.set('prettier.quoteProps', 'consistent') 29 | pkg.set('prettier.bracketSpacing', true) 30 | pkg.set('prettier.arrowParens', 'always') 31 | pkg.set('prettier.printWidth', 100) 32 | 33 | /** 34 | * Create prettier ignore file 35 | */ 36 | const prettierIgnore = new files.NewLineFile(absPath, '.prettierignore') 37 | prettierIgnore.add('build') 38 | prettierIgnore.commit() 39 | logger.action('create').succeeded('.prettierignore') 40 | 41 | /** 42 | * Install prettier dependencies and register formatting 43 | * script 44 | */ 45 | pkg.install('prettier') 46 | pkg.install('eslint-config-prettier') 47 | pkg.install('eslint-plugin-prettier') 48 | pkg.setScript('format', 'prettier --write .') 49 | } 50 | 51 | export default task 52 | -------------------------------------------------------------------------------- /tasks/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-ts-boilerplate 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 | import formatSource from './FormatSource' 11 | import configureTests from './ConfigureTests' 12 | import setupEslint from './Scaffold/setupEslint' 13 | import generateManifest from './GenerateManifest' 14 | import createRcFile from './Scaffold/createRcFile' 15 | import configurePackages from './ConfigurePackages' 16 | import setupPrettier from './Scaffold/setupPrettier' 17 | import copyTemplates from './Scaffold/copyTemplates' 18 | import createTsConfig from './Scaffold/createTsConfig' 19 | import installDependencies from './InstallDependencies' 20 | import createGitIgnore from './Scaffold/createGitIgnore' 21 | import createEditorConfig from './Scaffold/createEditorConfig' 22 | import configureWebpackEncore from './ConfigureEncore' 23 | import { CliState } from '../src/Contracts' 24 | 25 | /** 26 | * An array of tasks to be executed in chronological order 27 | */ 28 | export const tasks = function ({ encore }: CliState) { 29 | return [ 30 | { 31 | title: 'Scaffold project', 32 | actions: [ 33 | copyTemplates, 34 | createEditorConfig, 35 | createGitIgnore, 36 | createRcFile, 37 | createTsConfig, 38 | setupEslint, 39 | setupPrettier, 40 | ], 41 | }, 42 | { 43 | title: 'Install dependencies', 44 | actions: [installDependencies], 45 | }, 46 | { 47 | title: 'Configure installed packages', 48 | actions: [configurePackages, configureTests, generateManifest, formatSource], 49 | }, 50 | ...(encore 51 | ? [ 52 | { 53 | title: 'Configure webpack encore', 54 | actions: [configureWebpackEncore], 55 | }, 56 | ] 57 | : []), 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /templates/api/ace: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Ace Commands 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is the entry point for running ace commands. 7 | | 8 | */ 9 | 10 | require('reflect-metadata') 11 | require('source-map-support').install({ handleUncaughtExceptions: false }) 12 | 13 | const { Ignitor } = require('@adonisjs/core/build/standalone') 14 | new Ignitor(__dirname) 15 | .ace() 16 | .handle(process.argv.slice(2)) 17 | -------------------------------------------------------------------------------- /templates/api/app/Exceptions/Handler.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Http Exception Handler 4 | |-------------------------------------------------------------------------- 5 | | 6 | | AdonisJs will forward all exceptions occurred during an HTTP request to 7 | | the following class. You can learn more about exception handling by 8 | | reading docs. 9 | | 10 | | The exception handler extends a base `HttpExceptionHandler` which is not 11 | | mandatory, however it can do lot of heavy lifting to handle the errors 12 | | properly. 13 | | 14 | */ 15 | 16 | import Logger from '@ioc:Adonis/Core/Logger' 17 | import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler' 18 | 19 | export default class ExceptionHandler extends HttpExceptionHandler { 20 | constructor () { 21 | super(Logger) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /templates/api/commands/index.txt: -------------------------------------------------------------------------------- 1 | import { listDirectoryFiles } from '@adonisjs/core/build/standalone' 2 | import Application from '@ioc:Adonis/Core/Application' 3 | 4 | /* 5 | |-------------------------------------------------------------------------- 6 | | Exporting an array of commands 7 | |-------------------------------------------------------------------------- 8 | | 9 | | Instead of manually exporting each file from this directory, we use the 10 | | helper `listDirectoryFiles` to recursively collect and export an array 11 | | of filenames. 12 | | 13 | | Couple of things to note: 14 | | 15 | | 1. The file path must be relative from the project root and not this directory. 16 | | 2. We must ignore this file to avoid getting into an infinite loop 17 | | 18 | */ 19 | export default listDirectoryFiles(__dirname, Application.appRoot, ['./commands/index']) 20 | -------------------------------------------------------------------------------- /templates/api/env.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Validating Environment Variables 4 | |-------------------------------------------------------------------------- 5 | | 6 | | In this file we define the rules for validating environment variables. 7 | | By performing validation we ensure that your application is running in 8 | | a stable environment with correct configuration values. 9 | | 10 | | This file is read automatically by the framework during the boot lifecycle 11 | | and hence do not rename or move this file to a different location. 12 | | 13 | */ 14 | 15 | import Env from '@ioc:Adonis/Core/Env' 16 | 17 | export default Env.rules({ 18 | HOST: Env.schema.string({ format: 'host' }), 19 | PORT: Env.schema.number(), 20 | APP_KEY: Env.schema.string(), 21 | APP_NAME: Env.schema.string(), 22 | DRIVE_DISK: Env.schema.enum(['local'] as const), 23 | NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const), 24 | }) 25 | -------------------------------------------------------------------------------- /templates/api/providers/AppProvider.txt: -------------------------------------------------------------------------------- 1 | import type { ApplicationContract } from '@ioc:Adonis/Core/Application' 2 | 3 | export default class AppProvider { 4 | constructor (protected app: ApplicationContract) { 5 | } 6 | 7 | public register () { 8 | // Register your own bindings 9 | } 10 | 11 | public async boot () { 12 | // IoC container is ready 13 | } 14 | 15 | public async ready () { 16 | // App is ready 17 | } 18 | 19 | public async shutdown () { 20 | // Cleanup, since app is going down 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /templates/api/server.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | AdonisJs Server 4 | |-------------------------------------------------------------------------- 5 | | 6 | | The contents in this file is meant to bootstrap the AdonisJs application 7 | | and start the HTTP server to accept incoming connections. You must avoid 8 | | making this file dirty and instead make use of `lifecycle hooks` provided 9 | | by AdonisJs service providers for custom code. 10 | | 11 | */ 12 | 13 | import 'reflect-metadata' 14 | import sourceMapSupport from 'source-map-support' 15 | import { Ignitor } from '@adonisjs/core/build/standalone' 16 | 17 | sourceMapSupport.install({ handleUncaughtExceptions: false }) 18 | 19 | new Ignitor(__dirname) 20 | .httpServer() 21 | .start() 22 | -------------------------------------------------------------------------------- /templates/api/start/kernel.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Application middleware 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is used to define middleware for HTTP requests. You can register 7 | | middleware as a `closure` or an IoC container binding. The bindings are 8 | | preferred, since they keep this file clean. 9 | | 10 | */ 11 | 12 | import Server from '@ioc:Adonis/Core/Server' 13 | 14 | /* 15 | |-------------------------------------------------------------------------- 16 | | Global middleware 17 | |-------------------------------------------------------------------------- 18 | | 19 | | An array of global middleware, that will be executed in the order they 20 | | are defined for every HTTP requests. 21 | | 22 | */ 23 | Server.middleware.register([ 24 | () => import('@ioc:Adonis/Core/BodyParser'), 25 | ]) 26 | 27 | /* 28 | |-------------------------------------------------------------------------- 29 | | Named middleware 30 | |-------------------------------------------------------------------------- 31 | | 32 | | Named middleware are defined as key-value pair. The value is the namespace 33 | | or middleware function and key is the alias. Later you can use these 34 | | alias on individual routes. For example: 35 | | 36 | | { auth: () => import('App/Middleware/Auth') } 37 | | 38 | | and then use it as follows 39 | | 40 | | Route.get('dashboard', 'UserController.dashboard').middleware('auth') 41 | | 42 | */ 43 | Server.middleware.registerNamed({ 44 | }) 45 | -------------------------------------------------------------------------------- /templates/api/start/routes.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Routes 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is dedicated for defining HTTP routes. A single file is enough 7 | | for majority of projects, however you can define routes in different 8 | | files and just make sure to import them inside this file. For example 9 | | 10 | | Define routes in following two files 11 | | ├── start/routes/cart.ts 12 | | ├── start/routes/customer.ts 13 | | 14 | | and then import them inside `start/routes.ts` as follows 15 | | 16 | | import './routes/cart' 17 | | import './routes/customer' 18 | | 19 | */ 20 | 21 | import Route from '@ioc:Adonis/Core/Route' 22 | 23 | Route.get('/', async () => { 24 | return { hello: 'world' } 25 | }) 26 | -------------------------------------------------------------------------------- /templates/slim/ace: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Ace Commands 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is the entry point for running ace commands. 7 | | 8 | */ 9 | 10 | require('reflect-metadata') 11 | require('source-map-support').install({ handleUncaughtExceptions: false }) 12 | 13 | const { Ignitor } = require('@adonisjs/core/build/standalone') 14 | new Ignitor(__dirname) 15 | .ace() 16 | .handle(process.argv.slice(2)) 17 | -------------------------------------------------------------------------------- /templates/slim/app/Exceptions/Handler.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Http Exception Handler 4 | |-------------------------------------------------------------------------- 5 | | 6 | | AdonisJs will forward all exceptions occurred during an HTTP request to 7 | | the following class. You can learn more about exception handling by 8 | | reading docs. 9 | | 10 | | The exception handler extends a base `HttpExceptionHandler` which is not 11 | | mandatory, however it can do lot of heavy lifting to handle the errors 12 | | properly. 13 | | 14 | */ 15 | 16 | import Logger from '@ioc:Adonis/Core/Logger' 17 | import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler' 18 | 19 | export default class ExceptionHandler extends HttpExceptionHandler { 20 | constructor () { 21 | super(Logger) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /templates/slim/commands/index.txt: -------------------------------------------------------------------------------- 1 | import { listDirectoryFiles } from '@adonisjs/core/build/standalone' 2 | import Application from '@ioc:Adonis/Core/Application' 3 | 4 | /* 5 | |-------------------------------------------------------------------------- 6 | | Exporting an array of commands 7 | |-------------------------------------------------------------------------- 8 | | 9 | | Instead of manually exporting each file from this directory, we use the 10 | | helper `listDirectoryFiles` to recursively collect and export an array 11 | | of filenames. 12 | | 13 | | Couple of things to note: 14 | | 15 | | 1. The file path must be relative from the project root and not this directory. 16 | | 2. We must ignore this file to avoid getting into an infinite loop 17 | | 18 | */ 19 | export default listDirectoryFiles(__dirname, Application.appRoot, ['./commands/index']) 20 | -------------------------------------------------------------------------------- /templates/slim/env.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Validating Environment Variables 4 | |-------------------------------------------------------------------------- 5 | | 6 | | In this file we define the rules for validating environment variables. 7 | | By performing validation we ensure that your application is running in 8 | | a stable environment with correct configuration values. 9 | | 10 | | This file is read automatically by the framework during the boot lifecycle 11 | | and hence do not rename or move this file to a different location. 12 | | 13 | */ 14 | 15 | import Env from '@ioc:Adonis/Core/Env' 16 | 17 | export default Env.rules({ 18 | HOST: Env.schema.string({ format: 'host' }), 19 | PORT: Env.schema.number(), 20 | APP_KEY: Env.schema.string(), 21 | APP_NAME: Env.schema.string(), 22 | DRIVE_DISK: Env.schema.enum(['local'] as const), 23 | NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const), 24 | }) 25 | -------------------------------------------------------------------------------- /templates/slim/providers/AppProvider.txt: -------------------------------------------------------------------------------- 1 | import type { ApplicationContract } from '@ioc:Adonis/Core/Application' 2 | 3 | export default class AppProvider { 4 | constructor (protected app: ApplicationContract) { 5 | } 6 | 7 | public register () { 8 | // Register your own bindings 9 | } 10 | 11 | public async boot () { 12 | // IoC container is ready 13 | } 14 | 15 | public async ready () { 16 | // App is ready 17 | } 18 | 19 | public async shutdown () { 20 | // Cleanup, since app is going down 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /templates/slim/server.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | AdonisJs Server 4 | |-------------------------------------------------------------------------- 5 | | 6 | | The contents in this file is meant to bootstrap the AdonisJs application 7 | | and start the HTTP server to accept incoming connections. You must avoid 8 | | making this file dirty and instead make use of `lifecycle hooks` provided 9 | | by AdonisJs service providers for custom code. 10 | | 11 | */ 12 | 13 | import 'reflect-metadata' 14 | import sourceMapSupport from 'source-map-support' 15 | import { Ignitor } from '@adonisjs/core/build/standalone' 16 | 17 | sourceMapSupport.install({ handleUncaughtExceptions: false }) 18 | 19 | new Ignitor(__dirname) 20 | .httpServer() 21 | .start() 22 | -------------------------------------------------------------------------------- /templates/slim/start/kernel.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Application middleware 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is used to define middleware for HTTP requests. You can register 7 | | middleware as a `closure` or an IoC container binding. The bindings are 8 | | preferred, since they keep this file clean. 9 | | 10 | */ 11 | 12 | import Server from '@ioc:Adonis/Core/Server' 13 | 14 | /* 15 | |-------------------------------------------------------------------------- 16 | | Global middleware 17 | |-------------------------------------------------------------------------- 18 | | 19 | | An array of global middleware, that will be executed in the order they 20 | | are defined for every HTTP requests. 21 | | 22 | */ 23 | Server.middleware.register([ 24 | () => import('@ioc:Adonis/Core/BodyParser'), 25 | ]) 26 | 27 | /* 28 | |-------------------------------------------------------------------------- 29 | | Named middleware 30 | |-------------------------------------------------------------------------- 31 | | 32 | | Named middleware are defined as key-value pair. The value is the namespace 33 | | or middleware function and key is the alias. Later you can use these 34 | | alias on individual routes. For example: 35 | | 36 | | { auth: () => import('App/Middleware/Auth') } 37 | | 38 | | and then use it as follows 39 | | 40 | | Route.get('dashboard', 'UserController.dashboard').middleware('auth') 41 | | 42 | */ 43 | Server.middleware.registerNamed({ 44 | }) 45 | -------------------------------------------------------------------------------- /templates/slim/start/routes.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Routes 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is dedicated for defining HTTP routes. A single file is enough 7 | | for majority of projects, however you can define routes in different 8 | | files and just make sure to import them inside this file. For example 9 | | 10 | | Define routes in following two files 11 | | ├── start/routes/cart.ts 12 | | ├── start/routes/customer.ts 13 | | 14 | | and then import them inside `start/routes.ts` as follows 15 | | 16 | | import './routes/cart' 17 | | import './routes/customer' 18 | | 19 | */ 20 | 21 | import Route from '@ioc:Adonis/Core/Route' 22 | 23 | Route.get('/', async () => { 24 | return 'Hello world from a slim app' 25 | }) 26 | -------------------------------------------------------------------------------- /templates/stubs/css/app.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap'); 2 | 3 | html, body { 4 | background-color: #F7F8FA; 5 | font-family: 'Poppins', sans-serif; 6 | height: 100vh; 7 | color: #46444c; 8 | position: relative; 9 | } 10 | 11 | body:before { 12 | content: ''; 13 | background: #5A45FF; 14 | top: 0; 15 | left: 0; 16 | right: 0; 17 | height: 6px; 18 | position: absolute; 19 | } 20 | 21 | * { 22 | margin: 0; 23 | padding: 0; 24 | } 25 | 26 | a { 27 | color: #5A45FF; 28 | text-decoration: none; 29 | } 30 | 31 | main { 32 | max-width: 620px; 33 | margin: auto; 34 | height: 100vh; 35 | padding: 0 30px; 36 | align-items: center; 37 | display: flex; 38 | justify-content: center; 39 | } 40 | 41 | .title { 42 | font-size: 50px; 43 | line-height: 50px; 44 | margin-bottom: 10px; 45 | color: #17161A; 46 | } 47 | 48 | .subtitle { 49 | font-size: 26px; 50 | margin-bottom: 40px; 51 | } 52 | 53 | p { 54 | margin-bottom: 20px; 55 | } 56 | 57 | main ul { 58 | list-style: none; 59 | } 60 | 61 | main li { 62 | margin-bottom: 5px; 63 | position: relative; 64 | padding-left: 25px; 65 | } 66 | 67 | main li:before { 68 | content: '—'; 69 | position: absolute; 70 | left: 0; 71 | } 72 | 73 | main code { 74 | font-size: 16px; 75 | background: #e6e2ff; 76 | } 77 | -------------------------------------------------------------------------------- /templates/stubs/js/app.js: -------------------------------------------------------------------------------- 1 | import '../css/app.css' 2 | -------------------------------------------------------------------------------- /templates/web/ace: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Ace Commands 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is the entry point for running ace commands. 7 | | 8 | */ 9 | 10 | require('reflect-metadata') 11 | require('source-map-support').install({ handleUncaughtExceptions: false }) 12 | 13 | const { Ignitor } = require('@adonisjs/core/build/standalone') 14 | new Ignitor(__dirname) 15 | .ace() 16 | .handle(process.argv.slice(2)) 17 | -------------------------------------------------------------------------------- /templates/web/app/Exceptions/Handler.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Http Exception Handler 4 | |-------------------------------------------------------------------------- 5 | | 6 | | AdonisJs will forward all exceptions occurred during an HTTP request to 7 | | the following class. You can learn more about exception handling by 8 | | reading docs. 9 | | 10 | | The exception handler extends a base `HttpExceptionHandler` which is not 11 | | mandatory, however it can do lot of heavy lifting to handle the errors 12 | | properly. 13 | | 14 | */ 15 | 16 | import Logger from '@ioc:Adonis/Core/Logger' 17 | import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler' 18 | 19 | export default class ExceptionHandler extends HttpExceptionHandler { 20 | protected statusPages = { 21 | '403': 'errors/unauthorized', 22 | '404': 'errors/not-found', 23 | '500..599': 'errors/server-error', 24 | } 25 | 26 | constructor () { 27 | super(Logger) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /templates/web/commands/index.txt: -------------------------------------------------------------------------------- 1 | import { listDirectoryFiles } from '@adonisjs/core/build/standalone' 2 | import Application from '@ioc:Adonis/Core/Application' 3 | 4 | /* 5 | |-------------------------------------------------------------------------- 6 | | Exporting an array of commands 7 | |-------------------------------------------------------------------------- 8 | | 9 | | Instead of manually exporting each file from this directory, we use the 10 | | helper `listDirectoryFiles` to recursively collect and export an array 11 | | of filenames. 12 | | 13 | | Couple of things to note: 14 | | 15 | | 1. The file path must be relative from the project root and not this directory. 16 | | 2. We must ignore this file to avoid getting into an infinite loop 17 | | 18 | */ 19 | export default listDirectoryFiles(__dirname, Application.appRoot, ['./commands/index']) 20 | -------------------------------------------------------------------------------- /templates/web/env.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Validating Environment Variables 4 | |-------------------------------------------------------------------------- 5 | | 6 | | In this file we define the rules for validating environment variables. 7 | | By performing validation we ensure that your application is running in 8 | | a stable environment with correct configuration values. 9 | | 10 | | This file is read automatically by the framework during the boot lifecycle 11 | | and hence do not rename or move this file to a different location. 12 | | 13 | */ 14 | 15 | import Env from '@ioc:Adonis/Core/Env' 16 | 17 | export default Env.rules({ 18 | HOST: Env.schema.string({ format: 'host' }), 19 | PORT: Env.schema.number(), 20 | APP_KEY: Env.schema.string(), 21 | APP_NAME: Env.schema.string(), 22 | CACHE_VIEWS: Env.schema.boolean(), 23 | SESSION_DRIVER: Env.schema.string(), 24 | DRIVE_DISK: Env.schema.enum(['local'] as const), 25 | NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const), 26 | }) 27 | -------------------------------------------------------------------------------- /templates/web/providers/AppProvider.txt: -------------------------------------------------------------------------------- 1 | import type { ApplicationContract } from '@ioc:Adonis/Core/Application' 2 | 3 | export default class AppProvider { 4 | constructor (protected app: ApplicationContract) { 5 | } 6 | 7 | public register () { 8 | // Register your own bindings 9 | } 10 | 11 | public async boot () { 12 | // IoC container is ready 13 | } 14 | 15 | public async ready () { 16 | // App is ready 17 | } 18 | 19 | public async shutdown () { 20 | // Cleanup, since app is going down 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /templates/web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adonisjs-community/create-adonis-ts-app/0d6a1d6d4149d647fe04ccc1b8a7939a2fdb464e/templates/web/public/favicon.ico -------------------------------------------------------------------------------- /templates/web/resources/views/errors/not-found.edge: -------------------------------------------------------------------------------- 1 |

It's a 404

2 | -------------------------------------------------------------------------------- /templates/web/resources/views/errors/server-error.edge: -------------------------------------------------------------------------------- 1 |

It's a 500

2 | -------------------------------------------------------------------------------- /templates/web/resources/views/errors/unauthorized.edge: -------------------------------------------------------------------------------- 1 |

It's a 403

2 | -------------------------------------------------------------------------------- /templates/web/resources/views/welcome.edge: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AdonisJS - A fully featured web framework for Node.js 7 | {{#encore}} 8 | @entryPointStyles('app') 9 | @entryPointScripts('app') 10 | {{/encore}} 11 | {{^encore}} 12 | 13 | 89 | {{/encore}} 90 | 91 | 92 | 93 |
94 |
95 |

It Works!

96 |

97 | Congratulations, you have just created your first AdonisJS app. 98 |

99 | 100 |
    101 |
  • 102 | The route for this page is defined inside start/routes.ts file 103 |
  • 104 | 105 |
  • 106 | You can update this page by editing resources/views/welcome.edge file 107 |
  • 108 | 109 |
  • 110 | If you run into problems, you can reach us on Discord or the Github. 111 |
  • 112 |
113 |
114 |
115 | 116 | 117 | -------------------------------------------------------------------------------- /templates/web/server.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | AdonisJs Server 4 | |-------------------------------------------------------------------------- 5 | | 6 | | The contents in this file is meant to bootstrap the AdonisJs application 7 | | and start the HTTP server to accept incoming connections. You must avoid 8 | | making this file dirty and instead make use of `lifecycle hooks` provided 9 | | by AdonisJs service providers for custom code. 10 | | 11 | */ 12 | 13 | import 'reflect-metadata' 14 | import sourceMapSupport from 'source-map-support' 15 | import { Ignitor } from '@adonisjs/core/build/standalone' 16 | 17 | sourceMapSupport.install({ handleUncaughtExceptions: false }) 18 | 19 | new Ignitor(__dirname) 20 | .httpServer() 21 | .start() 22 | -------------------------------------------------------------------------------- /templates/web/start/kernel.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Application middleware 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is used to define middleware for HTTP requests. You can register 7 | | middleware as a `closure` or an IoC container binding. The bindings are 8 | | preferred, since they keep this file clean. 9 | | 10 | */ 11 | 12 | import Server from '@ioc:Adonis/Core/Server' 13 | 14 | /* 15 | |-------------------------------------------------------------------------- 16 | | Global middleware 17 | |-------------------------------------------------------------------------- 18 | | 19 | | An array of global middleware, that will be executed in the order they 20 | | are defined for every HTTP requests. 21 | | 22 | */ 23 | Server.middleware.register([ 24 | () => import('@ioc:Adonis/Core/BodyParser'), 25 | ]) 26 | 27 | /* 28 | |-------------------------------------------------------------------------- 29 | | Named middleware 30 | |-------------------------------------------------------------------------- 31 | | 32 | | Named middleware are defined as key-value pair. The value is the namespace 33 | | or middleware function and key is the alias. Later you can use these 34 | | alias on individual routes. For example: 35 | | 36 | | { auth: () => import('App/Middleware/Auth') } 37 | | 38 | | and then use it as follows 39 | | 40 | | Route.get('dashboard', 'UserController.dashboard').middleware('auth') 41 | | 42 | */ 43 | Server.middleware.registerNamed({ 44 | }) 45 | -------------------------------------------------------------------------------- /templates/web/start/routes.txt: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Routes 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is dedicated for defining HTTP routes. A single file is enough 7 | | for majority of projects, however you can define routes in different 8 | | files and just make sure to import them inside this file. For example 9 | | 10 | | Define routes in following two files 11 | | ├── start/routes/cart.ts 12 | | ├── start/routes/customer.ts 13 | | 14 | | and then import them inside `start/routes.ts` as follows 15 | | 16 | | import './routes/cart' 17 | | import './routes/customer'' 18 | | 19 | */ 20 | 21 | import Route from '@ioc:Adonis/Core/Route' 22 | 23 | Route.get('/', async ({ view }) => { 24 | return view.render('welcome') 25 | }) 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@adonisjs/mrm-preset/_tsconfig", 3 | "compilerOptions": { 4 | "skipLibCheck": true 5 | }, 6 | "files": ["./node_modules/@adonisjs/application/build/adonis-typings/index.d.ts"] 7 | } 8 | --------------------------------------------------------------------------------