native-doctor
v0.8.0
Published
An evidence-based project health scanner for React Native, Expo and React apps. Combines React Doctor & Native Doctor capabilities with AST symbol graphs, architecture analysis and official platform guidance.
Maintainers
Readme
native-doctor
Unified React & Native Project Intelligence Engine for React Native, Expo, and React apps.
Combines full React Doctor (Hooks rules, Component lifecycle, JSX reconciliation, State duplication) and Native Doctor (Android 14+ foreground services, Apple App Store privacy keys, Target SDK 34+, New Architecture, Audio state authority) into a single, unified static analysis tool.
Is this project implemented the official, minimal, platform-correct way — or does it carry unnecessary/legacy/AI-generated complexity?
Every finding answers:
- WHAT was found (precise file location and line numbers)
- WHY it is a problem (coupling, performance, security, architecture)
- OFFICIAL platform requirement / guideline (React, React Native, Android, Apple, Expo)
- DO NOT guidance (explicit warnings on what anti-patterns NOT to add)
- FIX (the smallest direct change, with safe
--fixautomation where possible) - PRIORITY (P0 Critical $\rightarrow$ P1 Warning $\rightarrow$ P2 Tech Debt $\rightarrow$ P3 Complexity Review)
Quick Execution
# Unified React + React Native scan
npx native-doctor@latest
# Deep architectural graph & target roadmap
npx native-doctor@latest --deep
# Focus specifically on React core & hooks (React Doctor mode)
npx native-doctor@latest --react
# Focus specifically on Native config & permissions (Native Doctor mode)
npx native-doctor@latest --native
# Auto-fix safe issues
npx native-doctor@latest --fixnative-doctor --performance native-doctor --accessibility native-doctor --native native-doctor --audio --plan
Run without interactive TTY prompt
native-doctor --no-interactive
---
## Diagnostic Rules Catalog (v0.1.0)
| Category | Rule ID | What It Checks |
|---|---|---|
| **ui** | `RNDOCTOR-UI-021` | `TouchableOpacity` usage that should migrate to `Pressable` |
| **accessibility** | `RNDOCTOR-A11Y-001` | Self-closing interactive touchables missing `accessibilityLabel` |
| **code** | `RNDOCTOR-CODE-040` | Scope-analyzed unused imports (with zero false-positives on React JSX runtime) |
| **code** | `RNDOCTOR-CODE-050` | `console.*` debug statements left in application code |
| **code** | `RNDOCTOR-PLATFORM-010` | Heavy inline `Platform.OS` branching that should move to `.ios.js` / `.android.js` |
| **code** | `RNDOCTOR-CODE-110` | Unnecessary `useMemo` / `useCallback` with empty deps and a trivial body |
| **code** | `RNDOCTOR-CODE-103` | Direct `async` callback passed to `useEffect` (unhandled promise leak) |
| **code** | `RNDOCTOR-CODE-104` | `useState` + `useEffect` loading state boilerplate tracking a single async call |
| **code** | `RNDOCTOR-PERF-011` | Uncontrolled `setInterval` timer polling |
| **correctness** | `RNDOCTOR-SYNTAX-001` | Syntax or AST parse errors in JavaScript / TypeScript / JSX files |
| **architecture** | `RNDOCTOR-FILE-031` | `services/`, `utils/`, or `api/` layers importing UI screens or navigation |
| **architecture** | `RNDOCTOR-ARCH-001` | Circular module import cycles across source files |
| **architecture** | `AUDIO-ARCH-001` | Overlapping playback-state authority across multiple modules |
| **architecture** | `AUDIO-IOS-003` | Multiple `AVAudioSession` configurations across native iOS files |
| **native** | `RNDOCTOR-NATIVE-005` | Android native modules extending legacy `ReactContextBaseJavaModule` |
| **native** | `RNDOCTOR-NATIVE-017` | Android manifest permissions declared without matching dependencies |
| **native** | `RNDOCTOR-NATIVE-001` | Legacy Android storage permissions (`READ/WRITE_EXTERNAL_STORAGE`) |
| **native** | `RNDOCTOR-CONFIG-201` | Application / bundle ID mismatches between `app.json`, Android, and Xcode |
| **native** | `RNDOCTOR-NATIVE-030` | New Architecture flag mismatch across `app.json`, `gradle.properties`, and `Podfile` |
| **native** | `AUDIO-ANDROID-004` | Legacy Android `MediaPlayer` / `MediaExtractor` usage instead of Android Media3 |
| **security** | `RNDOCTOR-SECURITY-012` | Hardcoded API keys, private tokens, or secrets committed in client code |
| **security** | `RNDOCTOR-SECURITY-021` | Insecure non-localhost `http://` URLs in client code |
| **security** | `RNDOCTOR-ANDROID-SEC-002` | Android `usesCleartextTraffic='true'` enabled in release manifests |
| **dependencies** | `RNDOCTOR-DEP-001` | Known deprecated/renamed packages (e.g. `@react-native-community/async-storage`, `react-navigation`) |
| **dependencies** | `RNDOCTOR-DEP-010` | Packages accidentally listed in both `dependencies` and `devDependencies` |
| **config** | `RNDOCTOR-CONFIG-001` | Missing or invalid `package.json` |
| **config** | `RNDOCTOR-CONFIG-050` | Duplicate plugin/preset entries in `babel.config.js` |
| **config** | `RNDOCTOR-EXPO-001` | Expo dependency and native directories without root app configuration |
| **performance** | `AUDIO-PROGRESS-007` | Playback position interval polling and event subscriptions conflicting |
---
## Configuration (`native-doctor.config.json`)
You can customize rules and ignore files by creating a `native-doctor.config.json` in your project root:
```json
{
"ignore": [
"src/legacy/**",
"**/*.test.ts"
],
"rules": {
"RNDOCTOR-UI-021": "off",
"RNDOCTOR-CODE-050": "warning",
"RNDOCTOR-SECURITY-012": "error"
}
}Programmatic API
import { runScan, applyFixes, buildContext } from "native-doctor";
// Run scan on a directory
const report = await runScan({ dir: "./my-app" });
console.log(`Overall Health: ${report.score.overall}/100`);
console.log(`Found ${report.findings.length} findings.`);
// Apply safe AST fixes
const fixResults = applyFixes(report.findings);
console.log(`Applied ${fixResults.filter(f => f.applied).length} fixes.`);Architecture & Design Principles
- Deterministic AST First: Full parsing via
@babel/parserand@babel/traversewith TypeScript & JSX support. - Zero False Positives Priority: Rules account for JSX runtimes, dev configs, and platform branching.
- Safe AST Transformations:
--fixalters only exact AST ranges without regex corruption. - CI & Automation Ready: Non-zero exit code on errors, clean JSON reporting.
License
MIT
