@rdjperron/lint 0.1.0 → 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.
Files changed (69) hide show
  1. package/README.md +146 -57
  2. package/dist/config.d.mts +113 -0
  3. package/dist/config.mjs +218 -0
  4. package/dist/config.mjs.map +1 -0
  5. package/dist/index.d.mts +5 -0
  6. package/dist/{anti-slop.mjs → index.mjs} +253 -94
  7. package/dist/index.mjs.map +1 -0
  8. package/dist/verify.d.mts +92 -0
  9. package/dist/verify.mjs +400 -0
  10. package/dist/verify.mjs.map +1 -0
  11. package/docs/rules/README.md +43 -0
  12. package/docs/rules/no-array-filter-map.md +60 -0
  13. package/docs/rules/no-chained-type-assertions.md +52 -0
  14. package/docs/rules/no-conditional-empty-object-spread.md +50 -0
  15. package/docs/rules/no-hardcoded-jsx-text.md +52 -0
  16. package/docs/rules/no-known-value-widening.md +62 -0
  17. package/docs/rules/no-module-mocking.md +53 -0
  18. package/docs/rules/no-object-parameters.md +55 -0
  19. package/docs/rules/no-reduce-accumulator-copy.md +57 -0
  20. package/docs/rules/no-reflect-apply.md +56 -0
  21. package/docs/rules/no-reflect-get.md +51 -0
  22. package/docs/rules/no-runtime-typeof.md +61 -0
  23. package/docs/rules/no-shape-in-symbol-names.md +53 -0
  24. package/docs/rules/no-unknown-parameters.md +55 -0
  25. package/docs/rules/no-unknown-returns.md +61 -0
  26. package/docs/rules/no-unknown-type-aliases.md +52 -0
  27. package/docs/rules/no-unsafe-dictionary-type.md +56 -0
  28. package/docs/rules/no-use-effect.md +55 -0
  29. package/docs/rules/no-widen-then-assert.md +53 -0
  30. package/docs/rules/require-safety-comment-for-type-assertion.md +59 -0
  31. package/docs/rules/static-public-env.md +55 -0
  32. package/fixtures/README.md +22 -23
  33. package/fixtures/{anti-slop/no-array-filter-map.fixture.ts → no-array-filter-map.fixture.ts} +1 -1
  34. package/fixtures/{anti-slop/no-chained-type-assertions.fixture.ts → no-chained-type-assertions.fixture.ts} +1 -1
  35. package/fixtures/{anti-slop/no-conditional-empty-object-spread.fixture.ts → no-conditional-empty-object-spread.fixture.ts} +1 -1
  36. package/fixtures/{i18n/no-hardcoded-jsx-text.fixture.tsx → no-hardcoded-jsx-text.fixture.tsx} +1 -1
  37. package/fixtures/{anti-slop/no-known-value-widening.fixture.ts → no-known-value-widening.fixture.ts} +1 -1
  38. package/fixtures/{anti-slop/no-module-mocking.fixture.ts → no-module-mocking.fixture.ts} +1 -1
  39. package/fixtures/{anti-slop/no-object-parameters.fixture.ts → no-object-parameters.fixture.ts} +1 -1
  40. package/fixtures/{anti-slop/no-reduce-accumulator-copy.fixture.ts → no-reduce-accumulator-copy.fixture.ts} +1 -1
  41. package/fixtures/{anti-slop/no-reflect-apply.fixture.ts → no-reflect-apply.fixture.ts} +1 -1
  42. package/fixtures/{anti-slop/no-reflect-get.fixture.ts → no-reflect-get.fixture.ts} +1 -1
  43. package/fixtures/{anti-slop/no-runtime-typeof.fixture.ts → no-runtime-typeof.fixture.ts} +1 -1
  44. package/fixtures/no-shape-in-symbol-names.fixture.ts +2 -0
  45. package/fixtures/{anti-slop/no-unknown-parameters.fixture.ts → no-unknown-parameters.fixture.ts} +1 -1
  46. package/fixtures/{anti-slop/no-unknown-returns.fixture.ts → no-unknown-returns.fixture.ts} +1 -1
  47. package/fixtures/no-unknown-type-aliases.fixture.ts +2 -0
  48. package/fixtures/no-unsafe-dictionary-type.fixture.ts +2 -0
  49. package/fixtures/{react/no-use-effect.fixture.tsx → no-use-effect.fixture.tsx} +1 -1
  50. package/fixtures/{anti-slop/no-widen-then-assert.fixture.ts → no-widen-then-assert.fixture.ts} +1 -1
  51. package/fixtures/{anti-slop/require-safety-comment-for-type-assertion.fixture.ts → require-safety-comment-for-type-assertion.fixture.ts} +1 -1
  52. package/fixtures/{expo/static-public-env.fixture.ts → static-public-env.fixture.ts} +1 -1
  53. package/package.json +27 -26
  54. package/dist/anti-slop.d.mts +0 -6
  55. package/dist/anti-slop.mjs.map +0 -1
  56. package/dist/expo.d.mts +0 -5
  57. package/dist/expo.mjs +0 -51
  58. package/dist/expo.mjs.map +0 -1
  59. package/dist/i18n.d.mts +0 -5
  60. package/dist/i18n.mjs +0 -50
  61. package/dist/i18n.mjs.map +0 -1
  62. package/dist/react.d.mts +0 -5
  63. package/dist/react.mjs +0 -73
  64. package/dist/react.mjs.map +0 -1
  65. package/dist/rule-options-DrAXz8BD.mjs +0 -18
  66. package/dist/rule-options-DrAXz8BD.mjs.map +0 -1
  67. package/fixtures/anti-slop/no-shape-in-symbol-names.fixture.ts +0 -2
  68. package/fixtures/anti-slop/no-unknown-type-aliases.fixture.ts +0 -2
  69. package/fixtures/anti-slop/no-unsafe-dictionary-type.fixture.ts +0 -2
package/README.md CHANGED
@@ -1,18 +1,20 @@
1
1
  # @rdjperron/lint
2
2
 
3
- Oxlint JS plugins in four packs. Each pack is one plugin, registered on its own, so a project
4
- enables only what it wants.
3
+ One Oxlint JS plugin, `rdj`, with twenty rules against low-evidence code, the config data a
4
+ project spreads into its own `vite.config.ts`, and the check that proves every rule still fires.
5
5
 
