@howells/lint 0.1.7 → 0.2.0

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/CONTEXT.md ADDED
@@ -0,0 +1,8 @@
1
+ # Context Glossary
2
+
3
+ ## Terms
4
+
5
+ ### Oxlint/Oxfmt lane
6
+
7
+ The project setup path that chooses Oxlint for linting and Oxfmt for formatting instead of Biome.
8
+
package/MIGRATIONS.md CHANGED
@@ -1,35 +1,51 @@
1
1
  # Adoption Notes
2
2
 
3
- Use these notes when replacing an existing ESLint, Prettier, Oxc, or ad hoc Biome setup with `@howells/lint`.
3
+ Use these notes when replacing an existing ESLint, Prettier, Oxlint/Oxfmt, or ad hoc Biome setup with `@howells/lint`.
4
4
 
5
5
  ## Primary rule
6
6
 
7
- Do not migrate an old local lint philosophy into a new local Biome override.
7
+ Do not migrate an old local lint philosophy into a new local override.
8
8
 
9
9
  Pick the closest shared preset first. Only add local config after you can explain why the repo is a real exception.
10
10
 
11
- ## Preset selection
11
+ ## Lane and preset selection
12
+
13
+ Choose one lane first, then choose the closest preset in that lane.
14
+
15
+ Biome lane:
12
16
 
13
17
  - Node or non-React TypeScript: `@howells/lint/biome/core`
14
18
  - React package or app without Next.js specifics: `@howells/lint/biome/react`
15
19
  - Next.js app: `@howells/lint/biome/next`
16
20
 
21
+ Oxlint/Oxfmt lane:
22
+
23
+ - Node or non-React TypeScript: `@howells/lint/oxlint/core`
24
+ - React package or app without Next.js specifics: `@howells/lint/oxlint/react`
25
+ - Next.js app: `@howells/lint/oxlint/next`
26
+
17
27
  If none of these fit cleanly, the likely answer is a new shared preset here, not a repo-specific fork.
18
28
 
19
29
  ## Migration steps
20
30
 
21
31
  1. Add `@howells/lint` as a dev dependency.
22
32
  2. Pin Node with `.node-version` set to `22.18.0` and `engines.node` set to `>=22.18.0`.
23
- 3. Replace `eslint`, `next lint`, `prettier`, or direct `biome` scripts with `howells-lint` and `howells-format`.
24
- 4. Replace the project `biome.json` or `biome.jsonc` with a minimal file that only extends one shared preset.
25
- 5. Remove direct `eslint`, `eslint-config-*`, `eslint-plugin-*`, `prettier`, `@biomejs/biome`, `oxlint`, `oxfmt`, `oxlint-tsgolint`, and `ultracite` dependencies once the project is green.
33
+ 3. Replace `eslint`, `next lint`, `prettier`, direct `biome`, or direct Oxlint/Oxfmt scripts with the chosen lane's package binaries.
34
+ 4. Replace local lint config with a minimal config that only extends one shared preset from the chosen lane.
35
+ 5. Remove direct `eslint`, `eslint-config-*`, `eslint-plugin-*`, `prettier`, `@biomejs/biome`, `oxlint`, `oxfmt`, `oxlint-tsgolint`, `ultracite`, `oxlint-plugin-react-doctor`, and `oxc-parser` dependencies once the project is green.
26
36
 
27
37
  ## Oxlint/Oxfmt opt-in
28
38
 
29
- Biome remains the default migration target. Use Oxlint/Oxfmt only for projects that deliberately choose the Oxc lane.
39
+ Biome remains the default migration target. Use Oxlint/Oxfmt only for projects that deliberately choose the Oxlint/Oxfmt lane. React and Next.js projects with real state, effects, architecture, or framework-boundary concerns are good candidates for that lane.
30
40
 
31
41
  For an Oxlint/Oxfmt project, add `oxlint.config.ts` and `oxfmt.config.ts` using the exports from `@howells/lint`, then use:
32
42
 
43
+ - `@howells/lint/oxlint/core` for Node or non-React TypeScript
44
+ - `@howells/lint/oxlint/react` for React (Ultracite React + React Doctor)
45
+ - `@howells/lint/oxlint/next` for Next.js (react preset + Next.js rules)
46
+
47
+ Each React or Next preset is self-contained. Extend only the closest preset — do not stack `core`, `react`, and `next` together.
48
+
33
49
  ```json
34
50
  {
35
51
  "scripts": {
@@ -43,7 +59,9 @@ Do not run Biome and Oxlint/Oxfmt together indefinitely. If both are present dur
43
59
 
44
60
  ## Keep local config thin
45
61
 
46
- The normal local config should look like this:
62
+ The normal local config should only extend the chosen lane's closest preset.
63
+
64
+ Biome lane:
47
65
 
48
66
  ```json
