diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..b557652 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Bulk reformats. `git config blame.ignoreRevsFile .git-blame-ignore-revs` +7c3ebac6c13c79aee6c79c917a09363ff6c8fa9d # prettier, 13 files diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a646416..554fa37 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,7 +11,7 @@ version: 2 updates: - package-ecosystem: npm - directory: "/" + directory: '/' schedule: interval: weekly open-pull-requests-limit: 5 @@ -20,7 +20,7 @@ updates: update-types: [minor, patch] - package-ecosystem: github-actions - directory: "/" + directory: '/' schedule: interval: weekly open-pull-requests-limit: 3 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b698663 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,31 @@ +# Build output and vendored trees — formatting these is noise. +node_modules +.next +dist +build +out +coverage +.turbo +.vercel +*.min.js +*.min.css + +# Generated during a build, so it is absent locally and present in CI — which +# makes a clean local --check no evidence at all. Contentlayer's output also +# uses import assertions, which prettier's parser rejects outright. +.contentlayer +.astro +.svelte-kit +storybook-static +test-results +playwright-report + +# Lockfiles are generated; prettier would rewrite them wholesale. +package-lock.json +pnpm-lock.yaml +yarn.lock + +# Markdown is deliberately out of scope for now. Prettier rewraps prose, which +# is where it is most opinionated and least useful, and it would bury the real +# diff. Remove this line when you want docs formatted too. +*.md diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..616247a --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "semi": true, + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2, + "trailingComma": "all", + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/next.config.ts b/next.config.ts index cb651cd..b22af96 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,4 +1,4 @@ -import type { NextConfig } from "next"; +import type { NextConfig } from 'next'; const nextConfig: NextConfig = {}; diff --git a/package-lock.json b/package-lock.json index 4ff4a7f..de9c171 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@types/react": "^19.2.18", "eslint": "^9.39.5", "eslint-config-next": "^15.5.20", + "prettier": "3.9.6", "prisma": "^6.2.1", "typescript": "^5.7.3", "vitest": "^4.1.11" @@ -5672,6 +5673,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prisma": { "version": "6.19.3", "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.3.tgz", diff --git a/package.json b/package.json index 8f13696..455b106 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,11 @@ "lint": "next lint", "typecheck": "tsc --noEmit", "test": "vitest run", - "verify": "npm run lint && npm run typecheck && npm run test", + "verify": "npm run format:check && npm run lint && npm run typecheck && npm run test", "db:generate": "prisma generate", - "db:migrate": "prisma migrate dev" + "db:migrate": "prisma migrate dev", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "dependencies": { "@prisma/client": "^6.2.1", @@ -27,6 +29,7 @@ "@types/react": "^19.2.18", "eslint": "^9.39.5", "eslint-config-next": "^15.5.20", + "prettier": "3.9.6", "prisma": "^6.2.1", "typescript": "^5.7.3", "vitest": "^4.1.11" diff --git a/src/app/EvidenceVerifier.module.css b/src/app/EvidenceVerifier.module.css index c0f69c4..e640b84 100644 --- a/src/app/EvidenceVerifier.module.css +++ b/src/app/EvidenceVerifier.module.css @@ -152,7 +152,7 @@ } .algo { - font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; + font-family: ui-monospace, 'SFMono-Regular', Menlo, monospace; font-size: 0.75rem; color: var(--color-text-muted); } diff --git a/src/app/EvidenceVerifier.tsx b/src/app/EvidenceVerifier.tsx index 41d2b26..4bb86b6 100644 --- a/src/app/EvidenceVerifier.tsx +++ b/src/app/EvidenceVerifier.tsx @@ -82,8 +82,8 @@ export function EvidenceVerifier() {
Verify a claim from its evidence

- The verdict is a tally of supporting vs. contradicting evidence. Add - evidence on each side and see the explainable result — nothing hidden. + The verdict is a tally of supporting vs. contradicting evidence. Add evidence on each side + and see the explainable result — nothing hidden.

