chore: migrate from prettier+eslint to biome#118
Open
Ovaculos wants to merge 7 commits into
Open
Conversation
Closes NimbleBrainInc#105. Replaces prettier (formatter) and eslint (linter) with biome across all TypeScript packages. Single binary, single config, no plugin chain. Aligns with NimbleBrain org tooling (nimblebrain repo, synapse-app servers). Changes: - Add @biomejs/biome ^2.0.0 as workspace devDependency - Drop @typescript-eslint/eslint-plugin, @typescript-eslint/parser, eslint, prettier, typescript-eslint from root devDependencies - Replace `pnpm format` / `pnpm format:check` with biome equivalents; add `pnpm lint`, `pnpm lint:fix`, `pnpm lint:ci` (biome ci) - Remove `lint` task from turbo.json and per-package `lint` / `lint:fix` scripts in web, registry, cli, sdk-typescript, schemas (single root entry point via `biome check .` instead of turbo fan-out) - Update CI workflows: drop separate "Format check" prettier step in sdk-typescript-ci/publish; route lint steps in cli-publish, schemas-publish, sdk-typescript-ci/publish through root `pnpm lint`; replace separate lint + typecheck steps in ci.yml with `pnpm lint:ci` - Delete .prettierrc, .prettierignore, eslint.config.js Biome configuration: vanilla recommended ruleset, only mpak-required overrides (2-space indent, 100 line width, single quotes, tailwind directives parser). `noNonNullAssertion` disabled to match org config. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three independent tsconfig fixes surfaced during the biome migration: - tsconfig.base.json: set `noPropertyAccessFromIndexSignature` to false. Resolves a deadlock between biome's `lint/complexity/useLiteralKeys` (wants dot access on index signatures) and tsc strict (wanted bracket). Code style across the monorepo is already dot access since the prior ESLint config didn't enforce the strict variant; this aligns the type checker with the existing style and biome's recommendation. - apps/registry/tsconfig.json: remove three duplicate compilerOptions keys (`exactOptionalPropertyTypes`, `noPropertyAccessFromIndexSignature`, `noUncheckedIndexedAccess`) that biome's `noDuplicateObjectKeys` rule caught — a real bug where the second declaration silently shadowed the first. Also drops the now-redundant `noPropertyAccessFromIndexSignature` override since the base now matches. - packages/schemas/tsconfig.json: explicitly pin `types: []`. Without it, tsc auto-discovers every `@types/*` package found via node_modules walk, which broke after `pnpm install` reshuffled hoisting (schemas itself depends on none of those types — only zod). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
a11y additions surfaced by biome's recommended ruleset:
- aria-hidden="true" on 119 decorative inline SVG icons across components
and pages. Audit confirmed each parent already carries an accessible
label (visible text sibling or aria-label on the interactive ancestor).
- type="button" on 33 form-buttons that previously defaulted to "submit",
preventing unintended form submission on click.
- ClaimPackageModal: explicit aria-label="Close" on the icon-only close
button (the only true icon-only-no-label interactive in the codebase),
htmlFor + matching ids on the two label/input pairs, Escape key handler
on the backdrop dismissal, scoped biome-ignore for the necessary static-
element interaction pattern.
- RootLayout: sr-only "GitHub" text inside the icon-only GitHub anchor
pair so screen readers announce content (aria-label alone doesn't satisfy
biome's useAnchorContent rule).
React hook stability (fixes useExhaustiveDependencies warnings on six
useEffect call sites): BrowsePackagesPage, CategoryPage, HomePage,
SkillsPage, UserPackagesPage, ClaimPackageModal. Each load* function
wrapped in useCallback with its real dependency set; the useEffect that
calls it now sits below the declaration so it doesn't reference a
not-yet-initialized binding.
Stable React keys: replace `key={index}` with content-based keys in
Breadcrumbs (href/label), ClaimPackageModal steps, SecurityReportSection
findings (purl), HomePage FAQ (question), SkillDetailPage examples
(prompt) + triggers, ConfigurationPanel CLI commands (command string).
Two syntax-highlight token-stream maps in ConfigurationPanel (JsonHighlight,
CliHighlight) keep numeric keys for positional rendering — scoped
biome-ignore explains intent.
Also drops two stale eslint-disable comments in SkillsPage and
SkillDetailPage (the noNonNullAssertion rule is now off project-wide
under biome).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Type annotations to satisfy biome's `noImplicitAnyLet` and to replace `any` with concrete types: - apps/registry/src/routes/packages.ts: replace `let result;` with an explicit shape literal type for the transaction return value. - apps/registry/src/routes/v1/bundles.ts, v1/skills.ts: replace `let claims;` with `Awaited<ReturnType<typeof verifyGitHubOIDC>>`. - apps/web/src/components/ScanTriggerButton.tsx: replace `catch (err: any)` with `catch (err)` + a narrow axios-shape cast on use. Also picks up the aria-hidden + type="button" additions from the a11y pass. forEach callbacks wrapped in braces to satisfy `useIterableCallbackReturn`: - packages/cli/src/commands/skills/show.ts (1 site) - packages/cli/src/commands/skills/validate.ts (2 sites) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Suppressions for intentional patterns biome flagged:
- File-level `biome-ignore-all lint/suspicious/noTemplateCurlyInString` in
nine test/seed files that legitimately use `${var}` placeholders inside
string literals — mpak manifest substitution syntax, expanded at install
time, not JS template literals:
apps/registry/prisma/seed.ts
apps/registry/tests/server-detail-composer.test.ts
apps/web/src/lib/manifest.test.ts
packages/cli/tests/bundles/{outdated,run}.test.ts
packages/schemas/tests/manifest.test.ts
packages/sdk-typescript/tests/{cache,mpak,validate}.test.ts
- packages/sdk-typescript/tests/mpak.test.ts: scoped biome-ignore on two
`as any` casts that deliberately exercise the non-string env-var guard.
Drops two stale `// eslint-disable-next-line` comments at the same sites.
- packages/sdk-typescript/tests/validate.test.ts: scoped biome-ignore on
one `as any` cast against a deliberately malformed manifest.
- apps/web/src/index.css: scoped biome-ignore on a highlight.js token
selector that descends in specificity — order is intentional for
syntax-highlight token precedence.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mechanical reformat applied by `biome check --write [--unsafe]`. No behavioral changes. Covers: - Import organization (sorted, type-only imports promoted to `import type`) - `useNodejsImportProtocol` autofix: `fs` -> `node:fs`, `path` -> `node:path`, etc., on all builtin module imports - `useLiteralKeys` autofix: `record["KEY"]` -> `record.KEY` where the property name is a valid identifier (deadlock with tsc was resolved in the prior tsconfig commit) - `noUnusedImports` autofix: drops two unused starlight imports in apps/docs/src/components/Header.astro - Misc formatter passes: indentation, trailing commas, semicolons, line width 100, single quotes (matches prior prettier output). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The biome reformat stripped `import Default` from Header.astro because its noUnusedImports pass parses only the .astro frontmatter, not the template where <Default> is rendered. On a cold build the override rendered empty (no nav, search, social, title, or content) — only a warm dev cache hid it. Restore the import with a scoped biome-ignore so biome keeps linting .astro without re-removing it. Also document why packages/schemas/tsconfig.json pins `types: []` (prevents tsc @types/* auto-discovery breaking on pnpm hoist changes). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces prettier (formatter) + eslint (linter) with biome across all TypeScript packages. One binary, one config, no plugin chain. Aligns mpak with the rest of NimbleBrain's TS tooling.
Closes #105.
Commits (logical, grep-able history)
chore: migrate from prettier+eslint to biome@biomejs/biome, drop eslint/prettier deps, replace scripts, update CI workflows, delete.prettierrc/.prettierignore/eslint.config.jschore: tsconfig adjustments for biome compatibilitynoPropertyAccessFromIndexSignaturein base; remove duplicate keys + redundant override in registry; pintypes: []in schemasfix(web): a11y, React hook stability, and array key improvementsaria-hiddenon decorative SVGs,type="button", modal a11y,useCallbackeffect deps, content-based React keysfix: explicit types and forEach braces for biome strict rulesnoImplicitAnyLetannotations,useIterableCallbackReturnbraces, dropcatch (err: any)chore: biome-ignore intentional patterns and drop stale eslint comments${var}placeholders in tests; scoped ignores for deliberateas anyand CSS specificitystyle: biome reformatnode:protocol, literal keys, formatting. No behavior change.fix(docs): restore Starlight Header import dropped by biome migrationBiome config
Vanilla
recommendedruleset. Only mpak-required overrides:indentStyle: space,lineWidth: 100,quoteStyle: single(matches prior prettier output — no churn)css.parser.tailwindDirectives: true(else parse error on Tailwind@theme)noNonNullAssertion: off(matches org config)Notable decisions
pnpm lint(biome check .) instead of per-package fan-out. Publish workflows lint the whole repo, but biome is ~100ms for 227 files and tags cut from already-green main, so no practical cost.noPropertyAccessFromIndexSignaturerelaxed to resolve a deadlock between biomeuseLiteralKeys(wants dot) and tsc strict (wanted bracket). Repo style was already dot under the prior eslint config.Test plan
pnpm lint— 0 issuespnpm lint:ci(biome ci .) — exit 0pnpm typecheck— all 7 packages passpnpm test— pass (registry needs local Postgres; CI covers)/health, route registration)--version,--help,config list)🤖 Generated with Claude Code