49
67
  {
@@ -51,6 +69,17 @@ The normal local config should look like this:
51
69
  }
52
70
  ```
53
71
 
72
+ Oxlint/Oxfmt lane:
73
+
74
+ ```ts
75
+ import { defineConfig } from "oxlint";
76
+ import next from "@howells/lint/oxlint/next";
77
+
78
+ export default defineConfig({
79
+ extends: [next],
80
+ });
81
+ ```
82
+
54
83
  Acceptable local additions:
55
84
 
56
85
  - repo-specific file includes or force-ignores for generated files that are unique to one project
@@ -59,7 +88,7 @@ Acceptable local additions:
59
88
 
60
89
  Avoid:
61
90
 
62
- - copying old ESLint rule customizations into Biome
91
+ - copying old ESLint rule customizations into the new lane
63
92
  - broad `linter.rules` sections to preserve team habit
64
93
  - local wrapper configs like `base.json` or `library.json`
65
94
  - repeating the same override across multiple repos
@@ -77,7 +106,9 @@ Do not normalize repeated local exceptions.
77
106
 
78
107
  ## Prefer scope in scripts
79
108
 
80
- If one repo only needs a narrower target, prefer script-level scope:
109
+ If one repo only needs a narrower target, prefer script-level scope.
110
+
111
+ Biome lane:
81
112
 
82
113
  ```json
83
114
  {
@@ -88,4 +119,15 @@ If one repo only needs a narrower target, prefer script-level scope:
88
119
  }
89
120
  ```
90
121
 
122
+ Oxlint/Oxfmt lane:
123
+
124
+ ```json
125
+ {
126
+ "scripts": {
127
+ "lint": "howells-ox-check apps/web packages/ui",
128
+ "lint:fix": "howells-ox-fix apps/web packages/ui"
129
+ }
130
+ }
131
+ ```
132
+
91
133
  That is usually better than teaching the config about the repo layout.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@howells/lint`
2
2
 
3
- Pinned Biome, Oxlint/Oxfmt, and Ultracite presets for Howells projects.
3
+ Pinned Biome, Oxlint/Oxfmt, Ultracite, and React Doctor presets for Howells projects.
4
4
 
5
5
  The goal is not to invent a second lint philosophy. The goal is to:
6
6
 
@@ -8,6 +8,7 @@ The goal is not to invent a second lint philosophy. The goal is to:
8
8
  - pin a single `oxlint` version
9
9
  - pin a single `oxfmt` version
10
10
  - pin a single `ultracite` version
11
+ - pin React Doctor's Oxlint plugin for React and Next.js projects on the Oxlint/Oxfmt lane
11
12
  - pin a single `@manypkg/cli` version for monorepo consistency checks
12
13
  - give every consumer the same small preset matrix
13
14
  - discourage repo-local overrides unless the project has a genuinely unique constraint
@@ -50,7 +51,7 @@ Install the shared tooling:
50
51
  pnpm add -D @howells/lint
51
52
  ```
52
53
 
53
- Do not add `@biomejs/biome`, `oxlint`, `oxfmt`, `oxlint-tsgolint`, `ultracite`, or `@manypkg/cli` directly unless you are developing this package itself. They are pinned transitively here.
54
+ Do not add `@biomejs/biome`, `oxlint`, `oxfmt`, `oxlint-tsgolint`, `ultracite`, `oxlint-plugin-react-doctor`, `oxc-parser`, or `@manypkg/cli` directly unless you are developing this package itself. They are pinned transitively here.
54
55
 
55
56
  ## Biome Presets
56
57
 
@@ -100,9 +101,15 @@ Next.js app:
100
101
 
101
102
  ## Oxlint/Oxfmt Presets
102
103
 
103
- Use this lane only when a project deliberately wants Oxlint and Oxfmt instead of Biome for day-to-day linting and formatting. The default `howells-lint` and `howells-format` commands stay on Biome.
104
+ Use this lane when a project wants Oxlint and Oxfmt instead of Biome. React and Next presets stack the relevant Ultracite Ox rules with [React Doctor](https://react.doctor) rules in one config.
104
105
 
105
- Create an `oxlint.config.ts`:
106
+ Choose the closest preset:
107
+
108
+ - `@howells/lint/oxlint/core` for Node or non-React TypeScript
109
+ - `@howells/lint/oxlint/react` for React (Ultracite React + React Doctor recommended rules)
110
+ - `@howells/lint/oxlint/next` for Next.js (react preset + Next.js rules)
111
+
112
+ Node or non-React TypeScript:
106
113
 
107
114
  ```ts
