@d3lm/lint-preset 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dominic Elm
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,242 @@
1
+ # @d3lm/lint-preset
2
+
3
+ Opinionated dual-lint preset for JavaScript and TypeScript projects.
4
+
5
+ - **[Oxlint](https://oxc.rs/docs/guide/usage/linter)** runs the bulk of the rule set, including type-aware rules (via [`oxlint-tsgolint`](https://www.npmjs.com/package/oxlint-tsgolint))
6
+ - **[ESLint](https://eslint.org/)** layers on only the rules Oxlint can't run yet (e.g. `@typescript-eslint/naming-convention`, a handful of unicorn rules, and ESLint-core gaps)
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ pnpm add -D @d3lm/lint-preset
12
+ ```
13
+
14
+ The preset relies on a set of peer dependencies that it does not bundle. pnpm (with `auto-install-peers`, the default) pulls them in for you. With npm or yarn, install them explicitly:
15
+
16
+ ```bash
17
+ pnpm add -D oxlint oxlint-tsgolint eslint typescript-eslint @typescript-eslint/eslint-plugin @stylistic/eslint-plugin eslint-config-prettier eslint-plugin-prettier eslint-plugin-oxlint eslint-plugin-jsdoc eslint-plugin-unicorn
18
+ ```
19
+
20
+ React linting is opt-in. If you enable it for ESLint, also install the optional React Hooks peer:
21
+
22
+ ```bash
23
+ pnpm add -D eslint-plugin-react-hooks
24
+ ```
25
+
26
+ ## Consumer Setup
27
+
28
+ ### `oxlint.config.ts`
29
+
30
+ ```ts
31
+ import { defineConfig } from 'oxlint';
32
+ import { oxlintConfig } from '@d3lm/lint-preset/oxlint';
33
+
34
+ export default defineConfig({
35
+ extends: [oxlintConfig],
36
+ });
37
+ ```
38
+
39
+ This pulls in the full rule set. Most rules run natively in Oxlint; a few plugins that Oxlint doesn't ship natively (custom `@d3lm` rules, `@stylistic`, `eslint-plugin-prettier`, `eslint-plugin-unicorn`, `eslint-plugin-jsdoc`) are wired in through Oxlint's `jsPlugins`. Either way you can toggle individual rules off in the same config.
40
+
41
+ React rules are disabled by default. Enable them by creating the shared config with `react: true`:
42
+
43
+ ```ts
44
+ import { defineConfig } from 'oxlint';
45
+ import { createOxlintConfig } from '@d3lm/lint-preset/oxlint';
46
+
47
+ export default defineConfig({
48
+ extends: [createOxlintConfig({ react: true })],
49
+ });
50
+ ```
51
+
52
+ `react` also accepts an object to toggle the two opt-in groups independently (both default to `true` when `react` is enabled):
53
+
54
+ ```ts
55
+ createOxlintConfig({
56
+ react: {
57
+ fastRefresh: true, // react/only-export-components
58
+ performance: true, // react-perf/* rules
59
+ },
60
+ });
61
+ ```
62
+
63
+ ### `eslint.config.js`
64
+
65
+ ```js
66
+ import { eslintConfig } from '@d3lm/lint-preset/eslint';
67
+ import { oxlintConfig } from '@d3lm/lint-preset/oxlint';
68
+
69
+ export default eslintConfig({
70
+ oxlintConfig,
71
+ tsconfigRootDir: import.meta.dirname,
72
+ });
73
+ ```
74
+
75
+ React Hooks linting is also opt-in:
76
+
77
+ ```js
78
+ import { eslintConfig } from '@d3lm/lint-preset/eslint';
79
+ import { createOxlintConfig } from '@d3lm/lint-preset/oxlint';
80
+
81
+ const oxlintConfig = createOxlintConfig({ react: true });
82
+
83
+ export default eslintConfig({
84
+ oxlintConfig,
85
+ react: true,
86
+ tsconfigRootDir: import.meta.dirname,
87
+ });
88
+ ```
89
+
90
+ The factory returns a `Linter.Config[]` you can spread, so you can append project-specific overrides:
91
+
92
+ ```js
93
+ import { eslintConfig } from '@d3lm/lint-preset/eslint';
94
+ import { oxlintConfig } from '@d3lm/lint-preset/oxlint';
95
+
96
+ export default [
97
+ ...eslintConfig({
98
+ oxlintConfig,
99
+ tsconfigRootDir: import.meta.dirname,
100
+ }),
101
+ {
102
+ files: ['src/lib/**/*.ts'],
103
+ rules: { '@typescript-eslint/no-floating-promises': 'off' },
104
+ },
105
+ ];
106
+ ```
107
+
108
+ Overrides spread _after_ `eslintConfig(...)` land after the Oxlint disabler, which is fine for turning rules **off**. To turn a rule back **on** that Oxlint owns, use `extraConfigs` instead (see below) so it isn't immediately disabled again — otherwise you'll get double-reporting from both linters.
109
+
110
+ ### `package.json`
111
+
112
+ ```json
113
+ {
114
+ "scripts": {
115
+ "lint": "oxlint && eslint",
116
+ "lint:fix": "oxlint --fix && eslint --fix"
117
+ }
118
+ }
119
+ ```
120
+
121
+ Oxlint runs first (fast feedback on the majority of issues) and ESLint only reports what Oxlint didn't cover.
122
+
123
+ ## ESLint Config Factory Options
124
+
125
+ ```ts
126
+ eslintConfig({
127
+ /**
128
+ * Oxlint config object that eslint-plugin-oxlint reads to decide which
129
+ * ESLint rules to turn off. Prefer this when your Oxlint config is created
130
+ * in TypeScript.
131
+ */
132
+ oxlintConfig,
133
+
134
+ /**
135
+ * Path to a JSON/JSONC oxlint config file that eslint-plugin-oxlint reads
136
+ * to decide which ESLint rules to turn off. Ignored when `oxlintConfig` is
137
+ * provided.
138
+ *
139
+ * @default '.oxlintrc.json'
140
+ */
141
+ oxlintConfigPath: './.oxlintrc.json',
142
+
143
+ /**
144
+ * TypeScript project-service root. Usually `import.meta.dirname`.
145
+ */
146
+ tsconfigRootDir: import.meta.dirname,
147
+
148
+ /**
149
+ * Enable the ESLint-side React Hooks config. Pass `true`, or an object
150
+ * `{ fastRefresh?, performance? }` mirroring the Oxlint factory. Requires
151
+ * the optional `eslint-plugin-react-hooks` peer.
152
+ *
153
+ * @default false
154
+ */
155
+ react: true,
156
+
157
+ /**
158
+ * Files allowed to fall back to the default inferred project when they
159
+ * aren't covered by the main tsconfig (e.g. top-level config files).
160
+ *
161
+ * @default ['*.config.ts', '*.config.mts', '*.config.cts', '*.config.js']
162
+ */
163
+ allowDefaultProject: ['*.config.ts', '*.config.js'],
164
+
165
+ /**
166
+ * Extra patterns to ignore. Layered on top of the built-in defaults unless
167
+ * you opt out via `extendDefaultIgnores: false`.
168
+ */
169
+ ignores: ['generated/**'],
170
+
171
+ /**
172
+ * Whether to extend the built-in ignores with the ones passed in `ignores`.
173
+ *
174
+ * @default true
175
+ */
176
+ extendDefaultIgnores: true,
177
+
178
+ /**
179
+ * Flat-config entries layered *before* the Oxlint disabler, so custom
180
+ * rules are still subject to the "Oxlint turns off last" ordering.
181
+ */
182
+ extraConfigs: [],
183
+
184
+ /**
185
+ * Optional rule-shape overrides forwarded to the TypeScript rule set,
186
+ * including per-selector `namingConvention` exceptions.
187
+ */
188
+ namingConvention: {
189
+ variable: { exceptions: ['MyGlobal'] },
190
+ },
191
+
192
+ /**
193
+ * Tune unicorn's `prevent-abbreviations`. Extends the built-in allow list
194
+ * and replacements by default; set `inheritAllowList` / `inheritReplacements`
195
+ * to false to replace them outright.
196
+ */
197
+ preventAbbreviations: {
198
+ allowList: ['args'],
199
+ replacements: { props: false },
200
+ },
201
+ });
202
+ ```
203
+
204
+ ## Oxlint Config Factory Options
205
+
206
+ `createOxlintConfig` accepts the React options shown above plus the same rule-shape overrides, scoped to the Oxlint rule set:
207
+
208
+ ```ts
209
+ createOxlintConfig({
210
+ /**
211
+ * Toggle React rules (boolean or `{ fastRefresh?, performance? }`).
212
+ *
213
+ * @default false
214
+ */
215
+ react: true,
216
+
217
+ /**
218
+ * Overrides forwarded to the JS rules (e.g. `preventAbbreviations`).
219
+ */
220
+ jsRulesOxlint: {
221
+ preventAbbreviations: { allowList: ['args'] },
222
+ },
223
+
224
+ /**
225
+ * Overrides forwarded to the TS rules (e.g. `namingConvention`).
226
+ */
227
+ tsRulesOxlint: {
228
+ namingConvention: { variable: { exceptions: ['MyGlobal'] } },
229
+ },
230
+ });
231
+ ```
232
+
233
+ ## Development
234
+
235
+ ```bash
236
+ pnpm install
237
+ pnpm run build
238
+ pnpm run lint
239
+ pnpm run test
240
+ ```
241
+
242
+ The repo dogfoods the preset via `oxlint.config.ts` + `eslint.config.js` at the root, both pointing at `./dist/*` so `pnpm run lint` always lints against a fresh build.