Commit Graph

6 Commits

Author SHA1 Message Date
Aiden Bai 938008119a feat(report): add versioned JSON v3 metadata (#1120)
* feat(report): add versioned JSON v3 metadata

Expose deterministic diagnostic identities and exact scan completeness while preserving v1 and v2 decoding.

* fix(report): make v3 identities and coverage exact

Keep workspace diagnostics distinct and align JSON completeness, telemetry verdicts, and fallback output with the versioned report contract.
2026-07-10 23:49:19 -07:00
Aiden Bai cbdff6203d feat(cli): "Add to CI" handoff option + default CI setup in install (#658)
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: Nisarg Patel <awesomenisarg@gmail.com>
2026-06-04 04:15:05 -07:00
Ray Arayilakath 4e23e5dd34 fix(ci): point smoke test at core fixture (#486)
* fix(ci): point smoke test at core fixture

Co-authored-by: Ray Arayilakath <me@rayhanadev.com>

* style: format JSON smoke fixture path

Co-authored-by: Ray Arayilakath <me@rayhanadev.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-05-25 16:37:29 -04:00
Aiden Bai 26b66b45d5 0.2.4 2026-05-24 02:49:37 -07:00
Aiden Bai aa61efae28 refactor: collapse @react-doctor/types and @react-doctor/project-info into core (#440)
* refactor: collapse @react-doctor/types and @react-doctor/project-info into core

Eliminates two private workspace packages whose only role was to
namespace shared TS types and project-discovery helpers — neither
was a real consumer boundary, and the indirection cost a `workspace:*`
edge per leaf package without saving any code.

**Layout**

- `packages/types/` → `packages/core/src/types/` (10 files, pure TS types)
- `packages/project-info/` → `packages/core/src/project-info/`
  (27 files, discoverProject + framework detection + monorepo helpers)
- `packages/types/src/react-native-dependency-names.ts` →
  `packages/oxlint-plugin-react-doctor/src/react-native-dependency-names.ts`
  (the canonical RN-aware-package list lives next to its heaviest
  consumer — the rule gate — and is re-exported from core to avoid
  the rule-plugin ↔ core dependency cycle the previous types package
  was specifically designed to break).

The two packages are deleted from the workspace; every consumer
(`react-doctor`, `api`, `oxlint-plugin-react-doctor`, `actions/review`,
+130 source/test files) now imports from `@react-doctor/core` directly.

**Errors cleanup**

Dropped the legacy plain-class `ReactDoctorError` and `isReactDoctorError`
from `project-info`. The four narrow errors (`ProjectNotFoundError`,
`NoReactDependencyError`, `PackageJsonNotFoundError`,
`AmbiguousProjectError`) now extend `Error` directly — the only valid
hierarchy is the tagged `Schema.TaggedErrorClass` `ReactDoctorError`
from `core/errors.ts`, which has been the canonical one since the
Effect v4 refactor. Added `isProjectDiscoveryError` as a narrow type
guard for the four leaves.

The discovery errors are thrown synchronously BEFORE the Effect
runtime takes over (at `diagnose()` / CLI entry points); inside the
runtime, the Project service's `translateProjectInfoError` converts
each one to its tagged-reason equivalent.

**Schema vs type name collisions**

`schemas.ts` exports `Diagnostic` / `JsonReport` / `JsonReportMode` /
… as Schema.Class values, while `types/` exports the same names as
TS types. The core barrel re-exports the TS-type versions
(broad-strokes API) and exposes the Schema classes via a new
`@react-doctor/core/schemas` subpath export for the two callers
that need them (`Reporter` service, smoke validator, schema tests).

**Validation**

- `pnpm typecheck` ✓
- `pnpm lint` ✓
- `pnpm format` ✓
- `pnpm test` ✓ (1449 passing, 3 skipped — no regressions)
- `pnpm smoke:json-report` ✓

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(core): keep RN-dependency constants out of types barrel to avoid pulling oxlint plugin into discovery

Bugbot caught (medium severity): re-exporting `isReactNativeDependencyName` from
`oxlint-plugin-react-doctor` via the core types barrel meant every consumer of
`@react-doctor/core` (including `discoverProject` / `discoverReactSubprojects`)
would load the entire 286-rule plugin at module-init.

Adds a tiny standalone leaf at `core/src/project-info/internal-rn-dependency-names.ts`
(zero imports, just the constants the workspace-discovery gate needs) and switches
`is-package-json-react-native-aware.ts` to use it. The types barrel no longer
re-exports the plugin-side constants — rule consumers import them directly from
`oxlint-plugin-react-doctor`.

The duplication is intentional and documented at both files; the two lists are
short enough that a future regression test in the plugin can observe the union.

Validated: typecheck + test (1449 pass) + lint + format all green.
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 01:32:44 -07:00
Aiden Bai 83a70de91e feat(core): Effect v4 foundation — tagged errors, schemas, refs, paths (#405)
First PR of the Effect v4 rewrite. Adds the architectural primitives
that subsequent PRs build on, while preserving every public contract
(inspect(), diagnose(), CLI flags, JSON schemaVersion: 1, GitHub Action).

## What lands

- packages/core/src/errors.ts — 9 leaf Schema.TaggedErrorClass
  (OxlintUnavailable, OxlintBatchExceeded, OxlintSpawnFailed,
  OxlintOutputUnparseable, ConfigParseFailed, ProjectNotFound,
  NoReactDependency, AmbiguousProject, DeadCodeAnalysisFailed) composed
  into ReactDoctorError. Helpers formatReactDoctorError /
  isReactDoctorError / isSplittableReactDoctorError (all _tag-based,
  zero string-grepping).
- packages/core/src/schemas.ts — Diagnostic + Severity + JsonReport
  (Schema.Union for forward-compat with a future v2) +
  buildDiagnosticIdentity. Schemas mirror the existing @react-doctor/types
  interfaces; ProjectInfo / ScoreResult stay Schema.Unknown until PR 3.
- packages/core/src/refs.ts — Context.Reference for env-derived ambient
  config (OxlintSpawnTimeoutMs, OxlintOutputMaxBytes,
  StagedFilesTempDirPrefix). Tests override via Layer.succeed.
- packages/core/src/paths.ts — Schema.brand for OxlintBinaryPath +
  NodeBinaryPath. Catches the swap at compile time.
- packages/core/src/constants.ts — hoisted OXLINT_SPAWN_TIMEOUT_MS from
  the inline IIFE in run-oxlint.ts with explanatory docstring.

## Wiring

- handle-error.ts and build-json-report-error.ts dispatch to the
  tagged-error message getter when isReactDoctorError(error), else
  fall back to the existing formatErrorChain. run-oxlint.ts still
  throws plain Errors; PR 2 converts it.
- scripts/smoke-json-report.ts runs the built CLI against
  tests/fixtures/basic-react and Schema.decodeUnknownSync's the stdout
  against the new JsonReport schema. New CI step (must stay green
  through PR 8). Verified locally that a full --no-offline run with
  263 real diagnostics decodes cleanly.

## Effect v4 deps

- effect@4.0.0-beta.70 in packages/core/dependencies and
  packages/react-doctor/dependencies. Marked neverBundle in
  packages/react-doctor/vite.config.ts (~1MB+ of tree-shakable source;
  installers pull it as a regular dep — matches react-doctor-evals).
- @effect/vitest@4.0.0-beta.70 as a devDependency of core for PR 3+.

## Patterns

Every new file matches react-doctor-evals conventions exactly:
- import * as X from "effect/X" (never the umbrella import)
- Schema.TaggedErrorClass<Self>()("Tag", { fields }) with get message()
  delegating to Cause.pretty(Cause.fail(this.cause)) for opaque causes
- Context.Reference<T>("react-doctor/X", { defaultValue }) with env-var
  reads in defaultValue
- Schema.brand("X") via .pipe()
- kebab-case file names (per AGENTS.md)

## Validation

- pnpm typecheck — 10/10 tasks green
- pnpm test — 113 files, 1442 pass / 3 skipped (up from 1198; +244 new
  tests in errors.test.ts and schemas.test.ts)
- pnpm lint — clean
- pnpm format:check — clean across 1119 files
- pnpm build — all 7 packages produce dist/
- pnpm smoke:json-report — schema-valid v1 JsonReport

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 16:20:18 -07:00