First of all, we'd like to thank you for taking some of your time to contribute to the project. You're awesome 🤠👍
Architecture decisions for this project are documented here, using the Architecture Decision Records (ADR) pattern.
- Getting started
- Run the tests
- Create a new refactoring
- Useful resources to start changing the code
- Code Style
- Debug locally
- Create a package and use it
- Open a PR and add acknowledge your contribution
- Deploy a new version
- Clone the repo:
git clone [email protected]:nicoespeon/abracadabra.git
- Go into the cloned repository:
cd abracadabra
- Install dependencies:
yarn install
The project uses TypeScript, Jest for the tests and Prettier for the formatting.
You can run unit tests with yarn test
.
To run tests in watch mode, use yarn test --watch
.
We use Jest under the hood, so you can pass any valid Jest command to yarn test
.
We write 2 kind of tests:
- Unit Tests
- Integration Tests (we call them Contract Tests)
Now, people have different definitions of what a "unit" is and what "integration" tests are. So here's an explaination of how it works in this project 🤠
Most of our tests are testing the business logic, isolated from VS Code API. It's pure logic and doesn't rely on a specific environment to run. That's what we call that "unit tests". Some would call them "integration tests" because we don't mock much. Others would call that sociable unit tests. What really matters is that they are reliable, fast, and don't test implementation details.
To make this possible, we're using an InMemoryEditor
implementation that behaves as expected. To ensure it behaves as expected, we have written contract tests. These same tests will run against the VSCodeEditor
implementation, ensuring we can replace one with the other. These contract tests are what we'd call "integration tests". But, we simply call them contract tests.
Here's a little schema to illustrate how it works:
Too small to read? Check the SVG 👍
You can run the contract tests with yarn test:contract
.
It's a distinct command because these tests are slower. They will integrate with VS Code API to actually do changes in a playground environment. Hopefully, we don't need to run them often—not until we have to change editors' behavior.
VS Code has a limitation. It can't launch tests that access VS Code API while another instance of the editor is running.
Thus, there are 2 ways to actually launch the tests:
- Use VS Code Insiders, which has less restrictions, but is riskier to use—it has the most recent code pushes and may lead to the occasional broken build.
- Lauch tests through the VS Code debugger. We created a dedicated task you can launch. It will compile the code, open a playground editor and run the tests inside.
The test report is available in the Debug Console
.
Finally, both unit & contract tests are run in CI. If you open a PR and CI is green, then you know everything is fine and you did an amazing job ✅
On top of expected editor behaviors, the InMemory editor has convenient features that makes tests easier to write:
[start]
and[end]
are parsed as if it was the selection of the user[cursor]
is parsed as if it was the cursor of the user (the cursor really is an empty selection, so that's a shorthand for[start][end]
)
Have a look at existing tests, you'll see that this leads to very easy to read specifications.
Run yarn new
and follow the tool, it will ask you the relevant questions.
We've documented the context of this decision in this ADR.
If you want to change how code scaffolding works, check hygen documentation.
You will also need to add the new refactoring to the lists in package.json
and src/extension.ts
. These lists should be kept in alphabetical order.
- VS Code Extension API documentation is a good start
- AST Explorer is a very handy tool to explore the AST. Use
babylon-7
parser. - As we use Babel to transform the AST, the handbook is very useful. In particular the transformation and the manipulation parts.
Style formatting is managed by Prettier. It runs as a pre-commit hook, so you shouldn't have to worry about it 👐
There a few conventions that we'd like to keep consistent and are not automatically enforced yet.
We structure TS files like this:
// 1. Imports from external libs
import { parse } from "@babel/parser";
// 2. Imports from local files
import { Selection } from "./selection";
import { Position } from "./position";
// 3. Rest of the code, starting with high-level concepts
export function statementWithBraces(node: t.Statement): t.Statement {
return isBlockStatement(node) ? node : blockStatement([node]);
}
function isBlockStatement() {}
function blockStatement() {}
As a general rule, we prefer to have what is exposed appear before what is private. We like to read the high-level concepts before the implementation details.
You can use VS Code's built-in debugger on the project to test the extension.
To build the project, press F5
.
Note: if pressing F5
runs the "Contract Tests", please select the "Run Extension" task instead and press F5
again.
It will open an "Extension Development Host" window, overriding your "Abracadabra" extension with your local code. This is helpful to test your changes in integration with VS Code API.
If you do changes, rebuild the project by clicking on the reload icon.
While debugging the extension is helpful to see changes in action, you can use the unit tests to develop without having to rebuild the project at every change.
If you want to see what's in the final build, run yarn build
(don't use --production
target).
This will generate meta-*.json
files in the out/
folder.
To visualize them, go to https://esbuild.github.io/analyze/ and import the file you want to visualize. It will give you the size of the build and a detailed breakdown of what's inside.
To create a package from your local code, run yarn package
.
When it's done, run yarn package:install
to install this new version instead of the one you had.
This allows you to use the package before it's published to the MarketPlace.
You can open a Pull-Request at any time. It can even be a draft if you need to ask for guidance and help. Actually, we'd be pretty happy to assist you going in the best direction!
Once everything is ready, open a Pull-Request (if it's not already done) and ask for a review. We'll do our best to review it asap.
Finally, use all-contributors bot command to add yourself to the list of contributors. It's very easy to do, you basically need to mention the bot in a comment of your PR.
Whether it's code, design, typo or documentation, every contribution is welcomed! So again, thank you very, very much 🧙
Usually, @nicoespeon will deploy new versions of Abracadabra. Here are the necessary steps documented, in case you need to do it (or he forgots how to).
Hopefully, most of the steps are automated already!
- Check that tests are passing (
yarn test:ci
) and package can be built (yarn build
). CI is automatically running against all Pull-Requests to ensure this is always true. Also, the new version won't be deployed if CI doesn't pass anyway. - Bump the version in the
package.json
following SemVer. - If it's a minor or major bump, choose a release name (no rule here, have fun). Update the Changelog accordingly.
- Commit all of these changes directly on the main branch, like this: 5.3.0
- Create a new release targeting the main branch. Use the release name as a title and changelog body as a description.
That's it. A GitHub Action will kick in and publish the new release to all marketplaces. @nicoespeon should receive an email when everything is done.