react-native-doctor-ci 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -22
- package/dist/cli.cjs +84 -4
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +84 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +82 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +82 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# react-native-doctor-ci
|
|
2
2
|
|
|
3
|
-
Fail pull requests that add abandoned, non-New-Architecture, or npm-deprecated React Native dependencies
|
|
3
|
+
Fail pull requests that add abandoned, non-New-Architecture, or npm-deprecated React Native dependencies — with inline annotations and a policy-as-code allowlist.
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
@@ -11,9 +11,9 @@ Fail pull requests that add abandoned, non-New-Architecture, or npm-deprecated R
|
|
|
11
11
|
|
|
12
12
|
## Why
|
|
13
13
|
|
|
14
|
-
Unmaintained dependencies are a perennial top-5 pain in React Native surveys, and the cost keeps climbing now that the New Architecture is the default: a package that looked fine when it was added quietly stops getting releases, never gains New Architecture support, or gets deprecated on npm
|
|
14
|
+
Unmaintained dependencies are a perennial top-5 pain in React Native surveys, and the cost keeps climbing now that the New Architecture is the default: a package that looked fine when it was added quietly stops getting releases, never gains New Architecture support, or gets deprecated on npm — and you find out during an upgrade, months after the PR that introduced it merged.
|
|
15
15
|
|
|
16
|
-
Lookup tools exist (the React Native Directory tells you a package's status if you go ask). What's been missing is **enforcement**: the check that runs on every PR, fails when someone adds a dying dependency, and points at the exact line
|
|
16
|
+
Lookup tools exist (the React Native Directory tells you a package's status if you go ask). What's been missing is **enforcement**: the check that runs on every PR, fails when someone adds a dying dependency, and points at the exact line — so the conversation happens at review time, when swapping the package costs five minutes instead of a quarter.
|
|
17
17
|
|
|
18
18
|
`rn-doctor` is that check. Pure TypeScript, zero native code, one command.
|
|
19
19
|
|
|
@@ -40,7 +40,7 @@ jobs:
|
|
|
40
40
|
with:
|
|
41
41
|
fetch-depth: 0 # required for changed-only (merge-base diff)
|
|
42
42
|
|
|
43
|
-
- uses: AmrithVengalath/react-native-doctor-ci/action@v0.1.
|
|
43
|
+
- uses: AmrithVengalath/react-native-doctor-ci/action@v0.1.1
|
|
44
44
|
with:
|
|
45
45
|
changed-only: "true"
|
|
46
46
|
base: origin/${{ github.base_ref }}
|
|
@@ -61,7 +61,7 @@ npx --yes --package react-native-doctor-ci rn-doctor
|
|
|
61
61
|
## GitHub Action reference
|
|
62
62
|
|
|
63
63
|
```yaml
|
|
64
|
-
- uses: AmrithVengalath/react-native-doctor-ci/action@v0.1.
|
|
64
|
+
- uses: AmrithVengalath/react-native-doctor-ci/action@v0.1.1
|
|
65
65
|
with:
|
|
66
66
|
version: "0.1.0" # npm version/dist-tag to run (default: latest)
|
|
67
67
|
policy: ".rn-doctor.yml" # policy file path (default: auto-detect)
|
|
@@ -76,8 +76,8 @@ npx --yes --package react-native-doctor-ci rn-doctor
|
|
|
76
76
|
|
|
77
77
|
Notes:
|
|
78
78
|
|
|
79
|
-
- `changed-only` requires `actions/checkout` with `fetch-depth: 0`
|
|
80
|
-
- The default `token` (the workflow's own `GITHUB_TOKEN`) is enough; it's only used to read public repo metadata (archived state, last push). Without any token those fields degrade to `unknown` with a warning
|
|
79
|
+
- `changed-only` requires `actions/checkout` with `fetch-depth: 0` — the diff is computed against the merge-base of the PR branch and `base`, same as GitHub's three-dot compare. Without history the run fails with an actionable message telling you exactly that.
|
|
80
|
+
- The default `token` (the workflow's own `GITHUB_TOKEN`) is enough; it's only used to read public repo metadata (archived state, last push). Without any token those fields degrade to `unknown` with a warning — the run never fails because of rate limits.
|
|
81
81
|
- Pin `version` for reproducible CI; `latest` is convenient but floats.
|
|
82
82
|
|
|
83
83
|
## CLI reference
|
|
@@ -98,7 +98,7 @@ rn-doctor [options]
|
|
|
98
98
|
-h, --help Show help
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
**Exit codes** (stable contract
|
|
101
|
+
**Exit codes** (stable contract — CI depends on it):
|
|
102
102
|
|
|
103
103
|
| Code | Meaning |
|
|
104
104
|
| ---- | ------- |
|
|
@@ -108,7 +108,7 @@ rn-doctor [options]
|
|
|
108
108
|
|
|
109
109
|
**Environment**: `GITHUB_TOKEN` (optional, enables GitHub repo enrichment), `NO_COLOR` (disables ANSI color), `GITHUB_ACTIONS=true` (auto-enables annotations).
|
|
110
110
|
|
|
111
|
-
Only `dependencies` are checked
|
|
111
|
+
Only `dependencies` are checked — `devDependencies` never ship in your app.
|
|
112
112
|
|
|
113
113
|
## Policy: `.rn-doctor.yml`
|
|
114
114
|
|
|
@@ -132,9 +132,9 @@ allow: [] # see "Unblocking a PR" below
|
|
|
132
132
|
|
|
133
133
|
Each rule takes `error | warn | off` (except `lastPublish`, which takes thresholds or `"off"`).
|
|
134
134
|
|
|
135
|
-
**How the data is gathered.** Each dependency is enriched in parallel from the npm registry (publish time, deprecation, `codegenConfig`), the [React Native Directory](https://reactnative.directory) (New Architecture support, unmaintained flag, GitHub URL), and the GitHub API (archived, last push
|
|
135
|
+
**How the data is gathered.** Each dependency is enriched in parallel from the npm registry (publish time, deprecation, `codegenConfig`), the [React Native Directory](https://reactnative.directory) (New Architecture support, unmaintained flag, GitHub URL), and the GitHub API (archived, last push — token optional). Results are cached in `.rn-doctor-cache.json` for 24 hours (add it to `.gitignore`; `--no-cache` bypasses).
|
|
136
136
|
|
|
137
|
-
**New Architecture verdicts** are tiered honestly: directory says supported
|
|
137
|
+
**New Architecture verdicts** are tiered honestly: directory says supported → pass; directory says unsupported → `newArchitecture` fires; unknown but the package ships `codegenConfig` → pass with an informational note; unknown otherwise → `newArchUnknown` fires (a warning by default — missing data is not the same as a dead package).
|
|
138
138
|
|
|
139
139
|
**Scope.** `rn-native-only` (default) checks packages that actually couple to React Native: listed in the RN Directory, peer-depend on `react-native`, or ship `android`/`ios` directories. `all-deps` checks everything under `dependencies`.
|
|
140
140
|
|
|
@@ -149,14 +149,14 @@ allow:
|
|
|
149
149
|
expires: 2027-01-31
|
|
150
150
|
```
|
|
151
151
|
|
|
152
|
-
- Suppressed findings still appear in output (marked as allowed)
|
|
152
|
+
- Suppressed findings still appear in output (marked as allowed) — nothing disappears silently.
|
|
153
153
|
- `expires` is optional but recommended: past that date the allow stops suppressing and findings **escalate to errors**, so exceptions can't quietly outlive their justification.
|
|
154
154
|
- Every finding's message suggests the exact allowlist entry to add, so unblocking is copy-paste.
|
|
155
155
|
|
|
156
156
|
## Output formats
|
|
157
157
|
|
|
158
|
-
- **Pretty** (default): one block per finding
|
|
159
|
-
- **`--json`**: stable-ordered, timestamp-free (`version: 1`)
|
|
158
|
+
- **Pretty** (default): one block per finding — severity badge, message, allow-reason if suppressed, and an evidence link (npm/directory/GitHub) so you can verify every claim.
|
|
159
|
+
- **`--json`**: stable-ordered, timestamp-free (`version: 1`) — safe to snapshot or post-process.
|
|
160
160
|
- **`--sarif`**: SARIF 2.1.0, validates against the official schema. Upload to GitHub code scanning:
|
|
161
161
|
|
|
162
162
|
```yaml
|
|
@@ -167,30 +167,30 @@ allow:
|
|
|
167
167
|
sarif_file: rn-doctor.sarif
|
|
168
168
|
```
|
|
169
169
|
|
|
170
|
-
- **GitHub annotations**: emitted automatically inside GitHub Actions, resolved to the dependency's real line in `package.json` (string-escape-aware
|
|
170
|
+
- **GitHub annotations**: emitted automatically inside GitHub Actions, resolved to the dependency's real line in `package.json` (string-escape-aware — a same-named key under `scripts` can't false-match).
|
|
171
171
|
|
|
172
172
|
## Changed-only and monorepos
|
|
173
173
|
|
|
174
|
-
`--changed-only` is the flagship PR mode: it diffs `dependencies` against the merge-base with `--base` and checks only additions and spec changes (downgrades and protocol changes count too
|
|
174
|
+
`--changed-only` is the flagship PR mode: it diffs `dependencies` against the merge-base with `--base` and checks only additions and spec changes (downgrades and protocol changes count too — they're re-checked). Fast, and zero noise from pre-existing debt: adopting rn-doctor on a 5-year-old app doesn't mean fixing 30 findings before the check goes green.
|
|
175
175
|
|
|
176
176
|
`--workspaces` walks npm/yarn `workspaces` globs or `pnpm-workspace.yaml` and checks every workspace manifest, with findings grouped per manifest and annotations pointing at the right file. Composes with `--changed-only`.
|
|
177
177
|
|
|
178
178
|
## FAQ
|
|
179
179
|
|
|
180
|
-
**Does it check devDependencies?** No
|
|
180
|
+
**Does it check devDependencies?** No — they don't ship in your app. Scope decisions live in the policy file, not flags.
|
|
181
181
|
|
|
182
182
|
**Is it a security scanner?** No. CVE auditing is `npm audit` / OSV territory. rn-doctor answers a different question: *is this dependency alive and does it have a future on the New Architecture?*
|
|
183
183
|
|
|
184
|
-
**Does it fix anything?** No
|
|
184
|
+
**Does it fix anything?** No — it tells you what's wrong and what to do (allowlist entry, `npx expo install --fix`, Renovate), then gets out of the way.
|
|
185
185
|
|
|
186
|
-
**What if the RN Directory is wrong about a package?** Every finding carries an evidence link so you can check, and a false positive costs one allowlist line. File a correction with the directory
|
|
186
|
+
**What if the RN Directory is wrong about a package?** Every finding carries an evidence link so you can check, and a false positive costs one allowlist line. File a correction with the directory — everyone benefits.
|
|
187
187
|
|
|
188
|
-
**Why is `yaml` the only runtime dependency?** The policy file and `pnpm-workspace.yaml` are YAML, and a spec-compliant YAML parser is not a weekend project
|
|
188
|
+
**Why is `yaml` the only runtime dependency?** The policy file and `pnpm-workspace.yaml` are YAML, and a spec-compliant YAML parser is not a weekend project — this one is worth its weight. Everything else (HTTP, caching, git diffing, glob matching, SARIF, annotations) is hand-rolled on Node built-ins; less supply chain in a tool whose whole job is judging dependencies.
|
|
189
189
|
|
|
190
190
|
## Contributing
|
|
191
191
|
|
|
192
|
-
Issues and PRs welcome
|
|
192
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). The project follows a phased roadmap; out-of-scope items (security auditing, auto-fixing, a hosted service) are listed there.
|
|
193
193
|
|
|
194
194
|
## License
|
|
195
195
|
|
|
196
|
-
[MIT](LICENSE)
|
|
196
|
+
[MIT](LICENSE) © Amrith Vengalath
|
package/dist/cli.cjs
CHANGED
|
@@ -117,6 +117,89 @@ async function mapWithConcurrency(items, fn, concurrency = 8) {
|
|
|
117
117
|
return results;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
// package.json
|
|
121
|
+
var package_default = {
|
|
122
|
+
name: "react-native-doctor-ci",
|
|
123
|
+
version: "0.1.1",
|
|
124
|
+
description: "Policy-as-code CI gate for React Native dependency health: fail PRs that add abandoned, non-New-Architecture, or npm-deprecated dependencies.",
|
|
125
|
+
keywords: [
|
|
126
|
+
"react-native",
|
|
127
|
+
"ci",
|
|
128
|
+
"dependencies",
|
|
129
|
+
"new-architecture",
|
|
130
|
+
"policy",
|
|
131
|
+
"lint",
|
|
132
|
+
"github-actions",
|
|
133
|
+
"sarif"
|
|
134
|
+
],
|
|
135
|
+
license: "MIT",
|
|
136
|
+
author: "Amrith Vengalath",
|
|
137
|
+
repository: {
|
|
138
|
+
type: "git",
|
|
139
|
+
url: "git+https://github.com/AmrithVengalath/react-native-doctor-ci.git"
|
|
140
|
+
},
|
|
141
|
+
homepage: "https://github.com/AmrithVengalath/react-native-doctor-ci#readme",
|
|
142
|
+
bugs: "https://github.com/AmrithVengalath/react-native-doctor-ci/issues",
|
|
143
|
+
type: "module",
|
|
144
|
+
bin: {
|
|
145
|
+
"rn-doctor": "./dist/cli.js"
|
|
146
|
+
},
|
|
147
|
+
exports: {
|
|
148
|
+
".": {
|
|
149
|
+
types: "./dist/index.d.ts",
|
|
150
|
+
import: "./dist/index.js",
|
|
151
|
+
require: "./dist/index.cjs"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
main: "./dist/index.cjs",
|
|
155
|
+
module: "./dist/index.js",
|
|
156
|
+
types: "./dist/index.d.ts",
|
|
157
|
+
files: [
|
|
158
|
+
"dist"
|
|
159
|
+
],
|
|
160
|
+
engines: {
|
|
161
|
+
node: ">=20"
|
|
162
|
+
},
|
|
163
|
+
packageManager: "pnpm@11.11.0",
|
|
164
|
+
publishConfig: {
|
|
165
|
+
access: "public",
|
|
166
|
+
provenance: true
|
|
167
|
+
},
|
|
168
|
+
scripts: {
|
|
169
|
+
typecheck: "tsc --noEmit",
|
|
170
|
+
lint: "eslint .",
|
|
171
|
+
"lint:fix": "eslint . --fix",
|
|
172
|
+
test: "vitest run",
|
|
173
|
+
"test:watch": "vitest",
|
|
174
|
+
"test:cov": "vitest run --coverage",
|
|
175
|
+
build: "tsup",
|
|
176
|
+
dev: "tsup --watch",
|
|
177
|
+
prepublishOnly: "pnpm run build",
|
|
178
|
+
release: "release-it"
|
|
179
|
+
},
|
|
180
|
+
devDependencies: {
|
|
181
|
+
"@eslint/js": "^10.0.1",
|
|
182
|
+
"@release-it/conventional-changelog": "^11.0.1",
|
|
183
|
+
"@types/node": "^20.19.0",
|
|
184
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
185
|
+
ajv: "^8.20.0",
|
|
186
|
+
eslint: "^10.7.0",
|
|
187
|
+
jiti: "^2.7.0",
|
|
188
|
+
msw: "^2.15.0",
|
|
189
|
+
"release-it": "^20.2.1",
|
|
190
|
+
tsup: "^8.5.1",
|
|
191
|
+
typescript: "6.0.3",
|
|
192
|
+
"typescript-eslint": "^8.63.0",
|
|
193
|
+
vitest: "^4.1.10"
|
|
194
|
+
},
|
|
195
|
+
dependencies: {
|
|
196
|
+
yaml: "^2.9.0"
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// src/version.ts
|
|
201
|
+
var VERSION = package_default.version;
|
|
202
|
+
|
|
120
203
|
// src/http.ts
|
|
121
204
|
async function fetchJson(url, options = {}) {
|
|
122
205
|
const controller = new AbortController();
|
|
@@ -125,7 +208,7 @@ async function fetchJson(url, options = {}) {
|
|
|
125
208
|
try {
|
|
126
209
|
const response = await fetch(url, {
|
|
127
210
|
headers: {
|
|
128
|
-
"user-agent":
|
|
211
|
+
"user-agent": `rn-doctor/${VERSION}`,
|
|
129
212
|
...options.headers
|
|
130
213
|
},
|
|
131
214
|
signal: controller.signal
|
|
@@ -1223,9 +1306,6 @@ function renderPretty(report, options) {
|
|
|
1223
1306
|
`;
|
|
1224
1307
|
}
|
|
1225
1308
|
|
|
1226
|
-
// src/version.ts
|
|
1227
|
-
var VERSION = "0.0.0";
|
|
1228
|
-
|
|
1229
1309
|
// src/report-sarif.ts
|
|
1230
1310
|
var INFORMATION_URI = "https://www.npmjs.com/package/react-native-doctor-ci";
|
|
1231
1311
|
var RULE_IDS = [
|