Version 3.3.0 · All versions

These are the docs as released with Solid Memo 3.3.0. Read the latest docs.

Style

How Solid Memo's code, data and docs are written. Most of it describes what the code already does, so new code reads like the code around it. When this page and the code disagree, follow the code nearby and fix this page.

Formatting

Biome formats and lints the TypeScript, JavaScript, JSON and CSS as biome.jsonc says, and npm run check fails on a file it would change. It leaves alone what is written by tools (the generated vocabulary, the lock files), the vendored files, and the Turtle in decks/ and ns/, which has its own formatter.

npm run format   # rewrite the files as Biome formats them, and apply its safe fixes
npm run lint     # check them, as npm run check does: formatting and lint rules

Biome's recommended lint rules are on. A rule that fires on code that is right as it is, is turned off in biome.jsonc with its reason beside it; a problem it finds is fixed.

In an editor, install Biome's extension (biomejs.biome for VS Code, which .vscode/extensions.json and the dev container recommend; others are listed on biomejs.dev), and make it the formatter for these files, on save if you like. It reads the same biome.jsonc, so the editor and the check agree.

The code was reformatted with Biome in one commit, which changed nothing else. .git-blame-ignore-revs lists it, so GitHub's blame looks past it; locally, run git config blame.ignoreRevsFile .git-blame-ignore-revs once. The file names a commit by its SHA, and the merge queue merges every pull request with a merge commit, which keeps its commits' SHAs (testing.md). So a pull request that adds a formatting commit can list its SHA in the file before it is merged.

TypeScript

The compiler holds the code to most of the rules (tsconfig.base.json): strict, no unused variables or parameters, no case falling through to the next in a switch, and verbatimModuleSyntax, so a type is imported with import type or type X in the import list.

Naming

WhatHowExample
A modulecamelCase, named for what it holdsdeckPace.ts, cardHistory.ts
A Preact component, and its filePascalCaseAddCardForm.tsx
A function, a variablecamelCase, a function named for what it does or returnspickLocale, shapesRuleset
A type, an interfacePascalCase, no I prefixUseCases, DeckInsight
A constant that is configuration or a tableUPPER_SNAKE_CASELOCALES, ERROR_TEMPLATES
An error code; a message keycamelCase, read as a short sentence; a key grouped by where it shows, with dotsdeckNeedsDescription; footer.createdBy
An RDF termcamelCase for properties, PascalCase for classessm:formatVersion, sm:Deck
A docs pagelowercase, hyphenateddeck-library.md

Names are whole words in the language of the domain (deck, card, review, release), not abbreviations: description, not desc.

Turtle

The hand-written Turtle in ns/, decks/ and the vocab package's fixtures/ has a house style, which formatTurtle.ts defines and writes. In short:

npm run format:turtle rewrites the files and npm run format:turtle:check fails on any that differ. A comment stays with the subject it comes before. A published version (vN.ttl under decks/ and ns/shapes/) is formatted once, before it is published, and never changes after; vendor/ is not ours and is never reformatted.

Comments

Licenses

Every file says who holds its copyright and under which license it may be reused, as the REUSE specification has it, so a file copied out of the repository still says so. A file that can carry a comment does, in a header at its top:

// SPDX-FileCopyrightText: 2026 Anton Wiklund and Solid Memo contributors
//
// SPDX-License-Identifier: MIT

A new file starts with that header, in its own kind of comment (# in YAML, a Dockerfile or a shell script, /* … */ in CSS). The reuse tool writes it:

reuse annotate --copyright "Anton Wiklund and Solid Memo contributors" --year 2026 --license MIT <file>

The files that cannot carry a header, or must not be edited, are licensed in REUSE.toml instead: the Markdown (kept free of headers so that it reads cleanly), the HTML (whose doctype comes first), JSON, pictures, test fixtures, the generated vocabulary, the published Turtle in decks/ and ns/, and the vendored shapes, which keep their authors' licenses. A new file of one of those kinds is covered by the pattern that matches it. The text of each license is in LICENSES/.

A library deck is under the license it states in dcterms:license, so REUSE.toml lists each deck under its license, and a new deck is added there under its own. npm run check:reuse, part of npm run check, fails when a version's dcterms:license is not the license REUSE.toml gives it (testing.md). A deck under a license no deck has used yet needs its SPDX identifier in checkReuse.ts and its text in LICENSES/ (reuse download <SPDX id>).

reuse lint checks that every file in the repository has both, in CI's docs job (testing.md), not in npm run check; npm run lint:reuse runs it locally with reuse installed (pipx install reuse), and pipx run reuse lint or uv run --no-project --with reuse reuse lint run it without installing it.

Docs

Language

English is the authoritative language of the code, the docs, commit messages, issues and pull requests. The app's messages are translated into the other languages it speaks (i18n.md); English is their source.

Commits

A commit is one change, whole: the code, its tests and its docs together, with npm run check passing. A file generated from another (packages/vocab/src/*.generated.ts from ns/) is committed with the change that generated it.

A commit message follows Conventional Commits, as CONTRIBUTING.md says, and has:

git log shows many examples; the commits before version 1.0.0 have the same body, under a header in sentence case, almost always with no type.