@jameswyse/oxc-config 0.1.0 → 0.3.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.
Files changed (50) hide show
  1. package/README.md +30 -163
  2. package/REFERENCE.md +105 -132
  3. package/dist/format.d.ts +5 -3
  4. package/dist/index.js +26 -0
  5. package/dist/lint.d.ts +3 -1
  6. package/dist/lint.js +153 -14
  7. package/dist/rules/explicit-api-states.js +7 -1
  8. package/dist/rules/import-boundaries.js +41 -13
  9. package/dist/rules/no-derived-test-expectation.d.ts +1 -0
  10. package/dist/rules/no-derived-test-expectation.js +136 -0
  11. package/dist/rules/no-disabled-tls-verification.d.ts +1 -0
  12. package/dist/rules/no-disabled-tls-verification.js +42 -0
  13. package/dist/rules/no-fixed-test-delay.js +46 -5
  14. package/dist/rules/no-generic-object-guard.d.ts +1 -0
  15. package/dist/rules/no-generic-object-guard.js +279 -0
  16. package/dist/rules/no-get-password-form.d.ts +1 -0
  17. package/dist/rules/no-get-password-form.js +113 -0
  18. package/dist/rules/no-hardcoded-credential.d.ts +1 -0
  19. package/dist/rules/no-hardcoded-credential.js +45 -0
  20. package/dist/rules/no-import-time-effects.d.ts +1 -0
  21. package/dist/rules/no-import-time-effects.js +90 -0
  22. package/dist/rules/no-optional-test-action.d.ts +1 -0
  23. package/dist/rules/no-optional-test-action.js +45 -0
  24. package/dist/rules/no-secret-fallback.d.ts +1 -0
  25. package/dist/rules/no-secret-fallback.js +64 -0
  26. package/dist/rules/no-swallowed-errors.js +131 -16
  27. package/dist/rules/no-test-timeout-overrides.js +22 -9
  28. package/dist/rules/no-unchecked-fetch-response.d.ts +1 -0
  29. package/dist/rules/no-unchecked-fetch-response.js +91 -0
  30. package/dist/rules/no-unchecked-index-search.d.ts +1 -0
  31. package/dist/rules/no-unchecked-index-search.js +41 -0
  32. package/dist/rules/no-uncontrolled-test-clock.d.ts +1 -0
  33. package/dist/rules/no-uncontrolled-test-clock.js +112 -0
  34. package/dist/rules/no-unsettled-promise.d.ts +1 -0
  35. package/dist/rules/no-unsettled-promise.js +64 -0
  36. package/dist/rules/require-suppression-reason.d.ts +1 -0
  37. package/dist/rules/require-suppression-reason.js +32 -0
  38. package/dist/shared/index.d.ts +9 -0
  39. package/dist/shared/index.js +70 -0
  40. package/dist/vendor/anti-slop/effect/rules/no-service-constructor-imports.js +10 -2
  41. package/dist/vendor/anti-slop/rules/no-known-value-widening.js +1 -1
  42. package/dist/vendor/anti-slop/rules/no-module-mocking.js +56 -1
  43. package/dist/vendor/anti-slop/rules/no-runtime-typeof.js +30 -1
  44. package/dist/vendor/anti-slop/rules/no-shape-in-symbol-names.js +28 -1
  45. package/dist/vendor/anti-slop/rules/no-unknown-returns.js +1 -1
  46. package/dist/vendor/anti-slop/rules/no-unsafe-dictionary-type.js +2 -2
  47. package/dist/vendor/anti-slop/shared/dictionary-types.js +72 -89
  48. package/dist/vendor/anti-slop/shared/type-alias-resolution.d.ts +8 -2
  49. package/dist/vendor/anti-slop/shared/type-alias-resolution.js +2 -2
  50. package/package.json +7 -7
package/README.md CHANGED
@@ -2,204 +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 and states what lint cannot check.
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
- Requires Node.js 22.23 or later. Supports Oxlint 1.86 or later, Oxfmt 0.71 or later and oxlint-tsgolint 7.0.2003 or later, within their current major versions.
7
+ ## Example: a test that can't fail
8
8
 
9
- ## Install
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
- ## Configure
27
-
28
- Create `oxlint.config.ts` in the project root:
9
+ Coding agents often write tests that pass whatever the code does. This one passes as long as `parseUser` is exported:
29
10
 
30
11
  ```ts
31
- import { createLintConfig } from "@jameswyse/oxc-config/oxlint";
32
-
33
- export default createLintConfig();
34
- ```
35
-
36
- 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.
37
-
38
- Create `oxfmt.config.ts` beside it:
39
-
40
- ```ts
41
- import { formatConfig } from "@jameswyse/oxc-config/oxfmt";
42
-
43
- export default formatConfig;
12
+ test("parseUser", () => {
13
+ expect(parseUser).toBeDefined();
14
+ });
44
15
  ```
45
16
 
46
- Add the scripts:
47
-
48
- ```json
49
- {
50
- "scripts": {
51
- "lint": "oxlint .",
52
- "lint:fix": "oxlint --fix . && oxfmt . && oxlint .",
53
- "format": "oxfmt .",
54
- "format:check": "oxfmt --check ."
55
- }
56
- }
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.
57
19
  ```
58
20
 
59
- Errors fail the run. Warnings mark patterns worth reviewing that have legitimate uses, so they report without blocking: dependency cycles, barrel and forwarding modules, `typeof` outside type guards, swallowed errors, boolean parameters on exported functions, pass-through functions, tests without a matching owner file and test timeout overrides. `lint:fix` formats after applying lint fixes, then lints again to confirm the result.
60
-
61
- ## Select framework and runtime profiles
62
-
63
- 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.
21
+ Calling the function and checking its result passes:
64
22
 
