@howells/lint 0.2.0 → 0.2.2

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 CHANGED
@@ -103,11 +103,15 @@ Next.js app:
103
103
 
104
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.
105
105
 
106
+ React Doctor severities are passed through as published by React Doctor. Native Oxlint Next.js severities come from Oxlint's official `nextjs` plugin via Ultracite's Next preset. `@howells/lint` adds canonical Howells policy on top for file naming, barrel files, env access, and tests.
107
+
106
108
  Choose the closest preset:
107
109
 
108
110
  - `@howells/lint/oxlint/core` for Node or non-React TypeScript
109
111
  - `@howells/lint/oxlint/react` for React (Ultracite React + React Doctor recommended rules)
110
112
  - `@howells/lint/oxlint/next` for Next.js (react preset + Next.js rules)
113
+ - `@howells/lint/oxlint/boundaries` for monorepo import boundaries (`packages/**` cannot import from `apps/**`, and apps cannot import from other apps)
114
+ - `@howells/lint/oxlint/react-doctor-rules` for composing or disabling React Doctor rules in mixed workspaces
111
115
 
112
116
  Node or non-React TypeScript:
113
117
 
@@ -142,6 +146,43 @@ export default defineConfig({
142
146
  });
143
147
  ```
144
148
 
149
+ Monorepo root or package boundary config:
150
+
151
+ ```ts
152
+ import { defineConfig } from "oxlint";
153
+ import {
154
+ boundaryJsPlugins,
155
+ boundaryRules,
156
+ boundarySettings,
157
+ } from "@howells/lint/oxlint/boundaries";
158
+
159
+ export default defineConfig({
160
+ jsPlugins: boundaryJsPlugins,
161
+ settings: boundarySettings,
162
+ rules: boundaryRules,
163
+ });
164
+ ```
165
+
166
+ Run boundary configs from the monorepo root so element patterns such as `apps/*/**` and `packages/*/**` match the project tree.
167
+
168
+ Mixed monorepo with a Next.js app and Node-only packages:
169
+
170
+ ```ts
171
+ import { defineConfig } from "oxlint";
172
+ import next from "@howells/lint/oxlint/next";
173
+ import { disabledReactDoctorRules } from "@howells/lint/oxlint/react-doctor-rules";
174
+
175
+ export default defineConfig({
176
+ extends: [next],
177
+ overrides: [
178
+ {
179
+ files: ["packages/**/*.ts"],
180
+ rules: disabledReactDoctorRules,
181
+ },
182
+ ],
183
+ });
184
+ ```
185
+
145
186
  Create an `oxfmt.config.ts`:
146
187
 
147
188
  ```ts
