|
| 1 | +<p align="center"> |
| 2 | + <h1 align="center">doxy</h1> |
| 3 | + <p align="center"> |
| 4 | + Static API compatibility verifier for JavaScript & TypeScript |
| 5 | + <br /> |
| 6 | + <strong>Catch deprecated, removed, and future APIs at lint time — before they break at runtime.</strong> |
| 7 | + </p> |
| 8 | +</p> |
| 9 | + |
| 10 | +<p align="center"> |
| 11 | + <a href="#installation">Installation</a> • |
| 12 | + <a href="#quick-start">Quick Start</a> • |
| 13 | + <a href="#cli-reference">CLI Reference</a> • |
| 14 | + <a href="#configuration">Configuration</a> • |
| 15 | + <a href="#how-it-works">How It Works</a> |
| 16 | +</p> |
| 17 | + |
| 18 | +<p align="center"> |
| 19 | + <img alt="License" src="https://img.shields.io/badge/license-MIT-blue.svg" /> |
| 20 | + <img alt="Node" src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg" /> |
| 21 | + <img alt="TypeScript" src="https://img.shields.io/badge/typescript-5.7-blue.svg" /> |
| 22 | + <img alt="Status" src="https://img.shields.io/badge/status-alpha-orange.svg" /> |
| 23 | +</p> |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +Think of doxy as **"caniuse for npm packages"** — it reads your lockfile versions and curated API data to find mismatches at lint time, with zero runtime cost. |
| 28 | + |
| 29 | +``` |
| 30 | +$ doxy verify |
| 31 | +
|
| 32 | + src/App.tsx |
| 33 | + 5:17 warning react.createFactory is deprecated since 16.13.0. deprecated-api dxy_a1b2c3d4 |
| 34 | + Use React.createElement or JSX instead. |
| 35 | + 11:18 warning react-dom.findDOMNode is deprecated since 16.6.0. deprecated-api dxy_e5f6a7b8 |
| 36 | + Use refs instead. |
| 37 | +
|
| 38 | + src/Dashboard.tsx |
| 39 | + 3:14 error react.useId is not available in 17.0.2. future-api dxy_c9d0e1f2 |
| 40 | + It was added in 18.0.0. |
| 41 | +
|
| 42 | + 3 findings (1 error, 2 warnings) |
| 43 | +``` |
| 44 | + |
| 45 | +## Why doxy? |
| 46 | + |
| 47 | +| Problem | Without doxy | With doxy | |
| 48 | +|---|---|---| |
| 49 | +| Using a deprecated API | Discover at code review (maybe) | Caught at lint time | |
| 50 | +| Calling a removed API after upgrade | Runtime crash in production | Caught before deploy | |
| 51 | +| Using an API from a newer version | `undefined is not a function` | Clear error with version info | |
| 52 | +| Wrong number of arguments | Subtle bugs, silent failures | Caught with expected arity | |
| 53 | + |
| 54 | +## Features |
| 55 | + |
| 56 | +- **Deprecated API detection** — warns when you use APIs deprecated in your installed version |
| 57 | +- **Removed API detection** — errors when you use APIs removed in your installed version |
| 58 | +- **Future API detection** — errors when you use APIs that require a newer version than installed |
| 59 | +- **Wrong arity detection** — errors when you call functions with the wrong number of arguments |
| 60 | +- **Incremental analysis** — only re-analyzes changed files using git diff + content hashing |
| 61 | +- **Inline suppression** — silence specific findings with `// doxy-ignore` comments |
| 62 | +- **Config-level suppression** — suppress patterns project-wide with glob-based rules |
| 63 | +- **Multiple output formats** — human-readable, JSON, JSONL, SARIF |
| 64 | +- **Framework-aware** — understands React/Next.js import patterns and re-exports |
| 65 | +- **Fast** — powered by SWC for parsing (~100x faster than TypeScript compiler) |
| 66 | + |
| 67 | +## Installation |
| 68 | + |
| 69 | +```bash |
| 70 | +npm install --save-dev doxy |
| 71 | +``` |
| 72 | + |
| 73 | +```bash |
| 74 | +pnpm add -D doxy |
| 75 | +``` |
| 76 | + |
| 77 | +```bash |
| 78 | +yarn add -D doxy |
| 79 | +``` |
| 80 | + |
| 81 | +> **Requirements:** Node.js >= 18 |
| 82 | +
|
| 83 | +## Quick Start |
| 84 | + |
| 85 | +```bash |
| 86 | +# Run verification on your project |
| 87 | +npx doxy verify |
| 88 | + |
| 89 | +# Only check changed files (great for CI) |
| 90 | +npx doxy verify --changed |
| 91 | + |
| 92 | +# Output as JSON for tooling integration |
| 93 | +npx doxy verify --json |
| 94 | + |
| 95 | +# Get detailed info about a specific finding |
| 96 | +npx doxy explain dxy_a1b2c3d4 |
| 97 | +``` |
| 98 | + |
| 99 | +## CLI Reference |
| 100 | + |
| 101 | +### Commands |
| 102 | + |
| 103 | +| Command | Description | |
| 104 | +|---|---| |
| 105 | +| `doxy verify [files...]` | Run verification (default command) | |
| 106 | +| `doxy init` | Initialize doxy in your project | |
| 107 | +| `doxy explain <finding-id>` | Detailed explanation of a finding | |
| 108 | +| `doxy cache status` | Show cache statistics | |
| 109 | +| `doxy cache clear` | Delete cached data | |
| 110 | +| `doxy authority list` | List loaded authority packages | |
| 111 | +| `doxy authority update` | Pull latest authority data | |
| 112 | +| `doxy authority show <pkg> [export]` | Inspect authority data for a package | |
| 113 | +| `doxy fix [files...]` | Apply auto-fixes | |
| 114 | + |
| 115 | +### Verify Flags |
| 116 | + |
| 117 | +| Flag | Description | |
| 118 | +|---|---| |
| 119 | +| `--json` | Output findings as JSON | |
| 120 | +| `--jsonl` | Output findings as newline-delimited JSON | |
| 121 | +| `--sarif` | Output findings in SARIF format | |
| 122 | +| `--severity <level>` | Minimum severity to report (default: `warning`) | |
| 123 | +| `--fail-on <level>` | Exit non-zero threshold (default: `error`) | |
| 124 | +| `--changed` | Only analyze changed files | |
| 125 | +| `--base <ref>` | Git ref for diff base | |
| 126 | +| `--no-cache` | Disable caching | |
| 127 | +| `--framework <name@version>` | Override framework detection | |
| 128 | +| `--save-baseline` | Save current findings as baseline | |
| 129 | +| `--update-baseline` | Update baseline to current findings | |
| 130 | +| `--include-baseline` | Show baseline findings in output | |
| 131 | +| `--include-suppressed` | Show suppressed findings in output | |
| 132 | + |
| 133 | +### Exit Codes |
| 134 | + |
| 135 | +| Code | Meaning | |
| 136 | +|---|---| |
| 137 | +| `0` | No findings at or above `--fail-on` severity | |
| 138 | +| `1` | Findings exist at or above `--fail-on` severity | |
| 139 | +| `2` | Configuration error | |
| 140 | +| `3` | Project error (can't read project) | |
| 141 | +| `4` | Authority data error | |
| 142 | +| `5` | Internal error | |
| 143 | + |
| 144 | +## Configuration |
| 145 | + |
| 146 | +Create a `doxy.config.json` in your project root: |
| 147 | + |
| 148 | +```json |
| 149 | +{ |
| 150 | + "include": ["src/**/*.{ts,tsx,js,jsx}"], |
| 151 | + "exclude": ["**/*.test.*", "**/*.spec.*"], |
| 152 | + "severity": "warning", |
| 153 | + "failOn": "error", |
| 154 | + "frameworks": {}, |
| 155 | + "pathAliases": {}, |
| 156 | + "suppressions": [], |
| 157 | + "requireSuppressionReason": false, |
| 158 | + "authorityDataSources": ["builtin"] |
| 159 | +} |
| 160 | +``` |
| 161 | + |
| 162 | +### Suppression Rules |
| 163 | + |
| 164 | +Suppress findings project-wide using config rules: |
| 165 | + |
| 166 | +```json |
| 167 | +{ |
| 168 | + "suppressions": [ |
| 169 | + { |
| 170 | + "paths": ["src/legacy/**"], |
| 171 | + "kind": "deprecated-api", |
| 172 | + "reason": "Legacy module — migrating to new APIs in Q2" |
| 173 | + }, |
| 174 | + { |
| 175 | + "package": "react", |
| 176 | + "export": "findDOMNode", |
| 177 | + "kind": "*", |
| 178 | + "reason": "Used in legacy adapter, isolated and tested" |
| 179 | + } |
| 180 | + ] |
| 181 | +} |
| 182 | +``` |
| 183 | + |
| 184 | +### Inline Suppression |
| 185 | + |
| 186 | +Suppress individual findings directly in code: |
| 187 | + |
| 188 | +```tsx |
| 189 | +// Suppress the next line |
| 190 | +// doxy-ignore deprecated-api -- Legacy compat layer |
| 191 | +const factory = createFactory("div"); |
| 192 | + |
| 193 | +// Suppress current line |
| 194 | +const node = findDOMNode(this); // doxy-ignore-line deprecated-api |
| 195 | + |
| 196 | +// Suppress a block |
| 197 | +/* doxy-ignore-start deprecated-api -- Entire legacy section */ |
| 198 | +const a = createFactory("div"); |
| 199 | +const b = createFactory("span"); |
| 200 | +/* doxy-ignore-end */ |
| 201 | +``` |
| 202 | + |
| 203 | +## How It Works |
| 204 | + |
| 205 | +``` |
| 206 | +Source files ─┐ |
| 207 | + ├─► SWC Parser ─► Import Resolver ─► Authority Store Query ─► Findings |
| 208 | +Lockfile ─────┘ │ │ │ |
| 209 | + │ │ │ |
| 210 | + Normalized AST SymbolUsage[] Version-aware lookup |
| 211 | + (deprecated? removed? |
| 212 | + future? wrong arity?) |
| 213 | +``` |
| 214 | + |
| 215 | +1. **Parse** — SWC parses your source files into a normalized AST |
| 216 | +2. **Resolve** — Import resolver maps `import` statements to package/export pairs |
| 217 | +3. **Query** — Each symbol is checked against curated authority data for your installed version |
| 218 | +4. **Emit** — Findings are generated with severity, messages, and fix suggestions |
| 219 | +5. **Filter** — Inline and config-level suppressions are applied |
| 220 | +6. **Cache** — Results are cached per-file with smart invalidation |
| 221 | + |
| 222 | +doxy never executes your code. It reads your lockfile for installed versions and uses curated API specifications to detect issues statically. |
| 223 | + |
| 224 | +## Supported Frameworks |
| 225 | + |
| 226 | +| Framework | Status | Packages | |
| 227 | +|---|---|---| |
| 228 | +| React | Supported | `react`, `react-dom` | |
| 229 | +| Next.js | Planned | `next` | |
| 230 | + |
| 231 | +Authority data currently covers **27 API specs** across React and ReactDOM, including hooks, lifecycle methods, rendering APIs, and more. |
| 232 | + |
| 233 | +## Finding Kinds |
| 234 | + |
| 235 | +| Kind | Severity | Description | |
| 236 | +|---|---|---| |
| 237 | +| `deprecated-api` | warning | API is deprecated in your installed version | |
| 238 | +| `removed-api` | error | API was removed in your installed version | |
| 239 | +| `future-api` | error | API requires a newer version than installed | |
| 240 | +| `wrong-arity` | error | Function called with wrong number of arguments | |
| 241 | +| `wrong-param` | error | Function called with wrong parameter names | |
| 242 | +| `unknown-export` | info | Export not found in authority data | |
| 243 | + |
| 244 | +## CI Integration |
| 245 | + |
| 246 | +```yaml |
| 247 | +# GitHub Actions |
| 248 | +- name: Check API compatibility |
| 249 | + run: npx doxy verify --fail-on error |
| 250 | +``` |
| 251 | +
|
| 252 | +```yaml |
| 253 | +# With JSON output for annotations |
| 254 | +- name: Check API compatibility |
| 255 | + run: npx doxy verify --json > doxy-results.json |
| 256 | +``` |
| 257 | +
|
| 258 | +doxy writes **findings to stdout** and **everything else to stderr**, making it easy to pipe and parse output in CI pipelines. |
| 259 | +
|
| 260 | +## Contributing |
| 261 | +
|
| 262 | +Contributions are welcome! Here's how to get started: |
| 263 | +
|
| 264 | +```bash |
| 265 | +git clone https://github.com/your-username/doxy.git |
| 266 | +cd doxy |
| 267 | +npm install |
| 268 | +npm run check # typecheck + lint + test |
| 269 | +``` |
| 270 | + |
| 271 | +### Project Structure |
| 272 | + |
| 273 | +``` |
| 274 | +doxy/ |
| 275 | +├── src/ |
| 276 | +│ ├── cli/ CLI entry point + commands |
| 277 | +│ ├── core/ Pure analysis logic |
| 278 | +│ │ ├── types/ All shared type definitions |
| 279 | +│ │ ├── repo-context/ Version detection from manifests |
| 280 | +│ │ ├── import-resolver/ Import → package/export mapping |
| 281 | +│ │ ├── suppression/ Inline + config suppression |
| 282 | +│ │ └── analyzer/ Per-file analysis orchestration |
| 283 | +│ ├── authority/ Authority data store |
| 284 | +│ ├── adapters/ Framework-specific adapters |
| 285 | +│ ├── parser/ SWC-based AST parsing |
| 286 | +│ └── incremental/ Git diff + caching |
| 287 | +├── authority-data/ Curated API spec datasets |
| 288 | +└── fixtures/ Test fixture mini-projects |
| 289 | +``` |
| 290 | + |
| 291 | +### Running Tests |
| 292 | + |
| 293 | +```bash |
| 294 | +npm test # run all tests |
| 295 | +npm run test:watch # watch mode |
| 296 | +npm run typecheck # type check only |
| 297 | +npm run lint # lint only |
| 298 | +npm run check # all of the above |
| 299 | +``` |
| 300 | + |
| 301 | +## License |
| 302 | + |
| 303 | +[MIT](./LICENSE) |
0 commit comments