Contributing
Code Standards
Code Standards
TypeScript
All packages use strict mode with noUncheckedIndexedAccess. This means:
- No implicit
any - Array index access returns
T | undefined - All function parameters and return types must be inferrable or explicit
// ✗ — implicit any
function process(data) { ... }
// ✓
function process(data: Record<string, unknown>): string { ... }
When you genuinely need any (e.g. CF Workers globals not typed in Node), add a biome-ignore comment:
// biome-ignore lint/suspicious/noExplicitAny: CF Workers global
const msg = new (globalThis as any).EmailMessage(...);
Use import type for type-only imports:
import type { StedefastPlugin } from "@stedefast/core";
import { definePlugin } from "@stedefast/core";
Biome (lint + format)
We use Biome for both linting and formatting — no Prettier, no ESLint.
pnpm check # check all files
pnpm check --write # auto-fix
Key conventions (see biome.json at the repo root):
- Indentation: 2 spaces
- Quotes: double quotes in TypeScript/TSX
- Semicolons: always
- Line width: 80 characters
- Import sorting: automatic
Commit messages
We enforce Conventional Commits via commitlint:
feat(plugin-mermaid): add dual-theme support
fix(module-search): handle empty content nodes
docs(contributing): add module PR checklist
test(content): add listing page pagination tests
Valid types: feat, fix, docs, test, refactor, perf, chore, ci.
The scope (in parentheses) should be the package name suffix — plugin-shiki, module-comments, cli, content, etc.
Testing
We use Vitest. Test files live at src/__tests__/*.test.ts alongside source code.
pnpm test # run all tests
pnpm --filter /content test # single package
pnpm --filter /content test --watch # watch mode
Guidelines:
- Test behaviour, not implementation — test what goes in and what comes out
- Don't mock internal modules — use real implementations
- Use the provided mock helpers for CF bindings (D1, KV) — see
module-comments/__tests__ - One
describeper module/function, oneitper behaviour
File naming
- Source files:
kebab-case.ts - React components:
PascalCase.tsx - Test files:
kebab-case.test.ts - No barrel
index.tsre-exports insrc/— import directly from the source file
Pre-commit hooks
Lefthook runs automatically on git commit:
biome checkon staged.ts/.tsxfilestsc --noEmiton the affected package
If either fails, the commit is blocked. Fix the issue and recommit — don't use --no-verify.
Changelog
Add a CHANGELOG.md entry in the relevant package for any user-facing change:
## [Unreleased]
### Added
- `lazy` option to defer language loading until the code block is in view (#123)
### Fixed
- Dual-theme CSS variables not applied when `themes` config is used (#124)
Format follows Keep a Changelog.