108
115
  import { defineConfig } from "oxlint";
@@ -113,16 +120,25 @@ export default defineConfig({
113
120
  });
114
121
  ```
115
122
 
116
- For React or Next.js projects, add the matching presets:
123
+ React package:
117
124
 
118
125
  ```ts
119
126
  import { defineConfig } from "oxlint";
120
- import core from "@howells/lint/oxlint/core";
121
127
  import react from "@howells/lint/oxlint/react";
128
+
129
+ export default defineConfig({
130
+ extends: [react],
131
+ });
132
+ ```
133
+
134
+ Next.js app:
135
+
136
+ ```ts
137
+ import { defineConfig } from "oxlint";
122
138
  import next from "@howells/lint/oxlint/next";
123
139
 
124
140
  export default defineConfig({
125
- extends: [core, react, next],
141
+ extends: [next],
126
142
  });
127
143
  ```
128
144
 
@@ -150,7 +166,9 @@ export default defineConfig({
150
166
 
151
167
  ## Package Scripts
152
168
 
153
- Every package or single-package app should use this shape:
169
+ Use scripts that match the lane the project has chosen.
170
+
171
+ Biome lane:
154
172
 
155
173
  ```json
156
174
  {
@@ -162,26 +180,28 @@ Every package or single-package app should use this shape:
162
180
  }
163
181
  ```
164
182
 
165
- Keep `lint` non-mutating. Put all `--write` behavior in `lint:fix` or `format` so CI and local checks have the same semantics.
166
-
167
- Prefer `howells-lint .` over raw `biome check` or long target lists. Use explicit script targets only when the package has a real scope constraint:
183
+ Oxlint/Oxfmt lane:
168
184
 
169
185
  ```json
170
186
  {
171
187
  "scripts": {
172
- "lint": "howells-lint apps/web packages/ui",
173
- "lint:fix": "howells-format apps/web packages/ui"
188
+ "lint": "howells-ox-check .",
189
+ "lint:fix": "howells-ox-fix ."
174
190
  }
175
191
  }
176
192
  ```
177
193
 
178
- For an Oxlint/Oxfmt project, keep the command names explicit:
194
+ The Oxlint/Oxfmt lane does not currently define a separate `lint:strict`; React Doctor's recommended rules are part of the normal Ox check.
195
+
196
+ Keep `lint` non-mutating. Put all write behavior in `lint:fix` or `format` so CI and local checks have the same semantics.
197
+
198
+ Prefer the package binaries over raw tool commands or long target lists. Use explicit script targets only when the package has a real scope constraint:
179
199
 
180
200
  ```json
181
201
  {
182
202
  "scripts": {
183
- "lint": "howells-ox-check .",
184
- "lint:fix": "howells-ox-fix ."
203
+ "lint": "howells-lint apps/web packages/ui",
204
+ "lint:fix": "howells-format apps/web packages/ui"
185
205
  }
186
206
  }
187
207
  ```
@@ -207,7 +227,7 @@ A monorepo root should have:
207
227
  "check": "pnpm lint && pnpm typecheck && pnpm test"
208
228
  },
209
229
  "devDependencies": {
210
- "@howells/lint": "^0.1.7"
230
+ "@howells/lint": "^0.2.0"
211
231
  }
212
232
  }
213
233
  ```
