134 lines
3.4 KiB
Markdown
134 lines
3.4 KiB
Markdown
A few notes on coding conventions used in this project.
|
|
|
|
# Tooling
|
|
|
|
Run these commands to perform type and style checks and automatically reformat code based on conventions:
|
|
|
|
```bash
|
|
make check # Type check + lint frontend and backend
|
|
make fmt # Format all code
|
|
```
|
|
|
|
# Code Style Guidelines
|
|
|
|
## TypeScript (client and plugs)
|
|
|
|
### Import Organization
|
|
|
|
```typescript
|
|
// Use relative imports by default (include .ts extension)
|
|
import { Space } from "./space.ts";
|
|
// Use `type` for type-only imports (part of the lint rules)
|
|
import type { Command } from "./types/command.ts";
|
|
|
|
// Use package-prefixed absolute when available (defined in package.json)
|
|
import { sleep } from "@silverbulletmd/silverbullet/lib/async";
|
|
```
|
|
|
|
### TypeScript Conventions
|
|
* Use `type` over `interface` for object shapes
|
|
* Use `type` for unions and complex types
|
|
* Always type function parameters explicitly
|
|
* Type return values for public APIs
|
|
* Let TypeScript infer obvious variable types
|
|
* Use `any` for error objects in catch blocks
|
|
|
|
|
|
### Naming Conventions
|
|
- **Variables & functions:** `camelCase`
|
|
- **Classes:** `PascalCase`
|
|
- **Files:** `snake_case.ts` (e.g., `http_space_primitives.ts`)
|
|
- **Test files:** `*.test.ts` alongside source files
|
|
- **Types:** `PascalCase` (e.g., `PageMeta`, `SpacePrimitives`)
|
|
- **Constants:** `camelCase`
|
|
|
|
|
|
### Testing Patterns
|
|
TypeScript tests run with Vitest (Node.js).
|
|
|
|
**Test structure:**
|
|
```typescript
|
|
import { expect, test } from "vitest";
|
|
|
|
test("Test description in plain English", async () => {
|
|
// Setup
|
|
const kv = new MemoryKvPrimitives();
|
|
const space = new Space(new DataStoreSpacePrimitives(kv), eventHook);
|
|
|
|
// Execute
|
|
await space.writePage("test", testPage);
|
|
|
|
// Assert
|
|
expect(await space.readPage("test")).toEqual(testPage);
|
|
});
|
|
```
|
|
|
|
**Assertions:**
|
|
```typescript
|
|
import { expect } from "vitest";
|
|
|
|
expect(actual).toEqual(expected);
|
|
expect(actual).not.toEqual(notExpected);
|
|
expect(value).toBeTruthy();
|
|
expect(value).toBeInstanceOf(ClassName);
|
|
```
|
|
|
|
**Running tests:**
|
|
```bash
|
|
npx vitest run # Run all tests once
|
|
npx vitest # Run in watch mode
|
|
npx vitest run <file> # Run specific test file
|
|
```
|
|
|
|
### Comments & Documentation
|
|
|
|
Use JSDoc for public APIs:
|
|
```typescript
|
|
/**
|
|
* Lists all pages (files ending in .md) in the space.
|
|
* @param unfiltered - Whether to include filtered pages
|
|
* @returns A list of all pages represented as PageMeta objects
|
|
*/
|
|
export function listPages(unfiltered?: boolean): Promise<PageMeta[]> {
|
|
return syscall("space.listPages", unfiltered);
|
|
}
|
|
```
|
|
|
|
Inline comments:
|
|
* In case of doubt: add comments around the _why_ of the code (not what)
|
|
* Add TODO comments for known issues
|
|
|
|
```typescript
|
|
// Note: these events are dispatched asynchronously (not waiting for results)
|
|
this.eventHook.dispatchEvent(...);
|
|
|
|
// TODO: Clean this up, this has become a god class
|
|
export class Client {
|
|
```
|
|
|
|
### Promise Handling
|
|
|
|
Use `void` to mark intentionally fire-and-forget promises. This satisfies the `noFloatingPromises` lint rule and signals that the unawaited call is deliberate.
|
|
|
|
### Code Patterns
|
|
|
|
**Definite assignment for late initialization:**
|
|
```typescript
|
|
class Client {
|
|
space!: Space; // Initialized in init()
|
|
editorView!: EditorView;
|
|
}
|
|
```
|
|
|
|
**Destructuring:**
|
|
```typescript
|
|
const { name, def } = command;
|
|
const { text, meta } = await this.space.readPage(name);
|
|
```
|
|
|
|
## Go (server)
|
|
Follow common Go conventions. `make fmt` also reformats Go code.
|
|
|
|
## Lua (libraries)
|
|
See `website/Space Lua/Conventions`
|