# Waspc This directory contains source code of the `wasp` CLI/compiler (aka `waspc`), and this README is aimed at the contributors to the project. If you are a Wasp user and not a contributor (yet 😉), you might want to look into the following resources instead ([**Project page**](https://wasp.sh), [**Docs**](https://wasp.sh/docs)). ## First time contributor checklist If you would like to make your first contribution, here is a handy checklist we made for you: - [ ] Read [Quick overview](#quick-overview). - [ ] Compile the project successfully and get `kitchen-sink` example running (follow [Basics](#basics)). - [ ] Join [Discord](https://discord.gg/rzdnErX) and say hi :)! - [ ] Pick an issue [labeled with "good first issue"](https://github.com/wasp-lang/wasp/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) and let us know you would like to work on it - ideally immediately propose a plan of action and ask questions. If you can't find a suitable issue for you, reach out to us on Discord and we can try to find something for you together. - [ ] Make a PR targeting `main` and have it accepted! Check [Typical workflow](#typical-development-workflow) and [Branching and merging strategy](#branching-and-merging-strategy) for guidance, and consult [Codebase overview](#codebase-overview) for more details on how Wasp compiler works internally. ## Quick overview The core of `waspc` is implemented in Haskell, but you will also see a lot of Javascript/TypeScript and other web technologies which apps generated with Wasp use. You don't have to be an expert in Haskell to contribute or understand the code since we don't use complicated Haskell features much. Most of the code is relatively simple and straight-forward, and we are happy to help with anything you get stuck with. The main result of building the project is `wasp` executable (also referred to as CLI), which is at the same time Wasp compiler, CLI, and Wasp project runner in one - one main tool for everything Wasp-related. Note that while `waspc` is the name of this Haskell project, the executable's name is `wasp` when released, and `wasp-cli` during development. ## Basics ### Repo Clone this repo (or its fork) to your machine. Position yourself in this directory (`waspc/`) and make sure that you are on the `main` branch. ### `run` script [`./run`](run) script captures the most common commands/workflows for the development of `waspc` (similar to the role that `scripts` in `package.json` play in `npm` projects), e.g. `./run build`, `./run test`, ... . It serves both as a convenient way to easily run common development tasks and also as a sort of documentation on how we develop `waspc`. You will see us mentioning it often in the rest of this README. Running `./run` without any arguments will print help/usage, which is a good way to discover the typical `waspc` development workflows. > [!TIP] > To make it easy to run the `./run` script from any place in your waspc codebase, you can create a bash alias that points to it, e.g.: > > ```sh > alias wrun="/home/martin/git/wasp-lang/wasp/waspc/run" > ``` > [!IMPORTANT] > The `./run` script and the rest of the development tooling are Bash scripts, so they won't work from PowerShell or Command Prompt in Windows. ### Dev tooling Follow repo-wide [Dev tooling](../CONTRIBUTING.md#dev-tooling) instructions. ### Build ```sh ./run build ``` to build the whole `waspc` project. This might take a while (e.g. 10 mins) if you are doing it for the very first time, due to having to download all the dependencies (which will later be cached). If that is the case, relax and feel free to get yourself a cup of coffee! When somebody asks what you are doing, you can finally rightfully say "compiling!" 😀. ### Run tests ```sh ./run test ``` to ensure all the tests are passing. #### Playwright on unsupported Linux distros (e.g. Arch) If `./run test` fails for you when installing Playwright browsers and their system deps, check [Playwright tests on unsupported Linux distributions (e.g. Arch)](#playwright-tests-on-unsupported-linux-distributions-eg-arch) below. ### Run the `wasp` CLI ```sh ./run wasp-cli ``` to run the `wasp-cli` executable (that you previously built with `./run build`)! Since you provided no arguments, you should see help/usage. Note that the executable during development is named `wasp-cli`, unlike `wasp` which is how it is named when you install a public release of Wasp via official installation method. This is to make it easier to differentiate between the development version of wasp CLI and the released version. ### Running the `kitchen-sink` example First, position yourself in the [`examples/kitchen-sink/`](../examples/kitchen-sink/) dir. Then, run the dev database: ```sh ./run wasp-cli db start ``` Leave it running, open a new terminal (tab), and run ```sh ./run wasp-cli db migrate-dev ``` to update the database schema. Run ```sh cp .env.server.example .env.server ``` to set up some mock env vars for the server, just to get the things running. Finally, run ```sh ./run wasp-cli start ``` to run the example app in the development mode. If you are doing this for the very first time, it might take a minute or so to download and install npm dependencies. When done, new tab in your browser should open and you will see the Kitchen Sink App! > [!NOTE] > You will notice that some functionality in the `kitchen-sink` is not working. That is because the env vars in `.env.server` files are just mock values. Check `kitchen-sink`'s README for more details on how to set up env vars for development. ## Typical development workflow 1. Create a new feature branch from `main`. 2. If you don't have a good/reliable working HLS (Haskell Language Server) connected to your IDE (which we strongly recommend), you will want to instead run `./run ghcid` from the root of the `waspc` project: this will run a process that watches the Haskell project and reports any Haskell compiler errors. Leave it running. - NOTE: You will need to install `ghcid` globally first. You can do it with `cabal install ghcid`. 3. Do a change in the codebase (most often in `src/` or `cli/src/` or `data/`), and update tests if that makes sense (see [Test](#tests)). Fix any errors shown by HLS/`ghcid`. Rinse and repeat. If you're an internal team member, postpone updating waspc e2e tests tests until approval (see [here](#note-for-team-members)). 4. Use `./run build:hs` to build the Haskell/cabal project, and `./run wasp-cli` to both build and run it. If you changed code in `data/packages/`, you will also need to run `./run build:packages` (check [TypeScript Packages section](#typescript-packages) for more details). Alternatively, you can also run slower `./run build` to at the same time build Haskell, TS packages, and any other piece of the project in one command. 5. For easier manual testing of the changes you did on a Wasp app, you have the [`kitchen-sink`](../examples/kitchen-sink/) app, which we always keep updated. Also, if you added a new feature, add it to this app (+ tests) if needed. Check its README for more details (including how to run it). 6. Run `./run test` to confirm that all the tests are passing. If needed, accept changes in the waspc e2e tests with `./run test:waspc:e2e:accept-all`. Check "Tests" for more info. 7. If you did a bug fix, added new feature or did a breaking change, add short info about it to `Changelog.md`. Also, bump version in `waspc.cabal` and `ChangeLog.md` if needed. If you are not sure how to decide which version to go with, check out [how we determine the next version](#determining-next-version). 8. Create a PR. Keep an eye on CI tests -> Everything must pass. If it doesn't, look into it. 9. If your PR changes how users(Waspers) use Wasp, make sure to also update the documentation, which is in this same repo, but under `/web/docs`. 10. Work with reviewer(s) to get the PR approved, keep committing until the PR is approved. 11. Reviewer will merge the branch into `main`. Yay! ### Note for team members Do not update waspc e2e tests until your PR is approved. Accepting waspc e2e tests prematurely: - Slows down the UI. - Creates noise for the reviewers. - Makes it less likely that you'll thoroughly check the final diffs after all review iterations. **Carefully review waspc e2e tests diffs before accepting them** (see [Waspc e2e tests](#waspc-e2e-tests) for more details). ## Design docs (aka RFCs) If the feature you are implementing is complex, be it due to its design or technical implementation, we recommend creating a [design doc](https://www.industrialempathy.com/posts/design-docs-at-google/) (aka RFC). It is a great way to share the idea you have with others while also getting help and feedback. To create one, make a PR that adds a markdown document under `wasp/docs/design-docs`, and in that markdown document explain the thinking behind and choices made when deciding how to implement a feature. Others will comment on your design doc, and once it has gone through needed iterations and is approved, you can start with the implementation of the feature (in a separate PR). ## Codebase overview Wasp is implemented in Haskell. Codebase is split into library (`src/`) and CLI (which itself has a library `cli/src/` and thin executable wrapper `cli/exe/`). CLI is actually `wasp` executable, and it uses the library, where most of the logic is. Wasp compiler takes .wasp files + everything in the `src/` dir (JS, HTML, ...) and generates a web app that consists of a client, server, and database. Wasp compiler code is split into 2 basic layers: Analyzer (frontend) and Generator (backend). Wasp file(s) are analyzed by Analyzer, where they are first parsed, then typechecked, and then evaluated into a central IR (Intermediate Representation), which is `AppSpec` (`src/Wasp/AppSpec.hs`). Check `src/Wasp/Analyzer.hs` for more details. AppSpec is passed to the Generator, which based on it decides how to generate a web app. Output of Generator is a list of FileDrafts, where each FileDraft explains how to create a file on the disk. Therefore, Generator doesn't generate anything itself, instead it provides instructions (FileDrafts) on how to generate the web app. FileDrafts are using mustache templates a lot (they can be found in `data/Generator/templates`). Alongside mustache templates, generated apps use internal npm packages (WaspLibs) that contain core logic and are unit tested. WaspLibs are bundled with Wasp and installed into generated apps (see [WaspLibs](#wasplibs) for more details). Generator is split into three generators, for the three main parts of the web app: WebAppGenerator, ServerGenerator and DbGenerator. After Generator provides us with FileDrafts, web app is generated by writing the FileDrafts to the disk. ![Waspc implementation diagram](images/waspc-implementation-diagram.png) Generated web app consists of a client, server and database. Client is written with React and TanStack Query (`@tanstack/react-query`). Server is written in NodeJS and uses ExpressJs. Database is abstracted via Prisma. We can run Wasp project with `wasp start`. This will first compile the app, generate JS code in the `.wasp/out/` dir, and then run `npm start` for the client, `npm start` for the server, and also run the database. On any changes you do to the source code of Wasp, Wasp project gets recompiled, and then changes in the generated app are picked up by the `npm start` of the client/server, therefore updating the web app. ## Important directories (in waspc/) - `src/` -> main source code, library - `cli/src/` -> rest of the source code, cli, uses library - `cli/exe/` -> thin executable wrapper around cli library code - `tests/`, `e2e-tests/`, `cli/tests/`, `starters-e2e-tests` -> tests - `data/Generator/templates/` -> mustache templates for the generated client/server. - `data/Generator/libs/` -> internal npm packages (WaspLibs) that are bundled with Wasp and copied into generated apps (see [WaspLibs](#wasplibs) for more details) - `data/packages/` -> TypeScript packages used by Wasp compiler (see [TypeScript Packages](#typescript-packages) for more details) - `data/Cli/starters/` -> starter templates for new projects ### Typescript packages `waspc`, while implemented in Haskell, relies on TypeScript for some of its functionality (e.g. for parsing TS code, or for deployment scripts). In these cases, the Haskell code runs these TS packages as separate processes and communicates through input/output streams. These packages are located in `data/packages/` and are normal npm projects. See `data/packages/README.md` for how the projects are expected to be set up. In order for `waspc`'s Haskell code to correctly use these TS packages (and to also have them correctly bundled when generating the release tarball), they need to be correctly installed/built in the `waspc_datadir` dir. To do so in development, run `./run build:packages` when any changes are made to these packages. We also run it in CI when building the release. ### WaspLibs WaspLibs are internal npm packages located under [`data/Generator/libs/`](data/Generator/libs/) and are bundled with Wasp and installed into generated apps. A more detailed description of WaspLibs can be found in the [`data/Generator/libs/README.md`](data/Generator/libs/README.md). ## Tests For tests in Haskell we are using [**Tasty**](https://github.com/UnkindPartition/tasty) testing framework. Tasty lets us combine different types of tests into a single test suite. In Tasty, there is a main test file that is run when test suite is run. In that file we need to manually compose test tree out of tests that we wrote. We organize tests in test groups, which are then recursively grouped resulting in a test tree. Cool thing is that we can organize tests this way however we want and also mix different type of tests (hspec, quickcheck, and whatever else we want). Tests are normally split in files of course, so we need to import those all the way up to the main test file, however we organize our test groups/trees. In order to avoid need for manual organization and importing of test files described above, we are using [tasty-discover](https://hackage.haskell.org/package/tasty-discover) which does this for us. It automatically detects files containing tests and organizes them for us into a test tree (and also takes care of importing). This means we only need to create a file, write tests in it and that is it. Test functions however do need to be prefixed with special prefix to indicate which type of test are they: spec* for Hspec, prop* for QuickCheck and similar. Check docs for more details. We can however still organize tests manually if we want in Tasty test trees, and then we just prefix them with test\_ and tasty-discover will pick them up from there. Additionally, currently we limited tasty-discover to auto-detect only files ending with Test.hs (\*Test.hs glob). We might remove that requirement in the future if it proves to have no benefit. To summarize: If you are writing new tests, just put them in a file that ends with `Test.hs` in `tests/` dir and that is it. For unit testing, we use **Hspec**. For property testing, we use **Quickcheck**. We additionally use **doctest** for testing code examples in documentation. All tests go into `tests/` directory. Haskell build tools don't have a good support for mixing them with source files. To run tests: - To run all tests, you can do `./run test` - To run `waspc` tests only, you can do `./run test:waspc`. - To run `waspc` unit tests only, you can do `./run test:waspc:unit`. - To run individual unit test, you can do `./run test:waspc:unit "Some test description to match"`. - To run `waspc` e2e tests only, you can do `./run test:waspc:e2e`. - To run Wasp CLI tests only, you can do `./run test:cli`. - To run `kitchen-sink` e2e tests, you can do `./run test:kitchen-sink`. - To run examples e2e tests, you can do `./run test:examples`. - To run starter templates e2e tests, you can do `./run test:starters`. ### Waspc e2e tests Inside of `waspc` e2e tests we have snapshot tests that run the `wasp-cli` on a couple of prepared projects, check that they successfully run, and also compare generated app with the expected generated app (golden output). This means that when you make a change in your code that modifies the generated app, snapshot tests will fail while showing a diff between the new generated app and the previous (golden) one. This gives you an opportunity to observe these differences and ensure that they are intentional and that you are satisfied with them. **It is the PR author's (or the reviewers for outside contributions) responsibility to carefully review these diffs.** Do not blindly accept changes, ensure they align with your intended modifications. If you notice something unexpected or weird, you have an opportunity to fix it. Once you are indeed happy with the changes in the generated app, you will want to update the golden output to the new (current) output, so that tests pass. Basically, you want to say "I am ok with the changes and I accept them as the new state of things.". Easiest way to do this is to use the convenient command from the `./run` script: ```sh ./run test:waspc:e2e:accept-all ``` ### Playwright tests on unsupported Linux distributions (e.g. Arch) Some of the test suites (examples, starters) test Wasp apps via Playwright. These test suites do `playwright install --with-deps`, which installs the exact browsers Playwright expects, and then also the system libraries these browsers need (that is the `--with-deps` part). Automatic installation of the system libraries is however supported only on apt-based distros (Debian, Ubuntu), so on other distros (e.g. Arch) it fails with an error message from Playwright. To go around this, we provide `WASP_PLAYWRIGHT_INSTALL_FLAGS` which allows customizing flags passed to `playwright install`. What you will most likely want to do is set this env var to empty, removing the default `--with-deps` so Playwright doesn't try to install deps on its own, and then ensure on your own that correct system deps are installed on your system. In most of the cases, these deps will already be installed on your system and you don't really have to do anything (despite the warning message that Playwright might still print about deps missing, can be silenced with `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=1`). Block of code you can easily just add to your `.bashrc`: ```sh # We set install flags to none so default --with-deps is not set, because # Playwright doesn't know how to install system deps on Arch and errors. # Instead, it is up to us to ensure system deps are installed, which is usually # a no-op since they are usually all already present on the typical system. export WASP_PLAYWRIGHT_INSTALL_FLAGS= # After skipping --with-deps (check above), even when system does have all the # deps, Playwright is not aware and will print a nasty looking warning. This # prevents that. export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=1 ``` ## Code analysis To run the Haskell code analysis, run: ```sh ./run code-check ``` This will check if code is correctly formatted, if it satisfies linter, and if it passes static analysis. These same checks are required to pass the CI, so make sure this is passing before making a PR. TODO: For now we check only the code formatting during the CI. In the future, once we make sure all the warnings are passing, we will also check linter and static analysis during the CI, but that is not happening yet. ### Formatting For formatting Haskell code we use [Ormolu](https://github.com/tweag/ormolu). Normally we set it up in our editors to run on file save. You can also run it manually with ```sh ./run check:ormolu ``` to see if there is any formatting that needs to be fixed, or with ```sh ./run format:ormolu ``` to have Ormolu actually format (in-place) all files that need formatting. NOTE: When you run it for the first time it might take a while (~10 minutes) for all the dependencies to get installed. The subsequent runs will be much faster. ### Linting We use [hlint](https://github.com/ndmitchell/hlint) for linting our Haskell code. You can use ```sh ./run hlint ``` to run the hlint on Wasp codebase. NOTE: When you run it for the first time it might take a while (~10 minutes) for all the dependencies to get installed. The subsequent runs will be much faster. ### Static Analysis We use [stan](https://github.com/kowainik/stan) to statically analyze our codebase. The easiest way to run it is to use ```sh ./run stan ``` This will build the codebase, run stan on it (while installing it first, if needed, with the correct version of GHC) and then write results to the CLI and also generate report in the `stan.html`. NOTE: When you run it for the first time it might take a while (~10 minutes) for all the dependencies to get installed. The subsequent runs will be much faster. ## Branching and merging strategy This repo contains both the source code that makes up a Wasp release (under `waspc`), as well as our website containing documentation and blog posts (under `web`). In order to facilitate the development of Wasp code while still allowing for website updates or hotfixes of the current release, we have decided on the following minimal branching strategy. All Wasp development should be done on feature branches. They form the basis of PRs that will target one of the two following branches: - `main`: this branch contains all the actively developed new features and corresponding documentation updates. Some of these things may not yet be released, but anything merged into `main` should be in a release-ready state. - This is the default branch to target for any Wasp feature branches. - `release`: this branch contains the source code of current/latest Wasp release, as well as the documentation and blog posts currently published and therefore visible on the website. - When doing a full release, which means making a new release based on what we have currently on `main`, we do the following: 1. Update `main` branch by merging `release` into it. There might be conflicts but they shouldn't be too hard to fix. Once `main` is updated, you can create a new waspc release from it, as well as deploy the website from it. 2. Update `release` branch to this new `main` by merging `main` into it. There will be no conflicts since we already resolved all of them in the previous step. How do I know where I want to target my PR, to `release` or `main`? - If you have a change that you want to publish right now or very soon, certainly earlier than waiting till `main` is ready for publishing, then you want to target `release`. This could be website content update, new blog post, documentation (hot)fix, compiler hotfix that we need to release quickly via a new patch version, ... . - If you have a change that is not urgent and can wait until the next "normal" Wasp release is published, then target `main`. These are new features, refactorings, docs accompanying new features, ... . - Stuff published on `release` uses/references version of `wasp` that was last released (so one that is also on `release`). - TLDR; - `release` represents the present, and is for changes to the already published stuff. - `main` represents near future, and is for changes to the to-be-published stuff. > [!IMPORTANT] > If you merge a PR or push any changes to `release`, a new PR will automatically be created to update `main` with the changes from `release`. You will be assigned it, and it's your responsibility to merge it. ## Deployment / CI We use Github Actions for CI. CI runs for any commits on `main` branch, for pull requests, and for any commits tagged with tag that starts with `v`. During CI, we build and test Wasp code on Linux, MacOS and Windows. If commit is tagged with tag starting with `v`, github draft release is created from it containing binary packages, and the Wasp npm packages are uploaded to npm's staging queue (see [Typical Release Process](#typical-release-process) for how they get approved). We also have a workflow for deploying example apps to Fly.io (`release-examples-deploy.yaml`). This workflow can be run manually from the GitHub UI and should typically be run from the `release` branch after publishing a new release to ensure the deployed examples are using the latest stable version of Wasp. You can run this workflow: - **From GitHub UI**: https://github.com/wasp-lang/wasp/actions/workflows/release-examples-deploy.yaml (click "Run workflow" and select the `release` branch) - **From GitHub CLI**: ```bash # Deploy with latest Wasp version gh workflow run release-examples-deploy --ref release # Deploy with specific Wasp version gh workflow run release-examples-deploy --ref release -f version=0.13.2 ``` If you put `[skip ci]` in commit message, that commit will be ignored by Github Actions. We also wrote a `new-release` script which you can use to help you with creating new release: you need to provide it with new version (`./new-release 0.3.0`) and it will check that everything is all right, create appropriate tag and push it, therefore triggering CI to create new release on Github. NOTE: If building of your commit is suddenly taking much longer time, it might be connected with cache on Github Actions. If it happens just once every so it is probably nothing to worry about. If it happens consistently, we should look into it. ### Typical Release Process Do the steps marked with 👉 for every release of `waspc`. Do the non-bold steps when necessary (decide for each step depending on the changes, e.g. some can be skipped if there were no breaking changes). - Ensure that OpenSaaS is updated to the latest Wasp `main` (go to https://github.com/wasp-lang/open-saas/actions/workflows/e2e-tests.yml and manually run the workflow on the `main` branch). - 👉 Ensure that you have merged any changes from the `release` branch into `main`. You can see the latest PR at https://github.com/wasp-lang/wasp/pull/release. - 👉 Update your local repository state to have all remote changes (`git fetch`) and ensure local `main` is up to date. - 👉 Branch out from the latest commit you want to release (most likely latest `main`) into a new RC branch called `rc-` (e.g., `rc-0.24.1`) and do the rest of the steps from there. - 👉 The version in `waspc.cabal` should already be correct, but double check and update it if needed. - If you modify `waspc.cabal`: create a PR, wait for approval and all the checks (CI) to pass. Then squash and merge the PR into the RC branch. - 👉 Create an RC release do some testing and fixing (see [below](#test-releases-eg-release-candidate)). Continue when everything is fine. - 👉 Check commits since the latest release, and consider enriching and polishing the `ChangeLog.md` and migration guides. - If this is a major version update, take a versioned "snapshot" of the current docs on the RC branch by running `npm run docusaurus docs:version {version}` in the [web](/web) dir. Check the [README in the `web` dir](https://github.com/wasp-lang/wasp/blob/main/web/README.md) for more details. Commit this change to the RC branch and push it. - 👉 Switch to the `release` branch and fast-forward it to the RC branch by running `git merge --ff rc-`. - 👉 When you're ready to make the final release, make sure you are on `release` and then run `./new-release 0.x.y`. - This script will do some checks, tag the commit with the new release version, and push the tag. - 👉 Wait for CI to finish & succeed for the new tag. - This is triggered automatically on tag push. When it's done, it will create a new draft release on Github and stage the npm packages on npm (staged packages are not published until a maintainer approves them). - 👉 Find the new draft release here: https://github.com/wasp-lang/wasp/releases and edit it with your release notes. This usually means copy-pasting the ChangeLog entries for the released version. - 👉 Publish the draft release when ready. - 👉 Approve the staged npm packages. Run `npm stage list` to find the stage IDs, then `npm stage approve ` for each. Approval requires 2FA. - 👉 Push your local `release` branch to remote. - 👉 You will have been tagged in an automated PR to merge `release` back to `main` (you can also find it [here](https://github.com/wasp-lang/wasp/pulls?q=is%3Apr+head%3Arelease+base%3Amain+is%3Aopen)). Make sure to merge that PR (create a merge commit, **don't squash or rebase**). This ensures that `main` is ahead of `release` and we won't have merge conflicts in future releases. - Deploy the example apps to Fly.io by running the [release-examples-deploy workflow](https://github.com/wasp-lang/wasp/actions/workflows/release-examples-deploy.yaml) (see "Deployment / CI" section for more details). - If there are changes to the docs, [publish the new version](../web/README.md#deployment) from the `release` branch. - Announce the new release in Discord. - Go back to [Notion](https://www.notion.so/wasp-lang/1d018a74854c80d9aa64deb058719000) and go through the "After the release" section of the checklist. #### Determining next version `waspc` follows typical SemVer versioning scheme, so `major.minor.patch`. While we are not 1.0 yet, we follow the SemVer convention of keeping `major` at 0, and bumping `minor` on breaking changes instead. #### Test releases (e.g. Release Candidate) Making a test release, especially "Release Candidate" (RC) release is useful when you want to test the release without it being published to the normal users. If doing this, steps are the following: 1. Create a new branch called `rc-` (e.g., `rc-0.24.1`) by branching out of the last commit you want to release (probably latest `main`). 2. Locally execute the `new-release` script. Append `-rc.N` to the version number to make it obvious that this release is a pre-release used for testing (e.g., `./new-release 0.24.1-rc.1`). The script will throw some warnings which you should accept. 3. Once the draft release is created on Github: - Use their UI to mark it as a pre-release and publish it. This will automatically remove the checkmark from "latest release", which is exactly what we want. **This is the crucial step that differentiates test release from the proper release.** - Push the `rc-` branch to remote. 4. Approve the staged npm packages. Run `npm stage list` to find the stage IDs, then `npm stage approve ` for each. Approval requires 2FA. 5. Install the package by passing an explicit version: ```sh npm i -g @wasp.sh/wasp-cli@0.24.1-rc.1 ``` 6. Create a new checklist [in Notion](https://www.notion.so/wasp-lang/1d018a74854c80d9aa64deb058719000) and go through the "Before the release" section. If you find problems, fix them on the `rc` branch and create a new RC following the same process (e.g., `0.24.1-rc.2`, see step 2). ## Documentation External documentation, for users of Wasp, is hosted at https://wasp.sh/docs, and its source is available at [web/docs](/web/docs), next to the website and blog. ## Haskell We are documenting best practices related to Haskell in our [Haskell Handbook](https://github.com/wasp-lang/haskell-handbook). ### Cabal dep freezing Why don't we use a cabal freeze file to lock our dependencies? In order to better support a wider range of developer operating systems, we have decided against using a cabal freeze file and instead use cabal's `index-state` feature to get package version pinning from hackage. See this question for more: https://github.com/haskell/cabal/issues/8059 . ## Code style guide ### General #### Comments ##### Grammar When writing a comment, we prefer starting it with a capital letter. If it starts with a capital letter, it must end with a punctuation. If it doesn't start with a capital letter, it shouldn't end with a punctuation. ##### TODO / NOTE When writing a TODO or NOTE, use all capital letters, like this: ```hs -- TODO: Wash the car. -- NOTE: This piece of code is slow. ``` If you wish, you can add your name to TODO / NOTE. This is useful if you think there is a fair chance that reader of that TODO / NOTE might want to consult with its author. You can do it like this: ```hs -- TODO(martin): Doesn't work on my machine in some unusual use cases. ``` ### JavaScript #### Functions For detailed reasoning/discussion on all listed rules, check [Issue #487](https://github.com/wasp-lang/wasp/issues/487). ##### Top-level named functions When defining top-level named functions, we prefer to use statements: ```javascript // good function foo(param) { // ... } // bad const foo = (param) => { // ... }; // bad const foo = function (param) { // ... }; ``` ##### Inline function expression When defining inline function expressions, we prefer the arrow syntax: ```javascript // good const squares = arr.map((x) => x * x); // bad const squares = arr.map(function (x) { return x * x; }); ```