@@ -283,3 +303,4 @@ This package wraps:
283
303
  - [Oxlint configuration docs](https://oxc.rs/docs/guide/usage/linter/config-file-reference.html)
284
304
  - [Oxfmt configuration docs](https://oxc.rs/docs/guide/usage/formatter/config-file-reference)
285
305
  - [Ultracite configuration docs](https://www.ultracite.ai/configuration)
306
+ - [React Doctor docs](https://react.doctor/docs)
@@ -0,0 +1,34 @@
1
+ # 0001. Stack Ultracite and React Doctor on the Oxlint/Oxfmt Lane
2
+
3
+ ## Status
4
+
5
+ Accepted
6
+
7
+ ## Context
8
+
9
+ `@howells/lint` offers separate linting lanes. Projects choose the Biome lane or the Oxlint/Oxfmt lane; they do not run both indefinitely.
10
+
11
+ For React and Next.js projects on the Oxlint/Oxfmt lane, there are two useful rule sources:
12
+
13
+ - Ultracite's Oxlint presets, which provide broad JavaScript, TypeScript, React, accessibility, and framework rules.
14
+ - React Doctor's Oxlint plugin, which adds deeper React-specific rules for state, effects, architecture, performance, server boundaries, and framework behavior.
15
+
16
+ Some React Doctor rules overlap with Ultracite's React and accessibility rules. Filtering duplicates would reduce repeated diagnostics, but it would also require `@howells/lint` to maintain a reconciliation layer that could drift as either upstream package changes.
17
+
18
+ ## Decision
19
+
20
+ For React and Next.js projects on the Oxlint/Oxfmt lane, stack the relevant Ultracite Oxlint presets with React Doctor rules in one preset:
21
+
22
+ - `@howells/lint/oxlint/react` extends `ultracite/oxlint/core` and `ultracite/oxlint/react`, then adds React Doctor's recommended rules through `oxlint-plugin-react-doctor`.
23
+ - `@howells/lint/oxlint/next` extends the React preset and `ultracite/oxlint/next`, then adds React Doctor's Next.js rules.
24
+
25
+ Do not filter overlapping rules by default.
26
+
27
+ ## Consequences
28
+
29
+ Consumers get one Oxlint/Oxfmt lane preset for React and Next.js projects, with both Ultracite coverage and React Doctor coverage.
30
+
31
+ Some findings may be duplicate or near-duplicate when upstream rule sets overlap. This is acceptable because coverage is preferred over maintaining a local rule reconciliation matrix.
32
+
33
+ `@howells/lint` owns the pinned React Doctor Oxlint plugin and its parser compatibility dependency so consumer projects do not install them directly.
34
+
package/oxlint/next.mjs CHANGED
@@ -1 +1,9 @@
1
- export { default } from "ultracite/oxlint/next";
1
+ import { defineConfig } from "oxlint";
2
+ import { NEXTJS_RULES } from "oxlint-plugin-react-doctor";
3
+ import ultraciteNext from "ultracite/oxlint/next";
4
+ import react from "./react.mjs";
5
+
6
+ export default defineConfig({
7
+ extends: [react, ultraciteNext],
8
+ rules: NEXTJS_RULES,
9
+ });
package/oxlint/react.mjs CHANGED
@@ -1 +1,12 @@
1
- export { default } from "ultracite/oxlint/react";
1
+ import { defineConfig } from "oxlint";
2
+ import { RECOMMENDED_RULES } from "oxlint-plugin-react-doctor";
3
+ import core from "ultracite/oxlint/core";
4
+ import ultraciteReact from "ultracite/oxlint/react";
5
+
6
+ export default defineConfig({
7
+ extends: [core, ultraciteReact],
8
+ jsPlugins: [
9
+ { name: "react-doctor", specifier: "oxlint-plugin-react-doctor" },
10
+ ],
11
+ rules: RECOMMENDED_RULES,
12
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@howells/lint",
3
- "version": "0.1.7",
4
- "description": "Pinned Biome, Oxlint/Oxfmt, and Ultracite presets for Howells projects.",
3
+ "version": "0.2.0",
4
+ "description": "Pinned Biome, Oxlint/Oxfmt, Ultracite, and React Doctor presets for Howells projects.",
5
5
  "license": "MIT",
6
6
  "packageManager": "pnpm@10.23.0",
7
7
  "engines": {
@@ -14,6 +14,8 @@
14
14
  "oxlint/*.d.mts",
15
15
  "oxlint/*.mjs",
16
16
  "bin/*.mjs",
17
+ "docs/**/*.md",
18
+ "CONTEXT.md",
17
19
  "README.md",
18
20
  "MIGRATIONS.md"
19
21
  ],
@@ -33,9 +35,11 @@
33
35
  "dependencies": {
34
36
  "@biomejs/biome": "2.4.15",
35
37
  "@manypkg/cli": "^0.25.1",
36
- "oxfmt": "0.49.0",
37
- "oxlint": "1.64.0",
38
- "oxlint-tsgolint": "0.22.1",
38
+ "oxc-parser": "0.133.0",
39
+ "oxfmt": "0.51.0",
40
+ "oxlint": "1.66.0",
41
+ "oxlint-plugin-react-doctor": "0.2.14",
42
+ "oxlint-tsgolint": "0.23.0",
39
43
  "ultracite": "7.7.0"
40
44
  },
41
45
  "exports": {
@@ -59,5 +63,20 @@
59
63
  "types": "./oxlint/next.d.mts",
60
64
  "default": "./oxlint/next.mjs"
61
65
  }
62
- }
66
+ },
67
+ "main": "index.js",
68
+ "scripts": {
69
+ "test": "echo \"Error: no test specified\" && exit 1"
70
+ },
71
+ "repository": {
72
+ "type": "git",
73
+ "url": "git+https://github.com/howells/lint.git"
74
+ },
75
+ "keywords": [],
76
+ "author": "",
77
+ "type": "commonjs",
78
+ "bugs": {
79
+ "url": "https://github.com/howells/lint/issues"
80
+ },
81
+ "homepage": "https://github.com/howells/lint#readme"
63
82
  }