@@ -0,0 +1,12 @@
1
+ import type { OxlintConfig } from "oxlint";
2
+
3
+ type OxlintRules = NonNullable<OxlintConfig["rules"]>;
4
+ type OxlintSettings = NonNullable<OxlintConfig["settings"]>;
5
+ type OxlintJsPlugins = NonNullable<OxlintConfig["jsPlugins"]>;
6
+
7
+ export const boundaryJsPlugins: OxlintJsPlugins;
8
+ export const boundarySettings: OxlintSettings;
9
+ export const boundaryRules: OxlintRules;
10
+
11
+ declare const config: OxlintConfig;
12
+ export default config;
@@ -0,0 +1,49 @@
1
+ import { defineConfig } from "oxlint";
2
+
3
+ export const boundaryJsPlugins = [
4
+ { name: "boundaries", specifier: "eslint-plugin-boundaries" },
5
+ ];
6
+
7
+ export const boundarySettings = {
8
+ "import/resolver": {
9
+ node: {
10
+ extensions: [".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"],
11
+ },
12
+ typescript: {
13
+ alwaysTryTypes: true,
14
+ project: ["tsconfig.json", "apps/*/tsconfig.json", "packages/*/tsconfig.json"],
15
+ },
16
+ },
17
+ "boundaries/elements": [
18
+ { type: "app", pattern: "apps/*/**", mode: "full" },
19
+ { type: "package", pattern: "packages/*/**", mode: "full" },
20
+ ],
21
+ };
22
+
23
+ export const boundaryRules = {
24
+ "boundaries/dependencies": [
25
+ "error",
26
+ {
27
+ default: "allow",
28
+ checkUnknownLocals: true,
29
+ rules: [
30
+ {
31
+ from: { type: "package" },
32
+ disallow: [{ to: { type: "app" } }],
33
+ message: "Packages must not import from apps.",
34
+ },
35
+ {
36
+ from: { type: "app" },
37
+ disallow: [{ to: { type: "app" } }],
38
+ message: "Apps must not import from other apps.",
39
+ },
40
+ ],
41
+ },
42
+ ],
43
+ };
44
+
45
+ export default defineConfig({
46
+ jsPlugins: boundaryJsPlugins,
47
+ settings: boundarySettings,
48
+ rules: boundaryRules,
49
+ });
package/oxlint/core.mjs CHANGED
@@ -1 +1,44 @@
1
- export { default } from "ultracite/oxlint/core";
1
+ import { defineConfig } from "oxlint";
2
+ import ultraciteCore from "ultracite/oxlint/core";
3
+
4
+ export default defineConfig({
5
+ extends: [ultraciteCore],
6
+ plugins: [...new Set([...(ultraciteCore.plugins ?? []), "vitest"])],
7
+ rules: {
8
+ "no-restricted-properties": [
9
+ "error",
10
+ {
11
+ message:
12
+ "Use the project env schema instead of reading process.env directly. Env schema files may override this rule locally.",
13
+ object: "process",
14
+ property: "env",
15
+ },
16
+ ],
17
+ "oxc/no-barrel-file": [
18
+ "error",
19
+ {
20
+ threshold: 0,
21
+ },
22
+ ],
23
+ "unicorn/filename-case": [
24
+ "error",
25
+ {
26
+ cases: {
27
+ kebabCase: true,
28
+ },
29
+ },
30
+ ],
31
+ "vitest/hoisted-apis-on-top": "error",
32
+ "vitest/no-commented-out-tests": "error",
33
+ "vitest/no-conditional-tests": "error",
34
+ "vitest/no-disabled-tests": "error",
35
+ "vitest/no-focused-tests": "error",
36
+ "vitest/no-identical-title": "error",
37
+ "vitest/no-import-node-test": "error",
38
+ "vitest/no-mocks-import": "error",
39
+ "vitest/no-standalone-expect": "error",
40
+ "vitest/valid-describe-callback": "error",
41
+ "vitest/valid-expect": "error",
42
+ "vitest/valid-expect-in-promise": "error",
43
+ },
44
+ });
@@ -0,0 +1,8 @@
1
+ import type { OxlintConfig } from "oxlint";
2
+
3
+ type OxlintRules = NonNullable<OxlintConfig["rules"]>;
4
+
5
+ export const reactDoctorRecommendedRules: OxlintRules;
6
+ export const reactDoctorNextRules: OxlintRules;
7
+ export const reactDoctorRules: OxlintRules;
8
+ export const disabledReactDoctorRules: OxlintRules;
@@ -0,0 +1,14 @@
1
+ import {
2
+ NEXTJS_RULES,
3
+ RECOMMENDED_RULES,
4
+ } from "oxlint-plugin-react-doctor";
5
+
6
+ export const reactDoctorRecommendedRules = RECOMMENDED_RULES;
7
+ export const reactDoctorNextRules = NEXTJS_RULES;
8
+ export const reactDoctorRules = {
9
+ ...RECOMMENDED_RULES,
10
+ ...NEXTJS_RULES,
11
+ };
12
+ export const disabledReactDoctorRules = Object.fromEntries(
13
+ Object.keys(reactDoctorRules).map((ruleName) => [ruleName, "allow"])
14
+ );
package/oxlint/react.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { defineConfig } from "oxlint";
2
2
  import { RECOMMENDED_RULES } from "oxlint-plugin-react-doctor";
3
- import core from "ultracite/oxlint/core";
4
3
  import ultraciteReact from "ultracite/oxlint/react";
4
+ import core from "./core.mjs";
5
5
 
6
6
  export default defineConfig({
7
7
  extends: [core, ultraciteReact],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howells/lint",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
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",
@@ -35,12 +35,14 @@
35
35
  "dependencies": {
36
36
  "@biomejs/biome": "2.4.15",
37
37
  "@manypkg/cli": "^0.25.1",
38
+ "eslint-import-resolver-typescript": "4.4.4",
39
+ "eslint-plugin-boundaries": "6.0.2",
38
40
  "oxc-parser": "0.133.0",
39
41
  "oxfmt": "0.51.0",
40
42
  "oxlint": "1.66.0",
41
- "oxlint-plugin-react-doctor": "0.2.14",
43
+ "oxlint-plugin-react-doctor": "0.4.0",
42
44
  "oxlint-tsgolint": "0.23.0",
43
- "ultracite": "7.7.0"
45
+ "ultracite": "7.8.1"
44
46
  },
45
47
  "exports": {
46
48
  "./package.json": "./package.json",
@@ -62,6 +64,14 @@
62
64
  "./oxlint/next": {
63
65
  "types": "./oxlint/next.d.mts",
64
66
  "default": "./oxlint/next.mjs"
67
+ },
68
+ "./oxlint/boundaries": {
69
+ "types": "./oxlint/boundaries.d.mts",
70
+ "default": "./oxlint/boundaries.mjs"
71
+ },
72
+ "./oxlint/react-doctor-rules": {
73
+ "types": "./oxlint/react-doctor-rules.d.mts",
74
+ "default": "./oxlint/react-doctor-rules.mjs"
65
75
  }
66
76
  },
67
77
  "main": "index.js",