@@ -118,12 +118,7 @@ export function EvidenceVerifier() {
- {error && {error}} @@ -132,9 +127,7 @@ export function EvidenceVerifier() { {result && display && (
- - {display.label} - + {display.label} {result.confidence !== null && ( {Math.round(result.confidence * 100)}% confidence @@ -148,9 +141,8 @@ export function EvidenceVerifier() {

A verdict of Supported or Contradicted needs at least{' '} - {Math.round(MIN_AGREEMENT_TO_CONCLUDE * 100)}% of evidence to agree; - below that the claim stays Unverifiable rather than assert a - weakly-backed conclusion. + {Math.round(MIN_AGREEMENT_TO_CONCLUDE * 100)}% of evidence to agree; below that the + claim stays Unverifiable rather than assert a weakly-backed conclusion.

algorithm: {result.algorithm}
diff --git a/src/app/api/claims/[id]/verify/route.ts b/src/app/api/claims/[id]/verify/route.ts index cfb2d08..32396b8 100644 --- a/src/app/api/claims/[id]/verify/route.ts +++ b/src/app/api/claims/[id]/verify/route.ts @@ -2,10 +2,7 @@ import { NextResponse } from 'next/server'; import type { ApiResult } from '@/lib/api/result'; import { prisma } from '@/lib/db/prisma'; -import { - scoreClaimVerification, - type ClaimVerification, -} from '@/lib/domain/claim-verification'; +import { scoreClaimVerification, type ClaimVerification } from '@/lib/domain/claim-verification'; /** * GET /api/claims/[id]/verify diff --git a/src/app/api/claims/verify/route.ts b/src/app/api/claims/verify/route.ts index 5508ef7..96175f2 100644 --- a/src/app/api/claims/verify/route.ts +++ b/src/app/api/claims/verify/route.ts @@ -1,10 +1,7 @@ import { NextResponse } from 'next/server'; import type { ApiResult } from '@/lib/api/result'; -import { - scoreClaimVerification, - type ClaimVerification, -} from '@/lib/domain/claim-verification'; +import { scoreClaimVerification, type ClaimVerification } from '@/lib/domain/claim-verification'; import { parseVerifyRequest } from '@/lib/domain/verify-request'; /** @@ -21,9 +18,7 @@ import { parseVerifyRequest } from '@/lib/domain/verify-request'; * The response carries the tally, confidence, and algorithm id straight from the * domain, so a caller can reproduce the verdict from what they sent. */ -export async function POST( - request: Request, -): Promise>> { +export async function POST(request: Request): Promise>> { let body: unknown; try { body = await request.json(); diff --git a/src/app/globals.css b/src/app/globals.css index de662b6..7027206 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -25,7 +25,7 @@ --color-tone-negative: var(--primitive-red-700); --color-tone-neutral: var(--primitive-stone-500); - --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + --font-sans: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; --radius-card: 16px; --radius-btn: 8px; } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b520f7e..2383464 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,15 +1,13 @@ -import type { Metadata } from "next"; -import "./globals.css"; +import type { Metadata } from 'next'; +import './globals.css'; export const metadata: Metadata = { - title: "BiasLens", + title: 'BiasLens', description: - "Media bias analysis engine — evidence before conclusions, facts separated from framing.", + 'Media bias analysis engine — evidence before conclusions, facts separated from framing.', }; -export default function RootLayout({ - children, -}: Readonly<{ children: React.ReactNode }>) { +export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { return ( {children} diff --git a/src/app/page.tsx b/src/app/page.tsx index 2b27c3a..e80c949 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,24 +1,24 @@ -import { EvidenceVerifier } from "./EvidenceVerifier"; +import { EvidenceVerifier } from './EvidenceVerifier'; export default function Home() { return (
-
-

BiasLens

-

- Media bias analysis engine. Evidence before conclusions; facts separated - from framing; every score explainable and reproducible. +

+

BiasLens

+

+ Media bias analysis engine. Evidence before conclusions; facts separated from framing; + every score explainable and reproducible.

diff --git a/src/lib/api/result.ts b/src/lib/api/result.ts index 3afe912..e43d343 100644 --- a/src/lib/api/result.ts +++ b/src/lib/api/result.ts @@ -3,6 +3,4 @@ * every client parses. Defining it once keeps the HTTP contract from drifting * between producer (route handlers) and consumer (UI/hooks). */ -export type ApiResult = - | { success: true; data: T } - | { success: false; error: string }; +export type ApiResult = { success: true; data: T } | { success: false; error: string }; diff --git a/src/lib/config/verification.ts b/src/lib/config/verification.ts index 6343993..997cd78 100644 --- a/src/lib/config/verification.ts +++ b/src/lib/config/verification.ts @@ -24,8 +24,7 @@ export const VERIFICATION_STATUS = { /** Evidence exists but is too balanced to conclude either way. */ UNVERIFIABLE: 'unverifiable', } as const; -export type VerificationStatus = - (typeof VERIFICATION_STATUS)[keyof typeof VERIFICATION_STATUS]; +export type VerificationStatus = (typeof VERIFICATION_STATUS)[keyof typeof VERIFICATION_STATUS]; /** * How each verdict is presented to a human: its label and a semantic *tone* diff --git a/src/lib/domain/claim-verification.test.ts b/src/lib/domain/claim-verification.test.ts index 10a34e5..8a46d1b 100644 --- a/src/lib/domain/claim-verification.test.ts +++ b/src/lib/domain/claim-verification.test.ts @@ -19,13 +19,7 @@ describe('scoreClaimVerification', () => { it('is SUPPORTED when the supporting majority meets the threshold', () => { // 3/5 = 0.6 ≥ MIN_AGREEMENT_TO_CONCLUDE - const result = scoreClaimVerification([ - supports, - supports, - supports, - contradicts, - contradicts, - ]); + const result = scoreClaimVerification([supports, supports, supports, contradicts, contradicts]); expect(result.status).toBe(VERIFICATION_STATUS.SUPPORTED); expect(result.confidence).toBeCloseTo(0.6); expect(result.inputs).toEqual({ supports: 3, contradicts: 2, total: 5 }); @@ -57,20 +51,14 @@ describe('scoreClaimVerification', () => { }); it('ignores unknown stance values rather than trusting them', () => { - const result = scoreClaimVerification([ - supports, - supports, - { stance: 'garbage' }, - ]); + const result = scoreClaimVerification([supports, supports, { stance: 'garbage' }]); expect(result.inputs).toEqual({ supports: 2, contradicts: 0, total: 2 }); expect(result.status).toBe(VERIFICATION_STATUS.SUPPORTED); expect(result.confidence).toBe(1); }); it('stamps the algorithm version for reproducibility', () => { - expect(scoreClaimVerification([]).algorithm).toBe( - CLAIM_VERIFICATION_ALGORITHM, - ); + expect(scoreClaimVerification([]).algorithm).toBe(CLAIM_VERIFICATION_ALGORITHM); }); it('is deterministic — identical input yields identical output', () => { diff --git a/src/lib/domain/verify-request.ts b/src/lib/domain/verify-request.ts index 22c10a1..804c79e 100644 --- a/src/lib/domain/verify-request.ts +++ b/src/lib/domain/verify-request.ts @@ -13,9 +13,7 @@ import { EVIDENCE_STANCE, type EvidenceStance } from '../config/verification'; * uses — so an unknown stance is rejected here with a helpful message rather than * being silently dropped downstream. */ -export type ParseResult = - | { success: true; data: T } - | { success: false; error: string }; +export type ParseResult = { success: true; data: T } | { success: false; error: string }; export interface VerifyRequest { evidence: ReadonlyArray<{ stance: EvidenceStance }>;