Skip to content

Contributing

Thank you for your interest in actively participating in the project's development! Please read the Contributor Covenant Code of Conduct and the Contributor License Agreement first.

The project is written in ClojureScript - a compiler for Clojure that targets JavaScript, and is based on re-frame - a framework for building Modern Web Apps in ClojureScript. You should probably take a look at their exceptional documentation first.

Style Guide

We try to follow the Clojure Style Guide as much as possible. You are also advised to read an additional resource about how to name Clojure functions by Stuart Sierra. In addition to the idiomatic names, we use the following conventions

e           -> event
el, els     -> element, elements
attr, attrs -> attribute, attributes
prop, props -> property, properties
w, h        -> width, height
t           -> time
h, m, s, ms -> hours, minutes, seconds, milliseconds

App structure

Main structure

src\
├── renderer\ -> Renderer Process
├── electron\ -> Main Process & Preload script
├── lang\     -> Translation files
└── worker\   -> Web Workers

We are trying to split our code under renderer into relatively independent modules, following re-frame's app structure suggestions with some minor additions.

module\
├── core.cljs      -> entry point
├── db.cljs        -> schema, validation
├── views.cljs     -> reagent views
├── events.cljs    -> event handlers
├── subs.cljs      -> subscription handlers
├── handlers.cljs  -> helper functions for db transformations
├── effects.cljs   -> effect handlers
├── hierarchy.cljs -> multimethods and hierarchies
├── styles.css     -> styles
└── README.md      -> documentation

Re-frame recommendations

Avoid chaining events to create new ones. Always prefer composing pure functions that directly transform the db. That is the whole purpose of handlers namespace. Most functions under handlers take the db as their first argument, so they can be easily composed using the thread-first macro ->.

Use interceptors sparingly. Although they look (and probably are) ingenious, it is hard to write and reason with them. Doing things explicitly, is usually easier to grasp and maintain.

Always use auto-qualified keywords (e.g. ::copy) for subscriptions, events and effects. You can use as-alias to require those namespaces without evaluating the registrations multiple times.

Spec

We use malli to describe the shape of our app db and selectively validate incoming data (e.g. file loading). We also use this spec to generate default values. Full db validation is enabled on dev mode.

Function schemas are selectively applied to pure and critical namespaces, such as utils and handlers. By default, function schemas are instrumented only during tests to avoid performance overhead. However, runtime instrumentation can also be enabled in the development environment (see dev.cljs).

Useful development shortcuts

Ctrl+Shift+I -> Toggle devtools
Ctrl+Shift+X -> Toggle 10x
Ctrl+R       -> Reload app

AI and LLM policy

Contributors should ensure that their work does not violate any copyright laws. This also applies to AI generated code. Check the tool’s terms of use, to ensure you are not using copyrighted sources. You are advised to use models trained on content with compatible licensing.

Using AI to review changes to catch minor errors or fix typos before submitting a PR is allowed, and does not require notice.

Changes assisted by AI tools should be marked by adding an "Assisted-by: MODELS" label at the end of the pull requests. MODELS should be replaced by a comma-separated list of the utilized models. You should always review any AI generated changes, and make sure that they don't introduce any bugs, or reduce the quality of the code.

Contributions that are fully generated by AI tools will be rejected.

Translations under src/lang are mostly generated using LLMs, and are exempted from the previous rule. Using AI to update or add new languages without further modifications is accepted, but human intervention may required to make sure that the changes don't break existing functionality, or do not reduce the quality of existing translations. We are looking into ways to fully automate this process.

Pull requests fully generated by AI tools should be marked by adding a "Generated-by: MODELS" label at the end of the pull requests.