65
23
  ```ts
66
- import { createLintConfig } from "@jameswyse/oxc-config/oxlint";
67
-
68
- export default createLintConfig({ react: true, vitest: true });
69
- ```
70
-
71
- For a monorepo with separate server and browser packages:
72
-
73
- ```ts
74
- import { createLintConfig } from "@jameswyse/oxc-config/oxlint";
75
-
76
- export default createLintConfig({
77
- nextjs: ["apps/web"],
78
- react: ["packages/ui/**/*.{ts,tsx}"],
79
- node: ["packages/server/**/*.ts"],
80
- vitest: ["**/*.{test,spec}.{ts,tsx}"],
24
+ test("parseUser reads the name from JSON", () => {
25
+ expect(parseUser('{"name":"Ada"}')).toEqual({ name: "Ada" });
81
26
  });
82
27
  ```
83
28
 
84
- | Option | Adds |
85
- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
86
- | `react` | React and React Compiler rules, accessibility rules, effect-misuse rules, and e18e performance rules outside tests |
87
- | `nextjs` | The React profile plus Next.js rules, with default exports allowed for `app` and `pages` entrypoints under each root |
88
- | `node` | Node.js environment and rules |
89
- | `vitest` | Vitest rules; its globs join the shared test scope |
90
- | `jest` | Jest rules; keep its scope separate from Vitest when both exist |
91
- | `effect` | Effect error-tag and service-import rules, for modules that use [Effect](https://effect.website) |
92
- | `tests` | Extra test globs, such as Playwright or Node tests, for the custom test rules |
93
- | `electron` | Electron security rules everywhere, and an import boundary keeping `electron` and `node:*` out of the renderer (`src/renderer/**` by default, or `{ renderer: [...] }`) |
94
-
95
- Default exports are also accepted where a tool loads them: config files, Storybook stories and `.storybook`, `sanity.cli`, GraphQL Codegen entrypoints and declaration files.
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.
96
30
 
97
- In a monorepo, run Oxlint from each package with a `tsconfig.json`, or pass an existing lint tsconfig with `--tsconfig`.
31
+ ## Set up with a coding agent
98
32
 
99
- ## Enforce project boundaries
100
-
101
- These options need the project to name its owners, so each is off until configured. Globs are relative to the directory Oxlint runs from.
102
-
103
- ```ts
104
- import { createLintConfig } from "@jameswyse/oxc-config/oxlint";
33
+ Give the agent this prompt:
105
34
 
106
- export default createLintConfig({
107
- react: ["src/renderer/**"],
108
- env: ["src/main/config.ts", "src/renderer/env.ts"],
109
- boundaries: [
110
- {
111
- files: ["src/renderer/**"],
112
- deny: ["electron", "node:*", "@main/**", "src/main/**"],
113
- message: "Use the typed contextBridge API exposed by the preload process.",
114
- },
115
- ],
116
- serverActionGuards: ["requireStaffPermission", "requireMember"],
117
- clock: ["src/platform/clock.ts"],
118
- random: ["src/platform/ids.ts"],
119
- });
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
120
38
  ```
121
39
 
122
- - `env` lists the modules that may read `process.env` or `import.meta.env`. Other source files must receive parsed configuration. Config files and scripts are entrypoints and remain allowed.
123
- - `boundaries` rejects imports from `files` that match a `deny` glob. Bare specifiers match as written. Relative specifiers resolve to a project path 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.
124
- - `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.
125
- - `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.
40
+ ## Set up by hand
126
41
 
127
- ## Share strict compiler settings
42
+ Install the package and its peers. It requires Node.js 22.23 or later.
128
43
 
129
- The package exports `strict`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noImplicitOverride` and `noFallthroughCasesInSwitch` as a base config. Extend it from the project's `tsconfig.json` and keep target, module and path settings local:
130
-
131
- ```json
132
- {
133
- "extends": "@jameswyse/oxc-config/tsconfig"
134
- }
44
+ ```sh
45
+ pnpm add -D @jameswyse/oxc-config oxlint oxfmt oxlint-tsgolint
135
46
  ```
136
47
 
137
- In an existing project, `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes` usually surface many type errors, so adopt them as a separate migration.
138
-
139
- ## Add project-specific exceptions
140
-
141
- 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:
142
49
 
143
50
  ```ts
144
51
  import { createLintConfig } from "@jameswyse/oxc-config/oxlint";
145
52
 
146
- const base = createLintConfig({ react: true, vitest: true });
147
-
148
- export default {
149
- ...base,
150
- ignorePatterns: [...base.ignorePatterns, "src/routeTree.gen.ts"],
151
- overrides: [
152
- ...base.overrides,
153
- {
154
- files: ["src/validation/**/*.ts"],
155
- rules: {
156
- "wyse/no-runtime-typeof": "off",
157
- "wyse/no-unsafe-dictionary-type": "off",
158
- },
159
- },
160
- ],
161
- };
53
+ export default createLintConfig();
162
54
  ```
163
55
 
164
- 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.
165
-
166
- ## Adjust the formatter
167
-
168
- 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:
169
-
170
56
  ```ts
171
57
  import { formatConfig } from "@jameswyse/oxc-config/oxfmt";
172
58
 
173
- export default {
174
- ...formatConfig,
175
- singleQuote: true,
176
- sortImports: {
177
- ...formatConfig.sortImports,
178
- internalPattern: ["@/", "#", "@my-workspace/"],
179
- },
180
- };
181
- ```
182
-
183
- Tailwind class sorting depends on the project's Tailwind version and stylesheet, so configure Oxfmt's `sortTailwindcss` option in the project.
184
-
185
- ## Develop
186
-
187
- ```sh
188
- pnpm install --frozen-lockfile
189
- pnpm check
59
+ export default formatConfig;
190
60
  ```
191
61
 
192
- `pnpm check` runs the rule tests, lints real consumer configs in temporary projects, checks type-aware diagnostics and formatter convergence, then lints, typechecks, checks formatting and builds `dist`.
193
-
194
- ## Release
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.
195
63
 
196
- Add a changeset to any pull request that should ship:
197
-
198
- ```sh
199
- pnpm changeset
200
- ```
64
+ ## Documentation
201
65
 
202
- On `main`, the release workflow keeps a "chore(release): version packages" pull request up to date with the pending changesets. Merging it publishes the new version to npm with provenance, tags it and creates a GitHub release.
66
+ - [Configuration guide](docs/configuration.md)
67
+ - [Agent setup instructions](docs/agent-setup.md)
68
+ - [Rule reference](REFERENCE.md)
69
+ - [Contributing](CONTRIBUTING.md)
203
70
 
204
71
  ## Vendored code
205
72
 
package/REFERENCE.md CHANGED
@@ -1,134 +1,107 @@
1
1
  # Rule reference
2
2
 
3
- ## Defaults
4
-
5
- The base config enables Oxlint's correctness and suspicious categories as errors. It also enables strict equality, mandatory braces, `prefer-const`, no parameter reassignment, unused-variable checks that ignore `_`-prefixed bindings, import ordering and duplicate checks, the accumulating-spread check, named exports and no console logging. Unused suppression comments are errors. `no-underscore-dangle` is off so schema-owned fields such as `_id` and `__typename` remain valid.
6
-
7
- Warnings do not fail the run. The warning-level rules mark patterns that are usually worth changing but have legitimate uses that no syntax separates; each was measured on real codebases before it was added.
8
-
9
- ## Standards and rules
10
-
11
- | Standard | Implemented automation | Limit |
12
- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
13
- | No `any`; keep unknown external values at a seam | `typescript/no-explicit-any`; type-aware `no-unsafe-*`; `no-unsafe-dictionary-type`, `no-known-value-widening`, `no-unknown-returns` and `no-unknown-type-aliases` | Legitimate parsers may need narrow exceptions; imported domain types require type-aware analysis |
14
- | Parse external data at a seam instead of probing it | `wyse/no-runtime-typeof` warns about `typeof` outside type guards; `typeof x === "undefined"` probes are allowed | Narrowing a known primitive union with `typeof` is legitimate; the warning prompts a schema without blocking |
15
- | Prefer validated narrowing and `satisfies` | Native `no-non-null-assertion`; type-aware `no-unsafe-type-assertion`, `no-unnecessary-type-assertion`; `no-chained-type-assertions` and `no-widen-then-assert` | No syntactic rule proves a runtime schema or invariant correct |
16
- | Guards have truthful, recognisable names | Custom `wyse/type-guard-name` | Names do not prove predicate correctness |
17
- | Handle every union case | Type-aware `typescript/switch-exhaustiveness-check` | The compiler still owns `never` assignments and valid-state modelling |
18
- | Remove redundant guards and dead code | Correctness/suspicious categories; unused variables/private members; type-aware `no-unnecessary-condition` | Whether validation belongs at another seam needs review |
19
- | Keep branches readable | Custom `wyse/no-deep-ternary`; native `curly` | Complexity, line count and parameter count are not used as design proxies |
20
- | Handle asynchronous work and errors | Native correctness/promise checks, `no-empty`, `no-useless-catch`; typed floating/misused promises, `await-thenable`, `return-await`, `only-throw-error` | Meaningful recovery, domain results, retry policy and error context need review |
21
- | Represent expected failures instead of silencing them | Custom `wyse/no-swallowed-errors` (warning) | Parser, filesystem-probe and existing-promise catches are allowed; other expected failures need a suppression with a reason |
22
- | Avoid boolean control parameters | Custom `wyse/explicit-api-states` (warning) | Final boolean parameters of `set*`/`update*` functions are allowed; a boolean that is domain data still warns |
23
- | Named exports and imports from an owner | `import/no-default-export`, `first`, `no-duplicates`, `no-self-import`, `no-unassigned-import`; warnings from `import/no-cycle` and `oxc/no-barrel-file` | Internal barrel ownership and public package entrypoints need architectural context; the barrel rule counts only `export *` fan-out above its default threshold |
24
- | Name files after their concept | Custom `wyse/no-generic-file-suffix` | Files named after a domain export, such as `agentPolicy.ts` exporting `AgentPolicy`, and standard header policies are allowed |
25
- | Import from the authoritative module | Custom `wyse/no-forwarding-module` (warning) | Package entrypoints and framework route files are allowed; other frameworks' mandated re-export files may need an exception |
26
- | Remove middle men | Custom `wyse/no-pass-through-function` (warning) | Only identifier callees are checked, because method facades usually hide an instance |
27
- | No shipped console logging | `eslint/no-console`; narrow config/script exceptions | Redaction, sensitive fields and sufficient structured context need review |
28
- | Never add code comments | Custom `wyse/no-comments`; tool directives and JavaScript type JSDoc remain allowed | Projects can allow further directive patterns; the rule cannot tell whether the removed intent reached a name, type, test or commit |
29
- | Parse configuration at startup | Custom `wyse/no-env-access` with the project's `env` owners | Owners must be named by the project; the rule does not check that the owner validates what it reads |
30
- | Keep privileged modules out of other runtimes | Custom `wyse/import-boundaries` from the project's `boundaries` | Only static, dynamic-literal and re-export specifiers are checked; `require` and computed imports are not |
31
- | Enforce authorisation at the protected operation | Custom `wyse/server-action-guard` with the project's `serverActionGuards` | A guard's name cannot prove it authorises the operation or checks the right resource |
32
- | Control time and randomness | Custom `wyse/no-ambient-clock` and `wyse/no-ambient-random` with the project's `clock` and `random` owners | Production code only; owners must be named by the project |
33
- | Harden Electron apps | Custom `wyse/electron-*` rules and a renderer import boundary in the `electron` profile | Checks literal `webPreferences`, `remote` usage and raw `ipcRenderer` exposure through `contextBridge` |
34
- | Prefer local state and avoid accidental mutation | `prefer-const`, `no-param-reassign`; React immutability checks; typed `prefer-readonly` | Local accumulator mutation is allowed; ownership is not inferred from a variable name |
35
- | Avoid repeated growing copies | Native `oxc/no-accumulating-spread`; `no-array-filter-map` and `no-reduce-accumulator-copy`; optional e18e profile | No performance improvement is claimed without measurement |
36
- | Avoid duplicate React state and effect chains | React and React Compiler native rules; `react-you-might-not-need-an-effect` rules | Product interactions still need runtime verification |
37
- | Basic accessible JSX | Native `jsx-a11y` correctness/suspicious rules in the React profile | Keyboard behaviour, accessible names through custom components and visual contrast require application evidence |
38
- | Tests execute assertions and are not silently skipped | Native Jest/Vitest focused/disabled/conditional/standalone/valid expectation checks | Valid helper-based assertions are allowed; assertion-count rules are not enabled blindly |
39
- | Tests wait for observable outcomes | Custom `wyse/no-fixed-test-delay` | Genuine timer tests need a scoped exception; unknown wait helpers are not guessed |
40
- | Tests have a non-vacuous oracle | Custom `wyse/no-vacuous-test-assertions` | Independent expected results and meaningful behavioural coverage still need review |
41
- | Tests protect behaviour, not edits | Custom `wyse/no-edit-proof-assertions` | Only existence checks of imports and `typeof … "function"` checks are recognised |
42
- | Tests do not hide slow or flaky work | Custom `wyse/no-test-timeout-overrides` (warning, unit tests only) | End-to-end suites legitimately need longer timeouts and are excluded |
43
- | Tests sit beside the module they cover | Custom `wyse/companion-has-owner` (warning) | Cross-module tests should be named `<behaviour>.integration.test` or live under `tests/` |
44
- | Avoid module mocking of runnable dependencies | `wyse/no-module-mocking` | External systems can justify a file-scoped exception |
45
- | Consistent layout and imports | Oxfmt; custom `wyse/statement-spacing` | Blank lines are only required around imports, multiline blocks, multiline declarations and returns, so deliberate groups of one-line statements stay together |
46
-
47
- `no-unnecessary-condition` is a nursery rule in Oxlint 1.86.0. It is enabled only with `typeAware`. The usual native nested-ternary rule conflicts with Oxfmt 0.71.0 because one tool adds parentheses and the other removes them. The custom depth rule allows one nested level and reports the third ternary level, without prescribing parentheses.
48
-
49
- ## Custom rules
50
-
51
- All rules use Oxlint's supported AST and lexical scopes and their tests sit beside their source, in `src/rules` or, for rules adapted from anti-slop, `src/vendor/anti-slop`. Only `statement-spacing` has an autofix, which inserts blank lines; its engine is adapted from ESLint Stylistic's `padding-line-between-statements`. `companion-has-owner` and `no-forwarding-module` read sibling files and the nearest `package.json`. The others are dependency-free.
52
-
53
- | Rule | Rejected pattern | Allowed or outside scope |
54
- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
55
- | `type-guard-name` | A named predicate such as `checkUser(value): value is User` | `isUser`, `hasId`, assertion functions, anonymous callbacks and computed method names |
56
- | `no-deep-ternary` | A conditional expression nested inside two conditional expressions | One nested level; a separate function's expressions start a new depth |
57
- | `no-fixed-test-delay` | Awaited literal timer delays and known Playwright fixture `waitForTimeout` calls in recognised tests | Local functions that shadow timer/test names, nonliteral delays, and unknown custom helpers |
58
- | `no-vacuous-test-assertions` | Literal-to-literal equality expectations or the same identifier on both sides of `toBe`, `toEqual`, `toStrictEqual` | Computed values, property getters, reversed meaningful expectations and promise resolution matchers |
59
- | `no-comments` | Line, block and JSDoc comments, including JSDoc in TypeScript files | Shebangs, JSDoc with type tags in JavaScript files, and tool directives: lint suppressions, `@ts-expect-error`, triple-slash references, `#__PURE__`, formatter and coverage ignores, bundler magic comments, test-environment and JSX pragmas; extra patterns through the `allow` option |
60
- | `no-env-access` | `process.env`, `import.meta.env` and destructuring `env` from either, outside `env` owners, config files and scripts | Local bindings named `process` and unrelated `env` properties |
61
- | `import-boundaries` | A value import, re-export or literal dynamic import from a configured scope whose specifier or resolved relative path matches a `deny` glob | Type-only imports and files outside the boundary's scope |
62
- | `server-action-guard` | An exported action in a `"use server"` module, or an inline `"use server"` function, whose first statement does not await a configured guard; indirect or default exports from server-action modules | Non-exported helpers in server-action modules and test files |
63
- | `statement-spacing` | A missing blank line after the imports, around a multiline block or a multiline declaration, including exported ones, or before `return` | Consecutive imports, consecutive one-line statements, and a type alias directly after the multiline declaration it derives from |
64
- | `no-edit-proof-assertions` | `toBeDefined`, `toBeTruthy` and similar on an imported binding or namespace member; `typeof X` or `toBeTypeOf` against a string on imports; `toBeTypeOf("function")` on anything; `toHaveProperty` on a namespace | Assertions on values produced by running code |
65
- | `no-test-timeout-overrides` | Per-test or per-suite timeout and retry options, `test.setTimeout`, `test.slow()`, `describe.configure`, `vi.setConfig` and `jest.setTimeout` in unit tests | End-to-end files under `e2e/` or named `*.e2e.*` |
66
- | `companion-has-owner` | A `.test`, `.spec` or `.bench` file whose name prefix matches no sibling module or directory, nor its own directory | Files with an `integration` or `e2e` segment and files under `tests/`, `test/`, `__tests__/` or `e2e/` |
67
- | `no-generic-file-suffix` | A file named `*Contract`, `*Policy`, `policy` or `contract` in camel, kebab, snake or dot form | Test and story files, standard header policies such as content security policy, and files exporting a binding with the file's name |
68
- | `no-forwarding-module` | A module made only of re-exports, or imports re-exported unchanged | Package entrypoints in the nearest `package.json`, Next.js `app` special files and `pages`, root `middleware`/`proxy`/`instrumentation`, modules with directives or side-effect imports |
69
- | `no-pass-through-function` | A named function whose body only calls an identifier with exactly its own parameters, in order | Zero-parameter functions, method callees, type predicates and `useEffectEvent` callees |
70
- | `explicit-api-states` | A `boolean`, optional `boolean`, or boolean-defaulted parameter on an exported function, exported class constructor or public method | Destructured parameters, accessors, private members, overloads and the final boolean of a `set*`/`update*` function |
71
- | `no-swallowed-errors` | A `catch` whose body only returns a fallback literal, and a `.catch` callback that is empty or returns one | Built-in parser and filesystem-probe try blocks, `response.json()`, and `.catch` on a promise another caller also receives |
72
- | `no-ambient-clock` | `Date.now()` and argument-less `new Date()`, including through `globalThis`/`window` | Parameter defaults, uncalled `Date.now` and provider functions that only return the read |
73
- | `no-ambient-random` | `Math.random()`, `crypto.randomUUID()`, and `randomUUID`/`randomInt` from `node:crypto` | The same injection seams; `randomBytes` and `getRandomValues`, which generate secrets |
74
- | `electron-no-remote-module` | `remote` from `electron`, and `@electron/remote` by import, `require`, dynamic import or re-export | Other Electron APIs |
75
- | `electron-secure-web-preferences` | `webPreferences` without literal `contextIsolation: true`, `sandbox: true` and `nodeIntegration: false`, or with insecure web security, insecure content, experimental or Blink features; overrides through later keys, spreads or computed keys | Preferences passed from a variable the rule cannot resolve |
76
- | `electron-no-raw-ipc-renderer-exposure` | Exposing `ipcRenderer` or its methods through `contextBridge`, forwarding renderer-chosen channels or arguments, or passing renderer callbacks straight to `on`/`once` | Narrow, named preload functions with fixed channels |
77
-
78
- Test-specific custom rules run on the default test globs, `tests` paths and any explicit Jest or Vitest profile scopes. Their import and binding recognition is deliberately narrower than unrestricted text matching. The tests are the executable reference for supported aliases, shadowing and callback forms.
79
-
80
- ## Type, data and test-double rules
81
-
82
- The base config also enables these rules as errors:
83
-
84
- ```text
85
- no-array-filter-map
86
- no-reduce-accumulator-copy
87
- no-chained-type-assertions
88
- no-conditional-empty-object-spread
89
- no-known-value-widening
90
- no-module-mocking
91
- no-object-parameters
92
- no-reflect-apply
93
- no-reflect-get
94
- no-shape-in-symbol-names
95
- no-unknown-returns
96
- no-unknown-type-aliases
97
- no-unsafe-dictionary-type
98
- no-widen-then-assert
99
- ```
100
-
101
- `no-runtime-typeof` is a warning with `allowInTypeGuards` enabled. Banning `typeof` outright blocks legitimate narrowing of known unions, while the warning still points towards parsing external data with a schema. Projects can turn it off at a validated input seam.
102
-
103
- The optional `effect` profile enables `no-manual-effect-error-tag` and `no-service-constructor-imports`.
104
-
105
- These rules do not have cross-file type knowledge. Their [source files](src/vendor/anti-slop/rules) and tests define the supported same-file alias, scope and inference cases. There is no blanket ban on legitimate `unknown` values or invariant-preserving `as const` expressions.
106
-
107
- ## Project-specific automation
108
-
109
- These policies are enforced once a project names the actual owners. They are intentionally not universal defaults:
110
-
111
- | Policy | Mechanism | Required project information |
112
- | --------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------- |
113
- | Parse configuration at startup | `env` option | Modules that own configuration parsing |
114
- | Keep privileged modules out of other runtimes | `boundaries` option | Each runtime's file scope, and the packages, aliases and paths it must not import |
115
- | Require access checks before server actions | `serverActionGuards` option | The guard functions that perform authorisation |
116
- | Control time and randomness | `clock` and `random` options | Modules that own the clock and ID or random generation |
117
- | Harden Electron apps | `electron` option | Renderer globs when they are not `src/renderer/**` |
118
- | Generated assets and style imports | Shared ignores plus local patterns; Oxfmt Tailwind configuration | Actual generators, CSS preprocessors, Tailwind config or stylesheet |
119
-
120
- ## Compiler settings and review work
121
-
122
- For new TypeScript projects, use `strict`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noImplicitOverride` and `noFallthroughCasesInSwitch`. The package exports them as `@jameswyse/oxc-config/tsconfig` for a project's `tsconfig.json` to extend. Lint configuration never applies them, because changing them in an existing project is a deliberate migration.
123
-
124
- Lint cannot establish correct authorisation, tenant isolation, schema validation, secret redaction, transaction boundaries, idempotency, crash recovery, concurrency ownership, dependency justification, useful module depth, constructive domain modelling or independent test oracles. These remain review and verification work. File naming, positional parameters, boolean inputs, `Partial<T>`, wrappers and abstraction counts have legitimate domain/framework exceptions and are not rejected through universal heuristics.
125
-
126
- ## Oxc API references
127
-
128
- The implementation follows the current [Oxlint configuration API](https://oxc.rs/docs/guide/usage/linter/config.html), [JS plugin API](https://oxc.rs/docs/guide/usage/linter/writing-js-plugins.html), [type-aware setup](https://oxc.rs/docs/guide/usage/linter/type-aware.html), and [Oxfmt options](https://oxc.rs/docs/guide/usage/formatter/config-file-reference.html). Absolute plugin specifiers keep imported configs independent of the consumer's working directory. Side-effect import sorting is explicitly disabled.
129
-
130
- ## Rules considered and dropped
131
-
132
- `no-call-count-assertions` would have rejected `toHaveBeenCalledTimes`, `toHaveBeenNthCalledWith` and `mock.calls` counting. On three codebases, 36 of 40 sampled findings were legitimate: the count was the behaviour under test, such as caching, retry, deduplication or firing once. No syntax separated them from incidental counts, so it was dropped.
133
-
134
- Rules for safety comments on type assertions, a blank line between every top-level statement, and rejecting `unknown` parameters are not included. The first conflicts with `no-comments`, the second split deliberate groups of related declarations, and the third rejected legitimate unparsed input seams. Effect rules that reject `_tag` comparisons, prefer `Match` or reject literal tagged construction are not included either, because discriminant checks are the preferred way to narrow a union and TypeScript already checks literal variants.
3
+ Rules are errors, which fail the run, unless marked as warnings. Warnings flag patterns that have legitimate uses, so they report without failing. Custom rules use the `wyse/` prefix. Each one's tests sit beside it in `src/rules` or `src/vendor/anti-slop/rules` and show exactly what it reports.
4
+
5
+ Framework profiles and project options add rules only when enabled. The [configuration guide](docs/configuration.md) explains how to turn them on.
6
+
7
+ ## Base rules
8
+
9
+ Oxlint's correctness and suspicious categories are errors. Unused variables are errors unless their names start with `_`, and suppression comments that no longer suppress anything are errors too. `no-underscore-dangle` is off, so fields such as `_id` and `__typename` stay valid.
10
+
11
+ Native rules also catch legacy and error-prone built-ins: `no-var`, `no-proto`, `no-new-func`, `no-new-wrappers`, `no-array-constructor`, `no-prototype-builtins`, `prefer-object-has-own`, `prefer-rest-params`, `prefer-regex-literals`, `import/no-mutable-exports`, `oxc/no-const-enum`, and Unicorn's `new-for-builtins`, `no-instanceof-array`, `no-new-buffer`, `prefer-node-protocol`, `prefer-import-meta-properties`, `prefer-response-static-json`, `prefer-string-trim-start-end`, `prefer-array-find`, `prefer-array-flat-map` and `prefer-array-some`.
12
+
13
+ ## Types and external data
14
+
15
+ Native rules: `typescript/no-explicit-any`, `no-non-null-assertion`, `no-unsafe-function-type` and `no-import-type-side-effects`. `consistent-type-assertions` allows only `as` assertions and rejects them on object and array literals, and `method-signature-style` requires property signatures such as `run: () => void`. `ban-ts-comment` rejects `@ts-ignore` and `@ts-nocheck`, and requires a reason after `--` on `@ts-expect-error`.
16
+
17
+ Type-aware checking, which is on by default, adds the `no-unsafe-*` rules, `no-unsafe-type-assertion`, `no-unnecessary-type-assertion`, `switch-exhaustiveness-check`, `prefer-reduce-type-parameter`, `restrict-plus-operands` with every mixed-type allowance turned off, and `no-unnecessary-condition`, a nursery rule in Oxlint 1.86. `typescript/no-deprecated` is a warning outside tests.
18
+
19
+ - `wyse/no-runtime-typeof` (warning): `typeof` outside a type guard. `typeof x === "undefined"` passes, as does `typeof` on a variable or parameter declared in the same file with a union type that has no `unknown` or `any` member. Turn it off in modules that validate external input.
20
+ - `wyse/no-generic-object-guard`: a named helper such as `isRecord` whose whole body proves only that a value is a non-null object, through `typeof`, `instanceof Object`, prototype or `Object.prototype.toString` checks. Guards that also check a field pass, as do inline callbacks. It also reports any guard that takes `unknown` or `any` and claims a specific type while only checking that the value exists, or always returns `true`.
21
+ - `wyse/no-hardcoded-credential`: a string containing a private key or a token in a well-known format, such as an AWS access key or a GitHub, Stripe live, Slack, Google, Anthropic or OpenAI key. Placeholders containing `example`, `fake`, `dummy`, `placeholder`, `redacted` or a run such as `abcdefgh` pass.
22
+ - `wyse/no-disabled-tls-verification`: `rejectUnauthorized: false`, or setting `NODE_TLS_REJECT_UNAUTHORIZED` to `"0"`.
23
+ - `wyse/no-secret-fallback`: a string fallback for an environment variable whose name contains `SECRET`, `TOKEN`, `PASSWORD`, `PRIVATE`, `CREDENTIAL`, `SALT`, `SIGNING` or `API_KEY`, or ends in `KEY`, such as `process.env.SESSION_SECRET ?? "dev"` or a destructuring default.
24
+ - `wyse/type-guard-name`: a named type predicate such as `checkUser(value): value is User`. Names such as `isUser` and `hasId` pass, as do assertion functions and anonymous callbacks.
25
+ - `wyse/no-unknown-returns`: a declared return type of `unknown` or `Promise<unknown>`.
26
+ - `wyse/no-unknown-type-aliases`: a type alias that resolves to `unknown`.
27
+ - `wyse/no-unsafe-dictionary-type`: a dictionary type whose values are `unknown`, `any`, `object` or `{}`.
28
+ - `wyse/no-object-parameters`: a parameter typed `object`, directly or through an alias.
29
+ - `wyse/no-known-value-widening`: a known value stored under a broader declared type, such as `const value: unknown = {}`.
30
+ - `wyse/no-widen-then-assert`: widening a known value, then asserting it to a narrower type.
31
+ - `wyse/no-chained-type-assertions`: chained assertions such as `value as unknown as User`.
32
+ - `wyse/no-reflect-apply` and `wyse/no-reflect-get`: `Reflect.apply` and `Reflect.get`.
33
+
34
+ These custom rules check one file at a time, without type information from other files. None of them bans `unknown` outright or rejects `as const`.
35
+
36
+ ## Control flow and errors
37
+
38
+ Native rules: `curly`, `eqeqeq`, `no-empty`, `no-useless-catch`, Oxlint's promise checks, `array-callback-return`, `no-case-declarations`, `no-constructor-return`, `no-fallthrough`, `no-loop-func`, `no-self-compare`, `no-unreachable-loop`, `no-useless-assignment` and `unicorn/error-message`. JavaScript files also get `no-throw-literal` and `prefer-promise-reject-errors`. Type-aware checking adds floating and misused promise checks, `await-thenable`, `return-await`, `only-throw-error`, `prefer-promise-reject-errors` and `use-unknown-in-catch-callback-variable`.
39
+
40
+ - `wyse/no-deep-ternary`: a ternary nested inside two others. It replaces Oxlint's nested-ternary rule, which conflicts with Oxfmt over parentheses.
41
+ - `wyse/no-swallowed-errors` (warning): a `catch` that only returns a fallback literal, a `.catch` callback or `.then` rejection callback that is empty or only returns one, and `Promise.allSettled` results that are never read. Effect's `orElseSucceed`, `orElse`, `catchAll` and `catchAllCause` count when they recover to a fallback literal or `Effect.void`. Built-in parser and filesystem-probe `try` blocks, `response.json()`, `.catch` on a promise another caller also receives, and Effect's `catchTag` all pass.
42
+ - `wyse/explicit-api-states` (warning): a boolean parameter on an exported function, exported class constructor or public method. Destructured parameters, accessors, private members, overloads, the subject of an `asserts` or `is` return type, and the final boolean of a `set*` or `update*` function pass.
43
+ - `wyse/no-unsettled-promise`: a `new Promise` executor that runs code but never calls `resolve` or `reject`, or calls them only inside an optional call such as `server?.close(resolve)`. Executors that do nothing, such as `() => {}`, pass. Test files aren't checked.
44
+ - `wyse/no-unchecked-index-search`: an `indexOf`, `lastIndexOf`, `findIndex` or `findLastIndex` result passed straight to `splice`, `toSpliced`, `with`, `at` or `slice`, where -1 counts from the end.
45
+ - `wyse/no-unchecked-fetch-response`: reading a `fetch` response body with `json()`, `text()` or a similar method without checking `ok` or `status`. A response passed to another function passes. Test files aren't checked.
46
+
47
+ ## Modules, files and names
48
+
49
+ Native rules: `import/first`, `import/no-default-export`, `import/no-duplicates`, `import/no-self-import` and `import/no-unassigned-import`. `import/no-cycle` and `oxc/no-barrel-file` are warnings. Default exports are allowed in the files that tools load them from, listed in the [configuration guide](docs/configuration.md#select-framework-and-runtime-profiles).
50
+
51
+ - `wyse/no-forwarding-module` (warning): a module made only of re-exports, or one that re-exports its imports unchanged. Package entrypoints, Next.js `app` special files and `pages`, root `middleware`, `proxy` and `instrumentation` files, and modules with directives or side-effect imports pass.
52
+ - `wyse/no-import-time-effects` (warning): starting a timer, `fetch`, top-level `await`, opening a `BroadcastChannel`, `WebSocket`, `EventSource` or `Worker`, calling `addEventListener` or `listen`, or registering `process.on` handlers when a module is imported, including inside immediately invoked functions and static class members. Config files, scripts, tests, and entrypoints such as `main`, `server`, `worker` and `instrumentation` files and `bin`, `cli`, `deploy`, `tools`, `test`, `e2e` and `fixtures` directories pass.
53
+ - `wyse/no-pass-through-function` (warning): a named function whose body only calls another function with its own parameters, in order. Zero-parameter functions, method calls, type predicates and `useEffectEvent` callees pass.
54
+ - `wyse/no-generic-file-suffix`: a file named `*Contract`, `*Policy`, `policy` or `contract`, in any case style. Test and story files pass, as do header policies such as a content security policy and files that export a binding with the file's name, such as `agentPolicy.ts` exporting `AgentPolicy`.
55
+ - `wyse/no-shape-in-symbol-names`: a name containing "shape", in any letter case.
56
+
57
+ ## Comments, suppressions and logging
58
+
59
+ - `wyse/no-comments`: line, block and JSDoc comments. Shebangs, JSDoc type tags in JavaScript files and tool directives pass. The directives include lint suppressions, `@ts-expect-error`, triple-slash references, `#__PURE__`, formatter and coverage ignores, bundler magic comments, and test-environment and JSX pragmas. The `allow` option adds more patterns.
60
+ - `wyse/require-suppression-reason`: an `oxlint-disable` or `eslint-disable` directive that names no rule, or gives no reason after `--`. Oxlint applies a blanket `oxlint-disable` or `oxlint-disable-line` to this rule too, so it can't report those two forms. It does report a blanket `oxlint-disable-next-line`.
61
+ - `eslint/no-console`: console calls outside config files and scripts.
62
+
63
+ ## Mutation and copying
64
+
65
+ Native rules: `prefer-const`, `no-param-reassign` and `oxc/no-accumulating-spread`. Type-aware checking adds `prefer-readonly`.
66
+
67
+ - `wyse/no-array-filter-map`: adjacent `filter` and `map` passes over an array.
68
+ - `wyse/no-reduce-accumulator-copy`: copying a reducer's accumulator with `Object.assign`, `Array.from` or an array copy method.
69
+ - `wyse/no-conditional-empty-object-spread`: spreading a conditional empty object to omit fields, such as `...(id ? { id } : {})`.
70
+
71
+ ## Project ownership
72
+
73
+ These rules run only once the project names its owners through the [project boundary options](docs/configuration.md#enforce-project-boundaries).
74
+
75
+ - `wyse/no-env-access` (`env`): reading `process.env` or `import.meta.env`, or destructuring `env` from either, outside the owners, config files and scripts. It doesn't check that the owner validates what it reads.
76
+ - `wyse/import-boundaries` (`boundaries`): a value import, re-export, literal dynamic import, or `require` call, including a loader made with `createRequire` from `node:module`, that matches a `deny` glob. Type-only imports and `import("…")` types pass unless the boundary sets `types: true`. It doesn't check computed imports.
77
+ - `wyse/server-action-guard` (`serverActionGuards`): a `"use server"` action that doesn't start by awaiting a guard, and indirect or default exports from server-action modules. Non-exported helpers and test files pass.
78
+ - `wyse/no-ambient-clock` (`clock`): `Date.now()` and argument-less `new Date()`, including through `globalThis` or `window`. Parameter defaults, uncalled `Date.now`, provider functions that only return the read, and test files pass.
79
+ - `wyse/no-ambient-random` (`random`): `Math.random()`, `crypto.randomUUID()`, and `randomUUID` or `randomInt` from `node:crypto`. The same exceptions apply. `randomBytes` and `getRandomValues` pass because they generate secrets.
80
+
81
+ ## Tests
82
+
83
+ These rules run on the default test globs, the `tests` paths and the Jest and Vitest profile scopes. The `vitest` and `jest` profiles add native checks for focused, disabled and conditional tests, standalone expectations, valid `expect` calls, interpolated snapshots and redundant async `expect` callbacks. They also require the specific matcher, such as `toStrictEqual` over `toEqual`, `toHaveLength`, `toContain`, and comparison or equality matchers over `toBe(true)`. The `jest` profile rejects `done` callbacks.
84
+
85
+ - `wyse/no-fixed-test-delay`: an awaited literal timer delay, Playwright's `waitForTimeout`, or `yield* Effect.sleep` with a fixed duration. Genuine timer tests need a scoped exception.
86
+ - `wyse/no-vacuous-test-assertions`: an expectation that compares two literals, or the same identifier on both sides of `toBe`, `toEqual` or `toStrictEqual`.
87
+ - `wyse/no-edit-proof-assertions`: an assertion that only proves an import exists or is a function, such as `toBeDefined` on an import, `toBeTypeOf("function")` or `toHaveProperty` on a namespace.
88
+ - `wyse/no-optional-test-action`: a statement directly in a test body that an optional call can skip, such as `button?.click()` or `await dismiss?.click()`. Hooks and callbacks inside the test pass.
89
+ - `wyse/no-derived-test-expectation` (warning): an expected value that calls a function imported from production code, such as `toBe(formatLabel(input))`, directly, through a namespace import or through a `const` such as `expected`. `.not` assertions, functions the actual value also calls, and imports from test, fixture, e2e and helper paths pass.
90
+ - `wyse/no-uncontrolled-test-clock`: `Date.now()` or argument-less `new Date()` in a test file that never calls `useFakeTimers`, `setSystemTime`, `mock.timers.enable`, `clock.install` or `clock.setFixedTime`. Fake timers set up with `apis`, `toFake` or `doNotFake` options that leave `Date` real don't count, and neither does Effect's `TestClock`, which doesn't control `Date`. Playwright and end-to-end files pass.
91
+ - `wyse/no-test-timeout-overrides` (warning): timeout and retry overrides such as `test.setTimeout`, `test.slow()`, `describe.configure`, `vi.setConfig`, `jest.setTimeout` and `jest.retryTimes`. Setting retries to 0 passes. End-to-end files under `e2e/` or named `*.e2e.*` pass.
92
+ - `wyse/companion-has-owner` (warning): a `.test`, `.spec` or `.bench` file with no matching sibling module or directory. Files with an `integration` or `e2e` segment, and files under `tests/`, `test/`, `__tests__/` or `e2e/`, pass.
93
+ - `wyse/no-module-mocking`: Vitest, Jest and `node:test` module mocking. Replace dependencies through real interfaces, or add a file-scoped exception for an external system.
94
+
95
+ ## Framework profiles
96
+
97
+ - `react` adds React and React Compiler rules, `jsx-a11y` correctness and suspicious rules, `react-you-might-not-need-an-effect`, and e18e performance rules outside tests. It includes `react/rules-of-hooks` outside end-to-end and `tests` paths, `no-unknown-property`, `checked-requires-onchange-or-readonly` and `jsx-no-useless-fragment`. It also adds `wyse/no-get-password-form`: a `<form>` with a password or one-time-code input that can submit by GET. An input belongs to the form it sits inside, or to the form its `form` attribute names. The form submits by GET when its `action` is missing or a string and its `method` is missing or anything but `post` or `dialog`, or when one of its submit buttons sets `formMethod` to anything but `post` or `dialog`.
98
+ - `nextjs` adds the React rules plus Next.js rules.
99
+ - `effect` adds `wyse/no-manual-effect-error-tag` and `wyse/no-service-constructor-imports`. The second reports a project-local `make*` import used as an uncalled value, such as `yield* makeIssueService`. Calling a `make*` factory with arguments passes.
100
+ - `electron` adds a renderer import boundary and these rules:
101
+ - `wyse/electron-no-remote-module`: `remote` from `electron`, or `@electron/remote`, by import, `require`, dynamic import or re-export.
102
+ - `wyse/electron-secure-web-preferences`: `webPreferences` without literal `contextIsolation: true`, `sandbox: true` and `nodeIntegration: false`, or with web security disabled, insecure content, or experimental or Blink features enabled. Later keys, spreads and computed keys that override these settings are reported too. Preferences passed from a variable the rule can't resolve pass.
103
+ - `wyse/electron-no-raw-ipc-renderer-exposure`: exposing `ipcRenderer` or its methods through `contextBridge`, forwarding renderer-chosen channels or arguments, or passing renderer callbacks straight to `on` or `once`.
104
+
105
+ ## Formatting
106
+
107
+ Oxfmt formats the code. `wyse/statement-spacing` requires a blank line after the imports, around multiline blocks and declarations, and before `return`. Consecutive imports, consecutive one-line statements, and a type alias directly after the multiline declaration it derives from stay together. It's the only custom rule with an autofix.
package/dist/format.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import type { OxfmtConfig, SortImportsConfig } from "oxfmt";
2
- export declare const formatConfig: OxfmtConfig & {
1
+ import type { OxfmtConfig } from "oxfmt";
2
+ type SortImportsOptions = Exclude<OxfmtConfig["sortImports"], boolean | undefined>;
3
+ export declare const formatConfig: Omit<OxfmtConfig, "ignorePatterns" | "sortImports"> & {
3
4
  ignorePatterns: string[];
4
- sortImports: SortImportsConfig;
5
+ sortImports: SortImportsOptions;
5
6
  };
7
+ export {};