6
- | Pack | Plugin name | Rules |
7
- | ----------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
8
- | `anti-slop` | `anti-slop` | 17 rules that reject low-evidence patterns: `unknown` contracts, unjustified type assertions, `Reflect` calls, runtime `typeof`, module mocking, and so on. |
9
- | `react` | `react-policy` | `no-use-effect`: reports every `useEffect` and `useLayoutEffect` call or import. |
10
- | `i18n` | `i18n` | `no-hardcoded-jsx-text`: reports words written straight into JSX children. |
11
- | `expo` | `expo` | `static-public-env`: allows only `process.env.NAME` reads, the one form Expo inlines at bundle time. |
6
+ | Entry | What it gives you |
7
+ | ---------------------------- | ------------------------------------------------------------------------------------ |
8
+ | `@rdjperron/lint` | The plugin. One `jsPlugins` entry, one prefix, twenty rules. |
9
+ | `@rdjperron/lint/config` | `recommended`, the override builders, and the `fmt`, `ignore` and `staged` blocks. |
10
+ | `@rdjperron/lint/verify` | `verifySuites`, `packageSuite`, `verifyPluginApiPin`, and the `rdj-lint-verify` bin. |
11
+ | `@rdjperron/lint/fixtures/*` | One deliberately violating file per rule, the input the verify command lints. |
12
12
 
