From d339e5674a6e582f70aa35acd2d8c0fa279f271c Mon Sep 17 00:00:00 2001 From: smartass Date: Thu, 11 Jun 2026 23:18:26 +0500 Subject: [PATCH] style: braces always, concat over interpolation --- AGENTS.md | 13 +++++++++++ biome.json | 6 ++++- .../plans/2026-06-11-dbmole-mcp.md | 5 ++++ src/config/store.ts | 20 ++++++++++------ src/format.ts | 23 +++++++++++++------ 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e42daa4..c0c4477 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,6 +9,19 @@ Applies to every change in this repo, by any agent or human. - Single quotes where possible - Functions as `const fn = () => {}` where possible - No trailing commas before a closing `}`, `]`, `)` (`trailingCommas: none`) +- Always use braces for `if`/`else`/loop bodies — never single-line bodies like + `if (x) return y`. Write: + + ```ts + if (typeof value === 'bigint') { + return value.toString() + } + ``` + + (Biome `useBlockStatements` enforces this) +- No template-literal interpolation for building strings: use concatenation — + `'[' + engine + '] ' + message`, NOT `` `[${engine}] ${message}` ``. + Plain multi-line template literals WITHOUT `${}` (e.g. SQL text blocks) are fine. - Biome enforces all of the above — run `npm run lint:fix` before every commit - Line width 100 diff --git a/biome.json b/biome.json index 1970704..58fa4e0 100644 --- a/biome.json +++ b/biome.json @@ -19,7 +19,11 @@ "linter": { "enabled": true, "rules": { - "recommended": true + "recommended": true, + "style": { + "useBlockStatements": "error", + "useTemplate": "off" + } } } } diff --git a/docs/superpowers/plans/2026-06-11-dbmole-mcp.md b/docs/superpowers/plans/2026-06-11-dbmole-mcp.md index 416a1a7..f58bc84 100644 --- a/docs/superpowers/plans/2026-06-11-dbmole-mcp.md +++ b/docs/superpowers/plans/2026-06-11-dbmole-mcp.md @@ -9,6 +9,11 @@ **Tech Stack:** `@modelcontextprotocol/sdk` v1 (stable; v2 is npm-alpha only — decided with the user), zod 3, `pg`, `mysql2`, `ssh2`, tsup, Biome, vitest + coverage-v8, testcontainers. **Conventions for every task:** +- AGENTS.md at repo root is the authority on style. Two rules postdate the code + samples below: ALWAYS braces for if/else/loop bodies, and NO `${}` template + interpolation (use string concatenation; plain multi-line template literals + without `${}`, e.g. SQL, stay). When a sample violates these, rewrite it to + comply while keeping identical behavior. - Code style: 4 spaces, no semicolons, single quotes, `const fn = () => {}`, no trailing commas before a closing `}`/`]`/`)`. Biome enforces all of this (`semicolons: asNeeded`, `trailingCommas: none`) — run `npx biome check --write src test` before each commit. - Types must line up without escape hatches: no `as unknown as X`, no `@ts-ignore`/`@ts-expect-error`, no `any` in `src/`. In tests prefer the typed fakes from `test/unit/helpers.ts` (`fakeManager()`); resort to a cast only if there is genuinely no typed way. - stdout is the MCP protocol channel. Diagnostics go to `console.error` ONLY. Never `console.log`. diff --git a/src/config/store.ts b/src/config/store.ts index b63b3ca..39ea9e3 100644 --- a/src/config/store.ts +++ b/src/config/store.ts @@ -14,7 +14,9 @@ export const parseConnections = (items: unknown[], origin: string): ConnectionCo result.push(check.data) } else { const name = (item as { name?: unknown })?.name ?? '' - console.error(`dbmole: skipping invalid connection '${String(name)}' from ${origin}`) + console.error( + "dbmole: skipping invalid connection '" + String(name) + "' from " + origin + ) } } return result @@ -22,19 +24,23 @@ export const parseConnections = (items: unknown[], origin: string): ConnectionCo export const readStore = (path: string): ConnectionConfig[] => { mkdirSync(dirname(path), { recursive: true, mode: 0o700 }) - if (!existsSync(path)) return [] + if (!existsSync(path)) { + return [] + } let parsed: unknown try { parsed = JSON.parse(readFileSync(path, 'utf8')) } catch { - console.error(`dbmole: store file ${path} is not valid JSON, treating as empty`) + console.error('dbmole: store file ' + path + ' is not valid JSON, treating as empty') return [] } if (!Array.isArray(parsed)) { - console.error(`dbmole: store file ${path} must contain a JSON array, treating as empty`) + console.error( + 'dbmole: store file ' + path + ' must contain a JSON array, treating as empty' + ) return [] } - return parseConnections(parsed, `store ${path}`) + return parseConnections(parsed, 'store ' + path) } let writeSeq = 0 @@ -42,9 +48,9 @@ let writeSeq = 0 export const writeStore = (path: string, connections: ConnectionConfig[]): void => { mkdirSync(dirname(path), { recursive: true, mode: 0o700 }) writeSeq += 1 - const tmp = `${path}.${process.pid}.${writeSeq}.tmp` + const tmp = path + '.' + process.pid + '.' + writeSeq + '.tmp' const items = connections.map((c) => JSON.stringify(c, null, 4)) - const content = items.length === 0 ? '[]\n' : `[\n${items.join(',\n')}\n]\n` + const content = items.length === 0 ? '[]\n' : '[\n' + items.join(',\n') + '\n]\n' writeFileSync(tmp, content, { mode: 0o600 }) renameSync(tmp, path) } diff --git a/src/format.ts b/src/format.ts index 04f48a1..1d63cf6 100644 --- a/src/format.ts +++ b/src/format.ts @@ -2,7 +2,9 @@ export const DEFAULT_ROW_LIMIT = 100 export const MAX_ROW_LIMIT = 1000 export const clampRowLimit = (requested?: number): number => { - if (requested === undefined) return DEFAULT_ROW_LIMIT + if (requested === undefined) { + return DEFAULT_ROW_LIMIT + } return Math.max(1, Math.min(Math.trunc(requested), MAX_ROW_LIMIT)) } @@ -12,9 +14,15 @@ export const truncateRows = (rows: T[], limit: number): { rows: T[]; truncate : { rows, truncated: false } export const normalizeCell = (value: unknown): unknown => { - if (typeof value === 'bigint') return value.toString() - if (value instanceof Date) return value.toISOString() - if (Buffer.isBuffer(value)) return `\\x${value.toString('hex')}` + if (typeof value === 'bigint') { + return value.toString() + } + if (value instanceof Date) { + return value.toISOString() + } + if (Buffer.isBuffer(value)) { + return '\\x' + value.toString('hex') + } return value } @@ -28,10 +36,11 @@ type DbErrorShape = Error & { export const formatDbError = (engine: string, error: unknown): string => { if (error instanceof Error) { const e = error as DbErrorShape - const code = e.code !== undefined && e.code !== null ? ` ${e.code}` : '' + const code = e.code !== undefined && e.code !== null ? ' ' + e.code : '' const message = e.sqlMessage ?? e.message const extras = [e.detail, e.hint].filter(Boolean).join(' | ') - return `[${engine}${code}] ${message}${extras ? ` (${extras})` : ''}` + const suffix = extras ? ' (' + extras + ')' : '' + return '[' + engine + code + '] ' + message + suffix } - return `[${engine}] ${String(error)}` + return '[' + engine + '] ' + String(error) }