@jameswyse/oxc-config 0.2.0 → 0.4.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/README.md +30 -186
- package/REFERENCE.md +105 -132
- package/dist/index.js +26 -0
- package/dist/lint.d.ts +1 -0
- package/dist/lint.js +124 -4
- package/dist/rules/electron-no-remote-module.js +3 -6
- package/dist/rules/explicit-api-states.js +7 -1
- package/dist/rules/import-boundaries.js +31 -6
- package/dist/rules/no-ambient-clock.js +104 -8
- package/dist/rules/no-derived-test-expectation.d.ts +1 -0
- package/dist/rules/no-derived-test-expectation.js +136 -0
- package/dist/rules/no-disabled-tls-verification.d.ts +1 -0
- package/dist/rules/no-disabled-tls-verification.js +42 -0
- package/dist/rules/no-env-access.js +62 -5
- package/dist/rules/no-fixed-test-delay.js +46 -5
- package/dist/rules/no-generic-object-guard.d.ts +1 -0
- package/dist/rules/no-generic-object-guard.js +279 -0
- package/dist/rules/no-get-password-form.d.ts +1 -0
- package/dist/rules/no-get-password-form.js +113 -0
- package/dist/rules/no-hardcoded-credential.d.ts +1 -0
- package/dist/rules/no-hardcoded-credential.js +45 -0
- package/dist/rules/no-import-time-effects.d.ts +1 -0
- package/dist/rules/no-import-time-effects.js +90 -0
- package/dist/rules/no-optional-test-action.d.ts +1 -0
- package/dist/rules/no-optional-test-action.js +45 -0
- package/dist/rules/no-secret-fallback.d.ts +1 -0
- package/dist/rules/no-secret-fallback.js +64 -0
- package/dist/rules/no-swallowed-errors.js +131 -16
- package/dist/rules/no-test-timeout-overrides.js +22 -9
- package/dist/rules/no-unchecked-fetch-response.d.ts +1 -0
- package/dist/rules/no-unchecked-fetch-response.js +91 -0
- package/dist/rules/no-unchecked-index-search.d.ts +1 -0
- package/dist/rules/no-unchecked-index-search.js +41 -0
- package/dist/rules/no-uncontrolled-test-clock.d.ts +1 -0
- package/dist/rules/no-uncontrolled-test-clock.js +112 -0
- package/dist/rules/no-unsettled-promise.d.ts +1 -0
- package/dist/rules/no-unsettled-promise.js +64 -0
- package/dist/rules/require-suppression-reason.d.ts +1 -0
- package/dist/rules/require-suppression-reason.js +32 -0
- package/dist/shared/index.d.ts +14 -1
- package/dist/shared/index.js +231 -91
- package/dist/vendor/anti-slop/effect/rules/no-service-constructor-imports.js +10 -2
- package/dist/vendor/anti-slop/rules/no-known-value-widening.js +1 -1
- package/dist/vendor/anti-slop/rules/no-module-mocking.js +56 -1
- package/dist/vendor/anti-slop/rules/no-runtime-typeof.js +30 -1
- package/dist/vendor/anti-slop/rules/no-shape-in-symbol-names.js +28 -1
- package/dist/vendor/anti-slop/rules/no-unknown-returns.js +1 -1
- package/dist/vendor/anti-slop/rules/no-unsafe-dictionary-type.js +2 -2
- package/dist/vendor/anti-slop/shared/dictionary-types.js +72 -89
- package/dist/vendor/anti-slop/shared/type-alias-resolution.d.ts +8 -2
- package/dist/vendor/anti-slop/shared/type-alias-resolution.js +2 -2
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -2,227 +2,71 @@
|
|
|
2
2
|
|
|
3
3
|
Opinionated [Oxlint](https://oxc.rs/docs/guide/usage/linter.html) and [Oxfmt](https://oxc.rs/docs/guide/usage/formatter.html) configs for TypeScript and JavaScript projects. They combine Oxlint's native rules with custom rules for type and data safety, comment-free code, configuration ownership, import boundaries, server-action guards, test reliability and statement spacing.
|
|
4
4
|
|
|
5
|
-
The rules aim to keep both people and coding agents on the same standards: parse external data at the seam, use named exports, never ship console logging, and let names, types and tests carry intent instead of comments. [The reference](REFERENCE.md) maps each standard to its rules
|
|
5
|
+
The rules aim to keep both people and coding agents on the same standards: parse external data at the seam, use named exports, never ship console logging, and let names, types and tests carry intent instead of comments. [The reference](REFERENCE.md) maps each standard to its rules.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Example: a test that can't fail
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```sh
|
|
12
|
-
pnpm add -D @jameswyse/oxc-config oxlint oxfmt oxlint-tsgolint
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
The React profile uses `eslint-plugin-react-you-might-not-need-an-effect`, which declares an ESLint peer even though it runs under Oxlint. To skip installing ESLint with pnpm, add this to the project's `pnpm-workspace.yaml` before installing:
|
|
16
|
-
|
|
17
|
-
```yaml
|
|
18
|
-
autoInstallPeers: false
|
|
19
|
-
peerDependencyRules:
|
|
20
|
-
ignoreMissing:
|
|
21
|
-
- eslint
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
`autoInstallPeers` affects every dependency in the workspace. No ESLint configuration is needed either way.
|
|
25
|
-
|
|
26
|
-
## Set up with a coding agent
|
|
27
|
-
|
|
28
|
-
To have a coding agent install and configure the package, give it this prompt:
|
|
29
|
-
|
|
30
|
-
```text
|
|
31
|
-
Set up @jameswyse/oxc-config in this repository by following its README:
|
|
32
|
-
https://github.com/jameswyse/oxc-config#readme
|
|
33
|
-
|
|
34
|
-
1. Install the package and its peers, then create oxlint.config.ts and oxfmt.config.ts. In a monorepo, check which directory each package's lint script runs from and which config Oxlint finds from there.
|
|
35
|
-
2. Survey the code before choosing options. Pass each option the evidence supports:
|
|
36
|
-
- react, nextjs, node, vitest, jest, effect, electron and tests: the frameworks, runtimes and test runners each package uses, scoped to the files that use them.
|
|
37
|
-
- env: the modules that read process.env or import.meta.env. Each runtime should have one module that parses configuration and passes typed values on. If reads are scattered, list them as owners for now and record the consolidation as follow-up.
|
|
38
|
-
- boundaries: code that must not import from another part of the project, such as browser code importing server modules, Node built-ins or database clients, an Electron renderer importing main-process code, or a shared package importing an application.
|
|
39
|
-
- serverActionGuards: the functions that "use server" actions call to check authentication or permissions.
|
|
40
|
-
- clock and random: the modules that own the current time and ID or random value generation.
|
|
41
|
-
3. Extend @jameswyse/oxc-config/tsconfig unless the project's existing compiler settings conflict with it.
|
|
42
|
-
4. Run the lint and format scripts. Fix the violations. Suppress a rule only where it reports correct code, with the reason after --, and list each such case as a possible upstream issue.
|
|
43
|
-
5. Report every option above, with the value you set or the evidence for leaving it out. Leaving out env or boundaries in an application needs a specific reason.
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Configure
|
|
47
|
-
|
|
48
|
-
Create `oxlint.config.ts` in the project root:
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
import { createLintConfig } from "@jameswyse/oxc-config/oxlint";
|
|
52
|
-
|
|
53
|
-
export default createLintConfig();
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Type-aware checking is on by default. It needs the project's `tsconfig.json` and `oxlint-tsgolint`, which uses TypeScript 7. Configurations that rely on removed options such as `baseUrl` need migrating first. For plain JavaScript or a TypeScript project that is not yet compatible, pass `typeAware: false`. Syntax and scope rules still run, and explicit `any` is still rejected.
|
|
57
|
-
|
|
58
|
-
Create `oxfmt.config.ts` beside it:
|
|
9
|
+
Coding agents often write tests that pass whatever the code does. This one passes as long as `parseUser` is exported:
|
|
59
10
|
|
|
60
11
|
```ts
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Add the scripts:
|
|
67
|
-
|
|
68
|
-
```json
|
|
69
|
-
{
|
|
70
|
-
"scripts": {
|
|
71
|
-
"lint": "oxlint .",
|
|
72
|
-
"lint:fix": "oxlint --fix . && oxfmt . && oxlint .",
|
|
73
|
-
"format": "oxfmt .",
|
|
74
|
-
"format:check": "oxfmt --check ."
|
|
75
|
-
}
|
|
76
|
-
}
|
|
12
|
+
test("parseUser", () => {
|
|
13
|
+
expect(parseUser).toBeDefined();
|
|
14
|
+
});
|
|
77
15
|
```
|
|
78
16
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
The defaults enable no framework profiles or project boundaries, because both depend on the project. Select the profiles below, then [configure the boundaries](#enforce-project-boundaries) that fit.
|
|
82
|
-
|
|
83
|
-
## Select framework and runtime profiles
|
|
84
|
-
|
|
85
|
-
Enable only the tools the project uses. Each profile accepts `true` for its default scope or an array of project-relative globs. `nextjs` takes application root directories instead of globs.
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
|
-
import { createLintConfig } from "@jameswyse/oxc-config/oxlint";
|
|
89
|
-
|
|
90
|
-
export default createLintConfig({ react: true, vitest: true });
|
|
17
|
+
```text
|
|
18
|
+
error wyse(no-edit-proof-assertions): This assertion only proves that an import exists or that a value is a function. Call it and assert the behaviour it provides.
|
|
91
19
|
```
|
|
92
20
|
|
|
93
|
-
|
|
21
|
+
Calling the function and checking its result passes:
|
|
94
22
|
|
|
95
23
|
```ts
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
export default createLintConfig({
|
|
99
|
-
nextjs: ["apps/web"],
|
|
100
|
-
react: ["packages/ui/**/*.{ts,tsx}"],
|
|
101
|
-
node: ["packages/server/**/*.ts"],
|
|
102
|
-
vitest: ["**/*.{test,spec}.{ts,tsx}"],
|
|
24
|
+
test("parseUser reads the name from JSON", () => {
|
|
25
|
+
expect(parseUser('{"name":"Ada"}')).toEqual({ name: "Ada" });
|
|
103
26
|
});
|
|
104
27
|
```
|
|
105
28
|
|
|
106
|
-
|
|
107
|
-
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
108
|
-
| `react` | React and React Compiler rules, accessibility rules, effect-misuse rules, and e18e performance rules outside tests |
|
|
109
|
-
| `nextjs` | The React profile plus Next.js rules, with default exports allowed for `app` and `pages` entrypoints under each root |
|
|
110
|
-
| `node` | Node.js environment and rules |
|
|
111
|
-
| `vitest` | Vitest rules; its globs join the shared test scope |
|
|
112
|
-
| `jest` | Jest rules; keep its scope separate from Vitest when both exist |
|
|
113
|
-
| `effect` | Effect error-tag and service-import rules, for modules that use [Effect](https://effect.website) |
|
|
114
|
-
| `tests` | Extra test globs, such as Playwright or Node tests, for the custom test rules |
|
|
115
|
-
| `electron` | Electron security rules everywhere, and an import boundary keeping `electron` and `node:*` out of the renderer (`src/renderer/**` by default, or `{ renderer: [...] }`). Needs [`root`](#enforce-project-boundaries) |
|
|
116
|
-
|
|
117
|
-
Default exports are also accepted where a tool loads them: config files, Storybook stories and `.storybook`, `sanity.cli`, GraphQL Codegen entrypoints and declaration files.
|
|
118
|
-
|
|
119
|
-
In a monorepo, run Oxlint from each package with a `tsconfig.json`, or pass an existing lint tsconfig with `--tsconfig`. Oxlint uses the nearest config file in or above the directory it runs from, so one root config can serve every package. Write its globs from the root, such as `apps/web/src/**`.
|
|
120
|
-
|
|
121
|
-
## Enforce project boundaries
|
|
29
|
+
This is one rule of many. [The reference](REFERENCE.md) lists the rest, from unparsed external data and scattered `process.env` reads to server actions that skip their auth check.
|
|
122
30
|
|
|
123
|
-
|
|
31
|
+
## Set up with a coding agent
|
|
124
32
|
|
|
125
|
-
|
|
126
|
-
import { createLintConfig } from "@jameswyse/oxc-config/oxlint";
|
|
33
|
+
Give the agent this prompt:
|
|
127
34
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
env: ["src/main/config.ts", "src/renderer/env.ts"],
|
|
132
|
-
boundaries: [
|
|
133
|
-
{
|
|
134
|
-
files: ["src/renderer/**"],
|
|
135
|
-
deny: ["electron", "node:*", "@main/**", "src/main/**"],
|
|
136
|
-
message: "Use the typed contextBridge API exposed by the preload process.",
|
|
137
|
-
},
|
|
138
|
-
],
|
|
139
|
-
serverActionGuards: ["requireStaffPermission", "requireMember"],
|
|
140
|
-
clock: ["src/platform/clock.ts"],
|
|
141
|
-
random: ["src/platform/ids.ts"],
|
|
142
|
-
});
|
|
35
|
+
```text
|
|
36
|
+
Set up @jameswyse/oxc-config in this repository by following
|
|
37
|
+
https://github.com/jameswyse/oxc-config/blob/main/docs/agent-setup.md
|
|
143
38
|
```
|
|
144
39
|
|
|
145
|
-
|
|
146
|
-
- `boundaries` rejects imports from `files` that match a `deny` glob. Bare specifiers match as written. Relative specifiers resolve to a path from the config file's directory first, so `../main/ipc` matches `src/main/**`. Type-only imports are allowed because they are erased. Use `ignore` to exclude files from a boundary's scope. The boundary rule needs `root: import.meta.dirname` to find that directory, and `createLintConfig` throws without it when `boundaries` or `electron` is set.
|
|
147
|
-
- `serverActionGuards` requires every exported function in a `"use server"` module, and every inline `"use server"` function, to start by awaiting one of the named guards. Server-action modules must export each action where it is declared. A guard's name cannot prove it authorises the operation, so review the guard itself.
|
|
148
|
-
- `clock` and `random` list the modules that may read the current time (`Date.now()`, argument-less `new Date()`) or generate random values and IDs (`Math.random()`, `crypto.randomUUID()`, `randomUUID`/`randomInt` from `node:crypto`). Other production code must receive them, so tests can control them without faking globals. Test files, parameter defaults such as `now = new Date()` and passing `Date.now` uncalled are allowed. Durations from `performance.now()` and secret generation are out of scope.
|
|
149
|
-
|
|
150
|
-
## Share strict compiler settings
|
|
40
|
+
## Set up by hand
|
|
151
41
|
|
|
152
|
-
|
|
42
|
+
Install the package and its peers. It requires Node.js 22.23 or later.
|
|
153
43
|
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
"extends": "@jameswyse/oxc-config/tsconfig"
|
|
157
|
-
}
|
|
44
|
+
```sh
|
|
45
|
+
pnpm add -D @jameswyse/oxc-config oxlint oxfmt oxlint-tsgolint
|
|
158
46
|
```
|
|
159
47
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
## Add project-specific exceptions
|
|
163
|
-
|
|
164
|
-
Append overrides to the returned config so its framework and test overrides stay active. Oxlint applies file overrides after top-level `rules`, so type-aware and framework rules can only be changed by a later override.
|
|
48
|
+
Create `oxlint.config.ts` and `oxfmt.config.ts` in the project root:
|
|
165
49
|
|
|
166
50
|
```ts
|
|
167
51
|
import { createLintConfig } from "@jameswyse/oxc-config/oxlint";
|
|
168
52
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
export default {
|
|
172
|
-
...base,
|
|
173
|
-
ignorePatterns: [...base.ignorePatterns, "src/routeTree.gen.ts"],
|
|
174
|
-
overrides: [
|
|
175
|
-
...base.overrides,
|
|
176
|
-
{
|
|
177
|
-
files: ["src/validation/**/*.ts"],
|
|
178
|
-
rules: {
|
|
179
|
-
"wyse/no-runtime-typeof": "off",
|
|
180
|
-
"wyse/no-unsafe-dictionary-type": "off",
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
],
|
|
184
|
-
};
|
|
53
|
+
export default createLintConfig();
|
|
185
54
|
```
|
|
186
55
|
|
|
187
|
-
Use this for validated input seams, real timer tests, external module mocks, framework-required default exports and generated files. Keep each exception to the smallest scope. Suppression comments that no longer suppress anything are errors.
|
|
188
|
-
|
|
189
|
-
## Adjust the formatter
|
|
190
|
-
|
|
191
|
-
The formatter uses 100 columns, two spaces, double quotes, semicolons and trailing commas. It sorts imports into value and type groups and sorts `package.json` scripts. To use single quotes or add a workspace import prefix:
|
|
192
|
-
|
|
193
56
|
```ts
|
|
194
57
|
import { formatConfig } from "@jameswyse/oxc-config/oxfmt";
|
|
195
58
|
|
|
196
|
-
export default
|
|
197
|
-
...formatConfig,
|
|
198
|
-
singleQuote: true,
|
|
199
|
-
sortImports: {
|
|
200
|
-
...formatConfig.sortImports,
|
|
201
|
-
internalPattern: ["@/", "#", "@my-workspace/"],
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
Tailwind class sorting depends on the project's Tailwind version and stylesheet, so configure Oxfmt's `sortTailwindcss` option in the project.
|
|
207
|
-
|
|
208
|
-
## Develop
|
|
209
|
-
|
|
210
|
-
```sh
|
|
211
|
-
pnpm install --frozen-lockfile
|
|
212
|
-
pnpm check
|
|
59
|
+
export default formatConfig;
|
|
213
60
|
```
|
|
214
61
|
|
|
215
|
-
|
|
62
|
+
Type-aware checking is on by default and needs a `tsconfig.json` that TypeScript 7 accepts. The defaults enable no framework profiles or project boundaries. The [configuration guide](docs/configuration.md) covers supported versions, scripts, framework profiles, project boundaries, the shared tsconfig, exceptions and formatter options.
|
|
216
63
|
|
|
217
|
-
##
|
|
218
|
-
|
|
219
|
-
Add a changeset to any pull request that should ship:
|
|
220
|
-
|
|
221
|
-
```sh
|
|
222
|
-
pnpm changeset
|
|
223
|
-
```
|
|
64
|
+
## Documentation
|
|
224
65
|
|
|
225
|
-
|
|
66
|
+
- [Configuration guide](docs/configuration.md)
|
|
67
|
+
- [Agent setup instructions](docs/agent-setup.md)
|
|
68
|
+
- [Rule reference](REFERENCE.md)
|
|
69
|
+
- [Contributing](CONTRIBUTING.md)
|
|
226
70
|
|
|
227
71
|
## Vendored code
|
|
228
72
|
|