13
- `anti-slop` is a copy of [dmmulroy/anti-slop](https://github.com/dmmulroy/anti-slop), owned and
14
- edited here (see `src/anti-slop/VENDORED.md` in the source repo). The plugin name is `react-policy`
15
- and not `react` because oxlint has a built-in plugin called `react`.
13
+ Seventeen of the rules are a copy of [dmmulroy/anti-slop](https://github.com/dmmulroy/anti-slop),
14
+ owned and edited here (`src/anti-slop/VENDORED.md` in the source repo records the commit). The
15
+ other three are written here.
16
+
17
+ Tested on vite-plus 0.3.1, oxlint 1.81.0 and `@oxlint/plugins` 1.79.0 (2026-09-17).
16
18
 
17
19
  ## Install
18
20
 
@@ -30,59 +32,146 @@ vp why @oxlint/plugins
30
32
  # or: node -p "require('vite-plus/package.json').dependencies['@oxlint/plugins']"
31
33
  ```
32
34
 
33
- Pin `@oxlint/plugins` exactly to that number. The peer range in this package is a caret so an
34
- exact pin anywhere in the same major satisfies it. Move the pin every time `vp` moves.
35
-
36
- ## Register a pack
35
+ Pin `@oxlint/plugins` exactly to that number. The peer range here is a caret, so an exact pin
36
+ anywhere in the same major satisfies it. Move the pin every time `vp` moves; `rdj-lint-verify`
37
+ fails when the two drift apart.
37
38
 
38
- Each pack is a `jsPlugins` entry with its name and its specifier, then rules by `<name>/<rule>`:
39
+ ## Use it
39
40
 
40
41
  ```ts
41
- // vite.config.ts (or .oxlintrc.json, same shape)
42
+ // vite.config.ts
43
+ import { fixtures, fmt, ignore, react, recommended, staged, tests } from "@rdjperron/lint/config";
44
+ import { defineConfig } from "vite-plus";
45
+
42
46
  export default defineConfig({
47
+ staged,
48
+ fmt: { ...fmt, ignorePatterns: ignore },
43
49
  lint: {
44
- jsPlugins: [
45
- { name: "anti-slop", specifier: "@rdjperron/lint/anti-slop" },
46
- { name: "react-policy", specifier: "@rdjperron/lint/react" },
47
- { name: "i18n", specifier: "@rdjperron/lint/i18n" },
48
- { name: "expo", specifier: "@rdjperron/lint/expo" },
50
+ extends: [recommended],
51
+ plugins: ["typescript", "unicorn", "oxc", "import", "promise", "node"],
52
+ categories: { correctness: "error", suspicious: "warn", perf: "warn" },
53
+ env: { builtin: true, node: true },
54
+ overrides: [
55
+ ...react(["app/**"], { useEffectAllowedIn: "hooks/use-mount-effect.ts" }),
56
+ ...tests(["**/*.test.ts", "**/*.test.tsx"]),
57
+ ...fixtures(),
49
58
  ],
50
- rules: {
51
- "anti-slop/no-reflect-get": "error",
52
- "react-policy/no-use-effect": [
53
- "error",
54
- { hint: "The one sanctioned wrapper is useMountEffect." },
55
- ],
56
- "i18n/no-hardcoded-jsx-text": "error",
57
- "expo/static-public-env": "error",
58
- },
59
+ options: { typeAware: true, typeCheck: true },
60
+ ignorePatterns: ignore,
59
61
  },
60
62
  });
61
63
  ```
62
64
 
63
- Measure before promoting: land a new rule at `warn`, fix or scope what fires, then move it to
64
- `error`. The anti-slop severities this package's own repo settled on are in its root
65
- `vite.config.ts`.
66
-
67
- ### Rule options
68
-
69
- - `react-policy/no-use-effect` takes `{ hint?: string }`. The hint is appended to every finding,
70
- so a project can name its one sanctioned wrapper. Exempt that wrapper's file with an override.
71
- - `i18n/no-hardcoded-jsx-text` takes `{ pattern?: string }`, a regex source compiled with the
72
- `u` flag. The default `\p{L}{3,}` says three letters in a row is a word; digits, separators and
73
- bullets are not. It looks at JSX text and at string literals placed as children, never at
74
- attribute values.
75
- - `expo/static-public-env` has no options. It reports destructuring of `process.env`, computed
76
- access, and `process.env` used as a value (assigned, passed, spread, returned).
77
-
78
- ## The fixtures ship with the package
79
-
80
- `fixtures/<pack>/<rule>.fixture.ts(x)` is one deliberately violating file per rule. A rule can
81
- go silently dead (a linter upgrade, a plugin API skew, an ignore pattern that swallows the wrong
82
- path), and "reports nothing" looks exactly like "no violations". The consumer's verify script
83
- lints each fixture directory through its own pipeline and asserts that every rule fired on the
84
- file named after it. The source repo's `scripts/verify-lint-fixtures.mjs` is the reference
85
- implementation; copy it and point its suites at
86
- `node_modules/@rdjperron/lint/fixtures/<pack>`. oxlint skips `node_modules`, so the script lints
87
- through a symlinked view outside it, and that view must never be gitignored (oxlint honours
88
- `.gitignore`, and a gitignored view silently disables the whole check).
65
+ `jsPlugins` needs no entry: `recommended` carries it. Registering by hand works too, in either
66
+ form, because the plugin declares its own `meta.name`:
67
+
68
+ ```ts
69
+ jsPlugins: ["@rdjperron/lint"];
70
+ jsPlugins: [{ name: "rdj", specifier: "@rdjperron/lint" }];
71
+ ```
72
+
73
+ ### What `extends` carries, and what it does not
74
+
75
+ Measured on vite-plus 0.3.1 and oxlint 1.81.0 (2026-09-17), with a base config object passed to
76
+ `lint.extends`:
77
+
78
+ | Field | Inherited |
79
+ | --------------------------------------------------------------------- | --------------------------------------- |
80
+ | `jsPlugins`, `rules`, `overrides`, `plugins`, `categories`, `options` | yes, and the consumer's own entries win |
81
+ | `env`, `settings`, `ignorePatterns` | no, the consumer writes its own |
82
+
83
+ So `recommended` carries a plugin entry and rules, nothing else. Write `plugins`, `categories`,
84
+ `env`, `options` and `ignorePatterns` in your own config; `ignore` is an array you spread into
85
+ `ignorePatterns`, not a field you inherit.
86
+
87
+ Two more things oxlint does quietly. An override that changes a built-in plugin's rule must
88
+ repeat that plugin in its own `plugins`, even when an earlier override already listed it, or the
89
+ entry is dropped with no error. And a relative plugin specifier inside an `extends` object is
90
+ refused; a package name is what works.
91
+
92
+ ### The config exports
93
+
94
+ | Export | What it is |
95
+ | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
96
+ | `plugin` | `{ name: "rdj", specifier: "@rdjperron/lint" }`. |
97
+ | `RULE_IDS`, `RuleId` | The twenty prefixed ids, as a readonly tuple and as a type. |
98
+ | `recommended` | The config object for `lint.extends`: the plugin entry, the rules below, and the built-in choices. |
99
+ | `react(files, options?)` | Browser globals, the hooks rules and the compiler's rules. `options.useEffectAllowedIn` names the one file allowed to call `useEffect`, puts its name in every finding, and switches the rule off for it. |
100
+ | `i18n(files, options?)` | `rdj/no-hardcoded-jsx-text` at error. `options.pattern` sets the word pattern. |
101
+ | `expo(files)` | `rdj/static-public-env` at error. |
102
+ | `tests(files)` | `any`, `!`, `no-runtime-typeof` and the safety-comment rule off, with the reason on each. |
103
+ | `fixtures(view?)` | Every rule at error on the verify view, `scripts/.lint-fixtures/**` by default. |
104
+ | `fmt` | `printWidth` 100, double quotes, semicolons, two spaces. |
105
+ | `ignore` | Dependencies, build output, the AI agent directories and the Vitest JSON report. |
106
+ | `staged` | `vp check --fix` on JS and TS sources. |
107
+
108
+ `recommended` puts every rule at `error` except `no-hardcoded-jsx-text` and `static-public-env`,
109
+ which belong to a translated app and to an Expo app and are left to `i18n()` and `expo()`. The
110
+ measurements behind those severities are in the comments beside them.
111
+
112
+ ## Prove the rules still fire
113
+
114
+ ```bash
115
+ npx rdj-lint-verify
116
+ ```
117
+
118
+ The fixtures ship in the package: `fixtures/<rule>.fixture.ts(x)` is one deliberately violating
119
+ file per rule. The command lints them through your own `vp lint` and asserts a positive, that
120
+ every rule fired on the file named after it, then checks the `@oxlint/plugins` pin. A rule can
121
+ go silently dead after a linter upgrade or a plugin API skew, and "reports nothing" looks exactly
122
+ like "no violations". Nothing else notices.
123
+
124
+ Your config has to carry `fixtures()` in its overrides, on the view path the command uses
125
+ (`scripts/.lint-fixtures/rdj` sits under the default `scripts/.lint-fixtures/**`). This is not a
126
+ convenience: `-A`, `-W` and `-D` reach built-in rules only and cannot switch a JS plugin rule on,
127
+ so the override is the only way the rules you leave off on your own code get proven.
128
+
129
+ Two things not to do. Do not gitignore the view: oxlint honours `.gitignore`, so an ignored view
130
+ reports zero files instead of a dead rule. And do not delete the fixtures.
131
+
132
+ A repo with a second plugin to check imports `verifySuites` and describes both suites itself; the
133
+ source repo's `scripts/verify-lint-fixtures.mjs` is the example.
134
+
135
+ ## The rules
136
+
137
+ Each page explains what the rule rejects, what to write instead, and what it deliberately allows.
138
+
139
+ | Rule | What it rejects |
140
+ | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
141
+ | [`rdj/no-array-filter-map`](docs/rules/no-array-filter-map.md) | `filter().map()`, two passes and an intermediate array. |
142
+ | [`rdj/no-chained-type-assertions`](docs/rules/no-chained-type-assertions.md) | `x as unknown as T`, an assertion laundered through a second one. |
143
+ | [`rdj/no-conditional-empty-object-spread`](docs/rules/no-conditional-empty-object-spread.md) | `...(cond ? { a } : {})`, omission hidden behind an empty object. |
144
+ | [`rdj/no-hardcoded-jsx-text`](docs/rules/no-hardcoded-jsx-text.md) | Words written straight into JSX children. |
145
+ | [`rdj/no-known-value-widening`](docs/rules/no-known-value-widening.md) | An annotation that throws away what inference already knew. |
146
+ | [`rdj/no-module-mocking`](docs/rules/no-module-mocking.md) | `vi.mock` and friends, a test of the mock rather than the module. |
147
+ | [`rdj/no-object-parameters`](docs/rules/no-object-parameters.md) | The bare `object` type on a function input. |
148
+ | [`rdj/no-reduce-accumulator-copy`](docs/rules/no-reduce-accumulator-copy.md) | Spreading the accumulator inside `reduce`, quadratic by construction. |
149
+ | [`rdj/no-reflect-apply`](docs/rules/no-reflect-apply.md) | `Reflect.apply`, a call the types cannot follow. |
150
+ | [`rdj/no-reflect-get`](docs/rules/no-reflect-get.md) | `Reflect.get`, a property read the types cannot follow. |
151
+ | [`rdj/no-runtime-typeof`](docs/rules/no-runtime-typeof.md) | `typeof` as a substitute for parsing input at its boundary. |
152
+ | [`rdj/no-shape-in-symbol-names`](docs/rules/no-shape-in-symbol-names.md) | "shape" in a symbol name, structure in place of a domain role. |
153
+ | [`rdj/no-unknown-parameters`](docs/rules/no-unknown-parameters.md) | `unknown` on a function input. |
154
+ | [`rdj/no-unknown-returns`](docs/rules/no-unknown-returns.md) | `unknown` on a function output. |
155
+ | [`rdj/no-unknown-type-aliases`](docs/rules/no-unknown-type-aliases.md) | A type alias that resolves to `unknown`. |
156
+ | [`rdj/no-unsafe-dictionary-type`](docs/rules/no-unsafe-dictionary-type.md) | A dictionary whose values are `unknown`, `any` or `object`. |
157
+ | [`rdj/no-use-effect`](docs/rules/no-use-effect.md) | Every `useEffect` and `useLayoutEffect` call or import. |
158
+ | [`rdj/no-widen-then-assert`](docs/rules/no-widen-then-assert.md) | Widening a value and asserting it back. |
159
+ | [`rdj/require-safety-comment-for-type-assertion`](docs/rules/require-safety-comment-for-type-assertion.md) | An assertion with no `SAFETY:` line naming the invariant. |
160
+ | [`rdj/static-public-env`](docs/rules/static-public-env.md) | Any `process.env` read but `process.env.NAME`, the one form Expo inlines. |
161
+
162
+ ### Options
163
+
164
+ - `rdj/no-use-effect` takes `{ hint?: string }`, appended to every finding, so a project can name
165
+ its one sanctioned wrapper. `react(files, { useEffectAllowedIn })` sets it and exempts that file.
166
+ - `rdj/no-hardcoded-jsx-text` takes `{ pattern?: string }`, a regex source compiled with `u`. The
167
+ default `\p{L}{3,}` says three letters in a row is a word; digits, separators and bullets are
168
+ not. It looks at JSX text and at string literals placed as children, never at attribute values.
169
+ - `rdj/no-runtime-typeof` takes `{ allowInTypeGuards?: boolean }`. `recommended` turns it on: a
170
+ `typeof` inside a type predicate is the decode the rule asks for, named and reusable.
171
+ - `rdj/static-public-env` has no options.
172
+
173
+ ## Severities are measurements
174
+
175
+ Land a new rule at `warn`, fix or scope what fires, then promote it. When a rule fires, fix the
176
+ code or add a narrowly scoped override with the measurement that justifies it. Never weaken the
177
+ rule, add a cast, or rename a symbol to dodge the check.
@@ -0,0 +1,113 @@
1
+ //#region src/config.d.ts
2
+ /**
3
+ * Config data for a consumer's `vite.config.ts` (or `.oxlintrc.ts`).
4
+ *
5
+ * The types below are declared locally rather than imported from `oxlint`:
6
+ * `oxlint` is never a dependency of this package (`vp migrate` strips one, and a
7
+ * direct dependency installs a second linter beside the Vite+ IDE stub), and a
8
+ * consumer that installs only `vite-plus` and `@oxlint/plugins` has no
9
+ * guaranteed path to oxlint's own `.d.ts`. They are structurally compatible with
10
+ * `OxlintConfig` and `OxlintOverride`, checked by a consumer-shaped config in
11
+ * `tests/config.test.ts`: arrays are mutable (oxlint's are), and `plugins` is
12
+ * oxlint's own literal union, because a bare `string[]` is not assignable to it.
13
+ */
14
+ /** A severity as oxlint spells it in a config; the numeric forms are not used here. */
15
+ type Severity = "off" | "warn" | "error";
16
+ /** A rule entry: a severity, or a severity followed by the rule's own options. */
17
+ type RuleEntry = Severity | [Severity, ...unknown[]];
18
+ interface Rules {
19
+ [ruleId: string]: RuleEntry;
20
+ }
21
+ /** oxlint's built-in plugins, the values its `plugins` field accepts. */
22
+ type BuiltinPlugin = "eslint" | "import" | "jest" | "jsdoc" | "jsx-a11y" | "nextjs" | "node" | "oxc" | "promise" | "react" | "react-perf" | "typescript" | "unicorn" | "vitest" | "vue";
23
+ interface JsPlugin {
24
+ name: string;
25
+ specifier: string;
26
+ }
27
+ export interface Override {
28
+ files: string[];
29
+ excludeFiles?: string[];
30
+ plugins?: BuiltinPlugin[];
31
+ env?: {
32
+ [name: string]: boolean;
33
+ };
34
+ jsPlugins?: JsPlugin[];
35
+ rules?: Rules;
36
+ }
37
+ export interface Config {
38
+ jsPlugins?: JsPlugin[];
39
+ rules?: Rules;
40
+ overrides?: Override[];
41
+ }
42
+ /**
43
+ * The plugin entry. The alias is `rdj`, which is also the prefix in every
44
+ * diagnostic and every disable comment, so a consumer that renames it renames
45
+ * its own rule keys too.
46
+ */
47
+ export declare const plugin: JsPlugin;
48
+ /** Every rule the plugin registers, prefixed. `fixtures()` and the verify bin read this list. */
49
+ export declare const RULE_IDS: readonly ["rdj/no-array-filter-map", "rdj/no-chained-type-assertions", "rdj/no-conditional-empty-object-spread", "rdj/no-hardcoded-jsx-text", "rdj/no-known-value-widening", "rdj/no-module-mocking", "rdj/no-object-parameters", "rdj/no-reduce-accumulator-copy", "rdj/no-reflect-apply", "rdj/no-reflect-get", "rdj/no-runtime-typeof", "rdj/no-shape-in-symbol-names", "rdj/no-unknown-parameters", "rdj/no-unknown-returns", "rdj/no-unknown-type-aliases", "rdj/no-unsafe-dictionary-type", "rdj/no-use-effect", "rdj/no-widen-then-assert", "rdj/require-safety-comment-for-type-assertion", "rdj/static-public-env"];
50
+ export type RuleId = (typeof RULE_IDS)[number];
51
+ /**
52
+ * The base config, for `lint: { extends: [recommended] }`.
53
+ *
54
+ * Measured through `extends` on vite-plus 0.3.1 / oxlint 1.81.0 (2026-09-17):
55
+ * `jsPlugins`, `rules`, `overrides`, `plugins`, `categories` and `options` are
56
+ * inherited by the consumer's config, and the consumer's own entries win.
57
+ * `env`, `settings` and `ignorePatterns` are not inherited, which is why this
58
+ * object carries none of them and the consumer keeps writing its own.
59
+ */
60
+ export declare const recommended: Config;
61
+ export interface ReactOptions {
62
+ /**
63
+ * The one file allowed to call `useEffect`, as a path. Its name goes into the
64
+ * `no-use-effect` hint for every React file, and the rule is off for it.
65
+ */
66
+ useEffectAllowedIn?: string;
67
+ }
68
+ /**
69
+ * The React file set: browser globals, the hooks rules, and the compiler's own
70
+ * judgement. A consumer appends its own entries after these, because an override
71
+ * that changes a `react/*` rule must repeat `plugins: ["react"]` or oxlint
72
+ * silently drops the entry.
73
+ */
74
+ export declare function react(files: string[], options?: ReactOptions): Override[];
75
+ export interface I18nOptions {
76
+ /**
77
+ * The word pattern, a regex source compiled with `u`. The rule's default,
78
+ * `\p{L}{3,}`, reads three letters in a row as a word.
79
+ */
80
+ pattern?: string;
81
+ }
82
+ /** Files whose JSX text belongs in a catalogue rather than in the source. */
83
+ export declare function i18n(files: string[], options?: I18nOptions): Override[];
84
+ /** Files Expo's bundler inlines `process.env` into, where only `process.env.NAME` survives. */
85
+ export declare function expo(files: string[]): Override[];
86
+ /** Test files: four rules whose premise a test does not hold. */
87
+ export declare function tests(files: string[]): Override[];
88
+ /**
89
+ * The view the verify command lints the shipped fixtures through. Without this
90
+ * override every rule the consumer leaves off reports nothing there, and "no
91
+ * findings" is exactly what a dead rule looks like.
92
+ */
93
+ export declare function fixtures(view?: string): Override[];
94
+ /** The formatting both consumers settled on. Spread it and add what is yours. */
95
+ export declare const fmt: {
96
+ printWidth: number;
97
+ singleQuote: boolean;
98
+ semi: boolean;
99
+ tabWidth: number;
100
+ useTabs: boolean;
101
+ };
102
+ /**
103
+ * Paths no linter and no formatter should walk: build output, dependencies, the
104
+ * directories AI coding agents scribble in, and the Vitest JSON report. Spread
105
+ * it into `ignorePatterns` and append the repo's own.
106
+ */
107
+ export declare const ignore: string[];
108
+ /** The pre-commit entry: `vp check --fix` is defined for JS and TS sources, nothing else. */
109
+ export declare const staged: {
110
+ "*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}": string;
111
+ };
112
+ //#endregion
113
+ //# sourceMappingURL=config.d.mts.map
@@ -0,0 +1,218 @@
1
+ //#region src/config.ts
2
+ /**
3
+ * The plugin entry. The alias is `rdj`, which is also the prefix in every
4
+ * diagnostic and every disable comment, so a consumer that renames it renames
5
+ * its own rule keys too.
6
+ */
7
+ const plugin = {
8
+ name: "rdj",
9
+ specifier: "@rdjperron/lint"
10
+ };
11
+ /** Every rule the plugin registers, prefixed. `fixtures()` and the verify bin read this list. */
12
+ const RULE_IDS = [
13
+ "rdj/no-array-filter-map",
14
+ "rdj/no-chained-type-assertions",
15
+ "rdj/no-conditional-empty-object-spread",
16
+ "rdj/no-hardcoded-jsx-text",
17
+ "rdj/no-known-value-widening",
18
+ "rdj/no-module-mocking",
19
+ "rdj/no-object-parameters",
20
+ "rdj/no-reduce-accumulator-copy",
21
+ "rdj/no-reflect-apply",
22
+ "rdj/no-reflect-get",
23
+ "rdj/no-runtime-typeof",
24
+ "rdj/no-shape-in-symbol-names",
25
+ "rdj/no-unknown-parameters",
26
+ "rdj/no-unknown-returns",
27
+ "rdj/no-unknown-type-aliases",
28
+ "rdj/no-unsafe-dictionary-type",
29
+ "rdj/no-use-effect",
30
+ "rdj/no-widen-then-assert",
31
+ "rdj/require-safety-comment-for-type-assertion",
32
+ "rdj/static-public-env"
33
+ ];
34
+ /**
35
+ * The base config, for `lint: { extends: [recommended] }`.
36
+ *
37
+ * Measured through `extends` on vite-plus 0.3.1 / oxlint 1.81.0 (2026-09-17):
38
+ * `jsPlugins`, `rules`, `overrides`, `plugins`, `categories` and `options` are
39
+ * inherited by the consumer's config, and the consumer's own entries win.
40
+ * `env`, `settings` and `ignorePatterns` are not inherited, which is why this
41
+ * object carries none of them and the consumer keeps writing its own.
42
+ */
43
+ const recommended = {
44
+ jsPlugins: [plugin],
45
+ rules: {
46
+ "rdj/no-array-filter-map": "error",
47
+ "rdj/no-chained-type-assertions": "error",
48
+ "rdj/no-conditional-empty-object-spread": "error",
49
+ "rdj/no-known-value-widening": "error",
50
+ "rdj/no-module-mocking": "error",
51
+ "rdj/no-object-parameters": "error",
52
+ "rdj/no-reduce-accumulator-copy": "error",
53
+ "rdj/no-reflect-apply": "error",
54
+ "rdj/no-reflect-get": "error",
55
+ "rdj/no-runtime-typeof": ["error", { allowInTypeGuards: true }],
56
+ "rdj/no-shape-in-symbol-names": "error",
57
+ "rdj/no-unknown-parameters": "error",
58
+ "rdj/no-unknown-returns": "error",
59
+ "rdj/no-unknown-type-aliases": "error",
60
+ "rdj/no-unsafe-dictionary-type": "error",
61
+ "rdj/no-widen-then-assert": "error",
62
+ "rdj/require-safety-comment-for-type-assertion": "error",
63
+ "rdj/no-use-effect": "error",
64
+ "typescript/no-floating-promises": "error",
65
+ "typescript/no-misused-promises": "error",
66
+ "typescript/await-thenable": "error",
67
+ "typescript/no-unnecessary-type-assertion": "error",
68
+ "typescript/no-misused-spread": "error",
69
+ "typescript/require-array-sort-compare": "error",
70
+ "typescript/no-explicit-any": "warn",
71
+ "prefer-const": ["error", { destructuring: "all" }],
72
+ "no-unused-vars": ["error", {
73
+ argsIgnorePattern: "^_",
74
+ varsIgnorePattern: "^_"
75
+ }],
76
+ "no-underscore-dangle": "off",
77
+ eqeqeq: [
78
+ "error",
79
+ "always",
80
+ { null: "ignore" }
81
+ ],
82
+ "typescript/no-unsafe-type-assertion": "off",
83
+ "no-await-in-loop": "off",
84
+ "unicorn/consistent-function-scoping": "off",
85
+ "promise/always-return": "off"
86
+ }
87
+ };
88
+ /**
89
+ * The React file set: browser globals, the hooks rules, and the compiler's own
90
+ * judgement. A consumer appends its own entries after these, because an override
91
+ * that changes a `react/*` rule must repeat `plugins: ["react"]` or oxlint
92
+ * silently drops the entry.
93
+ */
94
+ function react(files, options = {}) {
95
+ const { useEffectAllowedIn } = options;
96
+ const rules = {
97
+ "react/rules-of-hooks": "error",
98
+ "react/exhaustive-deps": "warn",
99
+ "react/react-in-jsx-scope": "off",
100
+ "react/immutability": "error",
101
+ "react/refs": "error",
102
+ "react/purity": "error",
103
+ "react/only-export-components": "error"
104
+ };
105
+ const overrides = [{
106
+ files,
107
+ plugins: ["react"],
108
+ env: { browser: true },
109
+ rules
110
+ }];
111
+ if (useEffectAllowedIn !== void 0) {
112
+ rules["rdj/no-use-effect"] = ["error", { hint: `The one sanctioned wrapper is ${useEffectAllowedIn}.` }];
113
+ overrides.push({
114
+ files: [useEffectAllowedIn],
115
+ rules: { "rdj/no-use-effect": "off" }
116
+ });
117
+ }
118
+ return overrides;
119
+ }
120
+ /** Files whose JSX text belongs in a catalogue rather than in the source. */
121
+ function i18n(files, options = {}) {
122
+ const { pattern } = options;
123
+ return [{
124
+ files,
125
+ rules: { "rdj/no-hardcoded-jsx-text": pattern === void 0 ? "error" : ["error", { pattern }] }
126
+ }];
127
+ }
128
+ /** Files Expo's bundler inlines `process.env` into, where only `process.env.NAME` survives. */
129
+ function expo(files) {
130
+ return [{
131
+ files,
132
+ rules: { "rdj/static-public-env": "error" }
133
+ }];
134
+ }
135
+ /** Test files: four rules whose premise a test does not hold. */
136
+ function tests(files) {
137
+ return [{
138
+ files,
139
+ rules: {
140
+ "typescript/no-explicit-any": "off",
141
+ "typescript/no-non-null-assertion": "off",
142
+ "rdj/no-runtime-typeof": "off",
143
+ "rdj/require-safety-comment-for-type-assertion": "off"
144
+ }
145
+ }];
146
+ }
147
+ /** Every rule of the plugin at `error`, so none of them can be missing from the list. */
148
+ const FIXTURE_RULES = {
149
+ "rdj/no-array-filter-map": "error",
150
+ "rdj/no-chained-type-assertions": "error",
151
+ "rdj/no-conditional-empty-object-spread": "error",
152
+ "rdj/no-hardcoded-jsx-text": "error",
153
+ "rdj/no-known-value-widening": "error",
154
+ "rdj/no-module-mocking": "error",
155
+ "rdj/no-object-parameters": "error",
156
+ "rdj/no-reduce-accumulator-copy": "error",
157
+ "rdj/no-reflect-apply": "error",
158
+ "rdj/no-reflect-get": "error",
159
+ "rdj/no-runtime-typeof": "error",
160
+ "rdj/no-shape-in-symbol-names": "error",
161
+ "rdj/no-unknown-parameters": "error",
162
+ "rdj/no-unknown-returns": "error",
163
+ "rdj/no-unknown-type-aliases": "error",
164
+ "rdj/no-unsafe-dictionary-type": "error",
165
+ "rdj/no-use-effect": "error",
166
+ "rdj/no-widen-then-assert": "error",
167
+ "rdj/require-safety-comment-for-type-assertion": "error",
168
+ "rdj/static-public-env": "error"
169
+ };
170
+ /**
171
+ * The view the verify command lints the shipped fixtures through. Without this
172
+ * override every rule the consumer leaves off reports nothing there, and "no
173
+ * findings" is exactly what a dead rule looks like.
174
+ */
175
+ function fixtures(view = "scripts/.lint-fixtures/**") {
176
+ return [{
177
+ files: [view],
178
+ rules: { ...FIXTURE_RULES }
179
+ }];
180
+ }
181
+ /** The formatting both consumers settled on. Spread it and add what is yours. */
182
+ const fmt = {
183
+ printWidth: 100,
184
+ singleQuote: false,
185
+ semi: true,
186
+ tabWidth: 2,
187
+ useTabs: false
188
+ };
189
+ /**
190
+ * Paths no linter and no formatter should walk: build output, dependencies, the
191
+ * directories AI coding agents scribble in, and the Vitest JSON report. Spread
192
+ * it into `ignorePatterns` and append the repo's own.
193
+ */
194
+ const ignore = [
195
+ "node_modules/**",
196
+ "**/node_modules/**",
197
+ "dist/**",
198
+ "**/dist/**",
199
+ ...[
200
+ ".agents",
201
+ ".claude",
202
+ ".codex",
203
+ ".continue",
204
+ ".cursor",
205
+ ".gemini",
206
+ ".opencode",
207
+ ".pi",
208
+ ".roo",
209
+ ".windsurf"
210
+ ].flatMap((dir) => [`${dir}/**`, `**/${dir}/**`]),
211
+ "**/test-results.json"
212
+ ];
213
+ /** The pre-commit entry: `vp check --fix` is defined for JS and TS sources, nothing else. */
214
+ const staged = { "*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}": "vp check --fix" };
215
+ //#endregion
216
+ export { RULE_IDS, expo, fixtures, fmt, i18n, ignore, plugin, react, recommended, staged, tests };
217
+
218
+ //# sourceMappingURL=config.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["/**\n * Config data for a consumer's `vite.config.ts` (or `.oxlintrc.ts`).\n *\n * The types below are declared locally rather than imported from `oxlint`:\n * `oxlint` is never a dependency of this package (`vp migrate` strips one, and a\n * direct dependency installs a second linter beside the Vite+ IDE stub), and a\n * consumer that installs only `vite-plus` and `@oxlint/plugins` has no\n * guaranteed path to oxlint's own `.d.ts`. They are structurally compatible with\n * `OxlintConfig` and `OxlintOverride`, checked by a consumer-shaped config in\n * `tests/config.test.ts`: arrays are mutable (oxlint's are), and `plugins` is\n * oxlint's own literal union, because a bare `string[]` is not assignable to it.\n */\n\n/** A severity as oxlint spells it in a config; the numeric forms are not used here. */\ntype Severity = \"off\" | \"warn\" | \"error\";\n\n/** A rule entry: a severity, or a severity followed by the rule's own options. */\ntype RuleEntry = Severity | [Severity, ...unknown[]];\n\ninterface Rules {\n [ruleId: string]: RuleEntry;\n}\n\n/** oxlint's built-in plugins, the values its `plugins` field accepts. */\ntype BuiltinPlugin =\n | \"eslint\"\n | \"import\"\n | \"jest\"\n | \"jsdoc\"\n | \"jsx-a11y\"\n | \"nextjs\"\n | \"node\"\n | \"oxc\"\n | \"promise\"\n | \"react\"\n | \"react-perf\"\n | \"typescript\"\n | \"unicorn\"\n | \"vitest\"\n | \"vue\";\n\ninterface JsPlugin {\n name: string;\n specifier: string;\n}\n\nexport interface Override {\n files: string[];\n excludeFiles?: string[];\n plugins?: BuiltinPlugin[];\n env?: { [name: string]: boolean };\n jsPlugins?: JsPlugin[];\n rules?: Rules;\n}\n\nexport interface Config {\n jsPlugins?: JsPlugin[];\n rules?: Rules;\n overrides?: Override[];\n}\n\n/**\n * The plugin entry. The alias is `rdj`, which is also the prefix in every\n * diagnostic and every disable comment, so a consumer that renames it renames\n * its own rule keys too.\n */\nexport const plugin: JsPlugin = { name: \"rdj\", specifier: \"@rdjperron/lint\" };\n\n/** Every rule the plugin registers, prefixed. `fixtures()` and the verify bin read this list. */\nexport const RULE_IDS = [\n \"rdj/no-array-filter-map\",\n \"rdj/no-chained-type-assertions\",\n \"rdj/no-conditional-empty-object-spread\",\n \"rdj/no-hardcoded-jsx-text\",\n \"rdj/no-known-value-widening\",\n \"rdj/no-module-mocking\",\n \"rdj/no-object-parameters\",\n \"rdj/no-reduce-accumulator-copy\",\n \"rdj/no-reflect-apply\",\n \"rdj/no-reflect-get\",\n \"rdj/no-runtime-typeof\",\n \"rdj/no-shape-in-symbol-names\",\n \"rdj/no-unknown-parameters\",\n \"rdj/no-unknown-returns\",\n \"rdj/no-unknown-type-aliases\",\n \"rdj/no-unsafe-dictionary-type\",\n \"rdj/no-use-effect\",\n \"rdj/no-widen-then-assert\",\n \"rdj/require-safety-comment-for-type-assertion\",\n \"rdj/static-public-env\",\n] as const;\n\nexport type RuleId = (typeof RULE_IDS)[number];\n\n/**\n * The base config, for `lint: { extends: [recommended] }`.\n *\n * Measured through `extends` on vite-plus 0.3.1 / oxlint 1.81.0 (2026-09-17):\n * `jsPlugins`, `rules`, `overrides`, `plugins`, `categories` and `options` are\n * inherited by the consumer's config, and the consumer's own entries win.\n * `env`, `settings` and `ignorePatterns` are not inherited, which is why this\n * object carries none of them and the consumer keeps writing its own.\n */\nexport const recommended: Config = {\n jsPlugins: [plugin],\n rules: {\n // The anti-slop rules. Measured on stack-lab 2026-08-20 and 2026-09-13, and\n // on rummy 2026-09-16 (vite-plus 0.3.1, oxlint 1.81.0): on real hand-written\n // code they fire only on the patterns they exist to reject, so a hit is the\n // finding. Land a new one at `warn` in the consumer, fix or scope what\n // fires, then let this default take over.\n \"rdj/no-array-filter-map\": \"error\",\n \"rdj/no-chained-type-assertions\": \"error\",\n \"rdj/no-conditional-empty-object-spread\": \"error\",\n \"rdj/no-known-value-widening\": \"error\",\n \"rdj/no-module-mocking\": \"error\",\n \"rdj/no-object-parameters\": \"error\",\n \"rdj/no-reduce-accumulator-copy\": \"error\",\n \"rdj/no-reflect-apply\": \"error\",\n \"rdj/no-reflect-get\": \"error\",\n // A `typeof` inside a type predicate is the decode the rule asks for, named\n // and reusable, and the pack already exempts a predicate's subject from\n // `no-unknown-parameters` (rummy, 2026-09-16).\n \"rdj/no-runtime-typeof\": [\"error\", { allowInTypeGuards: true }],\n \"rdj/no-shape-in-symbol-names\": \"error\",\n \"rdj/no-unknown-parameters\": \"error\",\n \"rdj/no-unknown-returns\": \"error\",\n \"rdj/no-unknown-type-aliases\": \"error\",\n \"rdj/no-unsafe-dictionary-type\": \"error\",\n \"rdj/no-widen-then-assert\": \"error\",\n \"rdj/require-safety-comment-for-type-assertion\": \"error\",\n // Derived state, event handlers and a reactive query cover every case; the\n // one sanctioned wrapper is named through `react(files, { useEffectAllowedIn })`.\n \"rdj/no-use-effect\": \"error\",\n\n // `no-hardcoded-jsx-text` and `static-public-env` are absent on purpose:\n // they belong to a translated app and to an Expo app. `i18n()` and `expo()`\n // switch them on for the files that want them.\n\n // Type-aware rules; they need `options.typeAware` in the consumer's config.\n \"typescript/no-floating-promises\": \"error\",\n \"typescript/no-misused-promises\": \"error\",\n \"typescript/await-thenable\": \"error\",\n // Measured on rummy 2026-09-16 before the cleanup: 5, 5 and 1 hits, zero after.\n \"typescript/no-unnecessary-type-assertion\": \"error\",\n \"typescript/no-misused-spread\": \"error\",\n \"typescript/require-array-sort-compare\": \"error\",\n \"typescript/no-explicit-any\": \"warn\",\n\n \"prefer-const\": [\"error\", { destructuring: \"all\" }],\n \"no-unused-vars\": [\"error\", { argsIgnorePattern: \"^_\", varsIgnorePattern: \"^_\" }],\n // oxlint 1.77 moved this into `suspicious`, where it contradicts the `^_`\n // convention above. The prefix wins.\n \"no-underscore-dangle\": \"off\",\n eqeqeq: [\"error\", \"always\", { null: \"ignore\" }],\n\n // Deliberate off-switches, held by both consumers since the 2026-08-20 setup.\n \"typescript/no-unsafe-type-assertion\": \"off\",\n \"no-await-in-loop\": \"off\",\n \"unicorn/consistent-function-scoping\": \"off\",\n \"promise/always-return\": \"off\",\n },\n};\n\nexport interface ReactOptions {\n /**\n * The one file allowed to call `useEffect`, as a path. Its name goes into the\n * `no-use-effect` hint for every React file, and the rule is off for it.\n */\n useEffectAllowedIn?: string;\n}\n\n/**\n * The React file set: browser globals, the hooks rules, and the compiler's own\n * judgement. A consumer appends its own entries after these, because an override\n * that changes a `react/*` rule must repeat `plugins: [\"react\"]` or oxlint\n * silently drops the entry.\n */\nexport function react(files: string[], options: ReactOptions = {}): Override[] {\n const { useEffectAllowedIn } = options;\n const rules: Rules = {\n \"react/rules-of-hooks\": \"error\",\n \"react/exhaustive-deps\": \"warn\",\n // React 19 and the automatic JSX runtime: nothing has to be in scope.\n \"react/react-in-jsx-scope\": \"off\",\n // The React Compiler's own rules: a component it silently skips is a\n // component that never memoizes.\n \"react/immutability\": \"error\",\n \"react/refs\": \"error\",\n \"react/purity\": \"error\",\n // A module that exports only components refreshes in place; any other\n // export re-runs every importer.\n \"react/only-export-components\": \"error\",\n };\n const overrides: Override[] = [{ files, plugins: [\"react\"], env: { browser: true }, rules }];\n\n if (useEffectAllowedIn !== undefined) {\n rules[\"rdj/no-use-effect\"] = [\n \"error\",\n { hint: `The one sanctioned wrapper is ${useEffectAllowedIn}.` },\n ];\n overrides.push({\n // The sanctioned wrapper exists precisely so every other file can be clean.\n files: [useEffectAllowedIn],\n rules: { \"rdj/no-use-effect\": \"off\" },\n });\n }\n\n return overrides;\n}\n\nexport interface I18nOptions {\n /**\n * The word pattern, a regex source compiled with `u`. The rule's default,\n * `\\p{L}{3,}`, reads three letters in a row as a word.\n */\n pattern?: string;\n}\n\n/** Files whose JSX text belongs in a catalogue rather than in the source. */\nexport function i18n(files: string[], options: I18nOptions = {}): Override[] {\n const { pattern } = options;\n return [\n {\n files,\n rules: {\n \"rdj/no-hardcoded-jsx-text\": pattern === undefined ? \"error\" : [\"error\", { pattern }],\n },\n },\n ];\n}\n\n/** Files Expo's bundler inlines `process.env` into, where only `process.env.NAME` survives. */\nexport function expo(files: string[]): Override[] {\n return [{ files, rules: { \"rdj/static-public-env\": \"error\" } }];\n}\n\n/** Test files: four rules whose premise a test does not hold. */\nexport function tests(files: string[]): Override[] {\n return [\n {\n files,\n rules: {\n // A fixture is allowed to be the wrong type on purpose.\n \"typescript/no-explicit-any\": \"off\",\n \"typescript/no-non-null-assertion\": \"off\",\n // `expect(typeof x).toBe(\"function\")` reads as an unparsed boundary, but\n // asserting the shape of your own public API is the point of the assertion.\n \"rdj/no-runtime-typeof\": \"off\",\n // A justification on every assertion in a test is noise (53 measured on\n // rummy, 2026-09-16).\n \"rdj/require-safety-comment-for-type-assertion\": \"off\",\n },\n },\n ];\n}\n\n/** Every rule of the plugin at `error`, so none of them can be missing from the list. */\nconst FIXTURE_RULES = {\n \"rdj/no-array-filter-map\": \"error\",\n \"rdj/no-chained-type-assertions\": \"error\",\n \"rdj/no-conditional-empty-object-spread\": \"error\",\n \"rdj/no-hardcoded-jsx-text\": \"error\",\n \"rdj/no-known-value-widening\": \"error\",\n \"rdj/no-module-mocking\": \"error\",\n \"rdj/no-object-parameters\": \"error\",\n \"rdj/no-reduce-accumulator-copy\": \"error\",\n \"rdj/no-reflect-apply\": \"error\",\n \"rdj/no-reflect-get\": \"error\",\n \"rdj/no-runtime-typeof\": \"error\",\n \"rdj/no-shape-in-symbol-names\": \"error\",\n \"rdj/no-unknown-parameters\": \"error\",\n \"rdj/no-unknown-returns\": \"error\",\n \"rdj/no-unknown-type-aliases\": \"error\",\n \"rdj/no-unsafe-dictionary-type\": \"error\",\n \"rdj/no-use-effect\": \"error\",\n \"rdj/no-widen-then-assert\": \"error\",\n \"rdj/require-safety-comment-for-type-assertion\": \"error\",\n \"rdj/static-public-env\": \"error\",\n} satisfies Record<RuleId, \"error\">;\n\n/**\n * The view the verify command lints the shipped fixtures through. Without this\n * override every rule the consumer leaves off reports nothing there, and \"no\n * findings\" is exactly what a dead rule looks like.\n */\nexport function fixtures(view = \"scripts/.lint-fixtures/**\"): Override[] {\n return [{ files: [view], rules: { ...FIXTURE_RULES } }];\n}\n\n/** The formatting both consumers settled on. Spread it and add what is yours. */\nexport const fmt = {\n printWidth: 100,\n singleQuote: false,\n semi: true,\n tabWidth: 2,\n useTabs: false,\n};\n\n/**\n * Paths no linter and no formatter should walk: build output, dependencies, the\n * directories AI coding agents scribble in, and the Vitest JSON report. Spread\n * it into `ignorePatterns` and append the repo's own.\n */\nexport const ignore: string[] = [\n \"node_modules/**\",\n \"**/node_modules/**\",\n \"dist/**\",\n \"**/dist/**\",\n ...[\n \".agents\",\n \".claude\",\n \".codex\",\n \".continue\",\n \".cursor\",\n \".gemini\",\n \".opencode\",\n \".pi\",\n \".roo\",\n \".windsurf\",\n ].flatMap((dir) => [`${dir}/**`, `**/${dir}/**`]),\n \"**/test-results.json\",\n];\n\n/** The pre-commit entry: `vp check --fix` is defined for JS and TS sources, nothing else. */\nexport const staged = {\n \"*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}\": \"vp check --fix\",\n};\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ //#region src/index.d.ts
2
+ declare const rdjPlugin: import("@oxlint/plugins").Plugin;
3
+ //#endregion
4
+ export { rdjPlugin as default };
5
+ //# sourceMappingURL=index.d.mts.map